Commit 79614a08 authored by Dhiraj Bodicherla's avatar Dhiraj Bodicherla Committed by Natalia Tepluhina

Added search box to dashboards dropdown

Dashboards list can get longer and the
current dropdown does not have a way to search
and filter. This MR adds a search input
parent 579b7c46
......@@ -402,7 +402,9 @@ export default {
:text="currentEnvironmentName"
>
<div class="d-flex flex-column overflow-hidden">
<gl-dropdown-header class="text-center">{{ __('Environment') }}</gl-dropdown-header>
<gl-dropdown-header class="monitor-environment-dropdown-header text-center">{{
__('Environment')
}}</gl-dropdown-header>
<gl-dropdown-divider />
<gl-search-box-by-type
v-if="shouldRenderSearchableEnvironmentsDropdown"
......
......@@ -4,11 +4,14 @@ import {
GlAlert,
GlDropdown,
GlDropdownItem,
GlDropdownHeader,
GlDropdownDivider,
GlSearchBoxByType,
GlModal,
GlLoadingIcon,
GlModalDirective,
} from '@gitlab/ui';
import { s__ } from '~/locale';
import DuplicateDashboardForm from './duplicate_dashboard_form.vue';
const events = {
......@@ -20,7 +23,9 @@ export default {
GlAlert,
GlDropdown,
GlDropdownItem,
GlDropdownHeader,
GlDropdownDivider,
GlSearchBoxByType,
GlModal,
GlLoadingIcon,
DuplicateDashboardForm,
......@@ -44,6 +49,7 @@ export default {
alert: null,
loading: false,
form: {},
searchTerm: '',
};
},
computed: {
......@@ -54,6 +60,17 @@ export default {
selectedDashboardText() {
return this.selectedDashboard.display_name;
},
filteredDashboards() {
return this.allDashboards.filter(({ display_name }) =>
display_name.toLowerCase().includes(this.searchTerm.toLowerCase()),
);
},
shouldShowNoMsgContainer() {
return this.filteredDashboards.length === 0;
},
okButtonText() {
return this.loading ? s__('Metrics|Duplicating...') : s__('Metrics|Duplicate');
},
},
methods: {
...mapActions('monitoringDashboard', ['duplicateSystemDashboard']),
......@@ -95,45 +112,70 @@ export default {
};
</script>
<template>
<gl-dropdown toggle-class="dropdown-menu-toggle" :text="selectedDashboardText">
<gl-dropdown-item
v-for="dashboard in allDashboards"
:key="dashboard.path"
:active="dashboard.path === selectedDashboard.path"
active-class="is-active"
@click="selectDashboard(dashboard)"
>
{{ dashboard.display_name || dashboard.path }}
</gl-dropdown-item>
<template v-if="isSystemDashboard">
<gl-dropdown
toggle-class="dropdown-menu-toggle"
menu-class="monitor-dashboard-dropdown-menu"
:text="selectedDashboardText"
>
<div class="d-flex flex-column overflow-hidden">
<gl-dropdown-header class="monitor-dashboard-dropdown-header text-center">{{
__('Dashboard')
}}</gl-dropdown-header>
<gl-dropdown-divider />
<gl-search-box-by-type
ref="monitorDashboardsDropdownSearch"
v-model="searchTerm"
class="m-2"
/>
<div class="flex-fill overflow-auto">
<gl-dropdown-item
v-for="dashboard in filteredDashboards"
:key="dashboard.path"
:active="dashboard.path === selectedDashboard.path"
active-class="is-active"
@click="selectDashboard(dashboard)"
>
{{ dashboard.display_name || dashboard.path }}
</gl-dropdown-item>
</div>
<gl-modal
ref="duplicateDashboardModal"
modal-id="duplicateDashboardModal"
:title="s__('Metrics|Duplicate dashboard')"
ok-variant="success"
@ok="ok"
@hide="hide"
<div
v-show="shouldShowNoMsgContainer"
ref="monitorDashboardsDropdownMsg"
class="text-secondary no-matches-message"
>
<gl-alert v-if="alert" class="mb-3" variant="danger" @dismiss="alert = null">
{{ alert }}
</gl-alert>
<duplicate-dashboard-form
:dashboard="selectedDashboard"
:default-branch="defaultBranch"
@change="formChange"
/>
<template #modal-ok>
<gl-loading-icon v-if="loading" inline color="light" />
{{ loading ? s__('Metrics|Duplicating...') : s__('Metrics|Duplicate') }}
</template>
</gl-modal>
{{ __('No matching results') }}
</div>
<template v-if="isSystemDashboard">
<gl-dropdown-divider />
<gl-modal
ref="duplicateDashboardModal"
modal-id="duplicateDashboardModal"
:title="s__('Metrics|Duplicate dashboard')"
ok-variant="success"
@ok="ok"
@hide="hide"
>
<gl-alert v-if="alert" class="mb-3" variant="danger" @dismiss="alert = null">
{{ alert }}
</gl-alert>
<duplicate-dashboard-form
:dashboard="selectedDashboard"
:default-branch="defaultBranch"
@change="formChange"
/>
<template #modal-ok>
<gl-loading-icon v-if="loading" inline color="light" />
{{ okButtonText }}
</template>
</gl-modal>
<gl-dropdown-item ref="duplicateDashboardItem" v-gl-modal="'duplicateDashboardModal'">
{{ s__('Metrics|Duplicate dashboard') }}
</gl-dropdown-item>
</template>
<gl-dropdown-item ref="duplicateDashboardItem" v-gl-modal="'duplicateDashboardModal'">
{{ s__('Metrics|Duplicate dashboard') }}
</gl-dropdown-item>
</template>
</div>
</gl-dropdown>
</template>
......@@ -47,7 +47,12 @@
}
.prometheus-graphs-header {
.monitor-environment-dropdown-menu {
.monitor-dashboard-dropdown-header header {
font-size: $gl-font-size;
}
.monitor-environment-dropdown-menu,
.monitor-dashboard-dropdown-menu {
&.show {
display: flex;
flex-direction: column;
......
---
title: Added search box to dashboards dropdown in monitoring dashboard
merge_request: 23906
author:
type: added
......@@ -44,7 +44,7 @@ exports[`Dashboard template matches the default snapshot 1`] = `
class="d-flex flex-column overflow-hidden"
>
<gl-dropdown-header-stub
class="text-center"
class="monitor-environment-dropdown-header text-center"
>
Environment
</gl-dropdown-header-stub>
......
......@@ -35,13 +35,17 @@ describe('DashboardsDropdown', () => {
const findItems = () => wrapper.findAll(GlDropdownItem);
const findItemAt = i => wrapper.findAll(GlDropdownItem).at(i);
const findSearchInput = () => wrapper.find({ ref: 'monitorDashboardsDropdownSearch' });
const findNoItemsMsg = () => wrapper.find({ ref: 'monitorDashboardsDropdownMsg' });
const setSearchTerm = searchTerm => wrapper.setData({ searchTerm });
describe('when it receives dashboards data', () => {
beforeEach(() => {
wrapper = createComponent();
});
it('displays an item for each dashboard', () => {
expect(wrapper.findAll(GlDropdownItem).length).toEqual(dashboardGitResponse.length);
expect(findItems().length).toEqual(dashboardGitResponse.length);
});
it('displays items with the dashboard display name', () => {
......@@ -49,6 +53,32 @@ describe('DashboardsDropdown', () => {
expect(findItemAt(1).text()).toBe(dashboardGitResponse[1].display_name);
expect(findItemAt(2).text()).toBe(dashboardGitResponse[2].display_name);
});
it('displays a search input', () => {
expect(findSearchInput().isVisible()).toBe(true);
});
it('hides no message text by default', () => {
expect(findNoItemsMsg().isVisible()).toBe(false);
});
it('filters dropdown items when searched for item exists in the list', () => {
const searchTerm = 'Default';
setSearchTerm(searchTerm);
return wrapper.vm.$nextTick(() => {
expect(findItems()).toHaveLength(1);
});
});
it('shows no items found message when searched for item does not exists in the list', () => {
const searchTerm = 'does-not-exist';
setSearchTerm(searchTerm);
return wrapper.vm.$nextTick(() => {
expect(findNoItemsMsg().isVisible()).toBe(true);
});
});
});
describe('when a system dashboard is selected', () => {
......@@ -224,7 +254,7 @@ describe('DashboardsDropdown', () => {
it('displays an item for each dashboard', () => {
const item = wrapper.findAll({ ref: 'duplicateDashboardItem' });
expect(findItems().length).toEqual(dashboardGitResponse.length);
expect(findItems()).toHaveLength(dashboardGitResponse.length);
expect(item.length).toBe(0);
});
......
......@@ -518,6 +518,15 @@ export const metricsDashboardPayload = {
],
};
const customDashboardsData = new Array(30).fill(null).map((_, idx) => ({
default: false,
display_name: `Custom Dashboard ${idx}`,
can_edit: true,
system_dashboard: false,
project_blob_path: `${mockProjectDir}/blob/master/dashboards/.gitlab/dashboards/dashboard_${idx}.yml`,
path: `.gitlab/dashboards/dashboard_${idx}.yml`,
}));
export const dashboardGitResponse = [
{
default: true,
......@@ -527,22 +536,7 @@ export const dashboardGitResponse = [
project_blob_path: null,
path: 'config/prometheus/common_metrics.yml',
},
{
default: false,
display_name: 'Custom Dashboard 1',
can_edit: true,
system_dashboard: false,
project_blob_path: `${mockProjectDir}/blob/master/dashboards/.gitlab/dashboards/dashboard_1.yml`,
path: '.gitlab/dashboards/dashboard_1.yml',
},
{
default: false,
display_name: 'Custom Dashboard 2',
can_edit: true,
system_dashboard: false,
project_blob_path: `${mockProjectDir}/blob/master/dashboards/.gitlab/dashboards/dashboard_2.yml`,
path: '.gitlab/dashboards/dashboard_2.yml',
},
...customDashboardsData,
];
export const graphDataPrometheusQuery = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment