From 27afe5496db343962c573ce4e48a87af74235e4c Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Wed, 26 Jun 2019 22:14:41 +0000 Subject: Add feature flag and dashboard endpoint First part of FE for Prometheus API Dashboard endpoint fetches all info except for chart results Renders empty groups after loading --- .../monitoring/components/dashboard.vue | 35 ++++++++++++++- .../javascripts/monitoring/monitoring_bundle.js | 12 ++++-- .../javascripts/monitoring/stores/actions.js | 21 +++++++-- .../monitoring/stores/mutation_types.js | 2 + .../javascripts/monitoring/stores/mutations.js | 7 +++ app/assets/javascripts/monitoring/stores/state.js | 3 ++ spec/javascripts/monitoring/dashboard_spec.js | 50 ++++++++++++++++++++-- spec/javascripts/monitoring/mock_data.js | 13 ++++++ spec/javascripts/monitoring/store/actions_spec.js | 17 +++++++- .../javascripts/monitoring/store/mutations_spec.js | 15 ++++++- 10 files changed, 160 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 973fa346a4f..23687c54fd3 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -106,17 +106,24 @@ export default { }, customMetricsPath: { type: String, - required: true, + required: false, + default: invalidUrl, }, validateQueryPath: { type: String, - required: true, + required: false, + default: invalidUrl, }, dashboardEndpoint: { type: String, required: false, default: invalidUrl, }, + currentDashboard: { + type: String, + required: false, + default: '', + }, }, data() { return { @@ -139,10 +146,15 @@ export default { 'deploymentData', 'metricsWithData', 'useDashboardEndpoint', + 'allDashboards', + 'multipleDashboardsEnabled', ]), groupsWithData() { return this.groups.filter(group => this.chartsWithData(group.metrics).length > 0); }, + selectedDashboardText() { + return this.currentDashboard || (this.allDashboards[0] && this.allDashboards[0].display_name); + }, }, created() { this.setEndpoints({ @@ -150,6 +162,7 @@ export default { environmentsEndpoint: this.environmentsEndpoint, deploymentsEndpoint: this.deploymentsEndpoint, dashboardEndpoint: this.dashboardEndpoint, + currentDashboard: this.currentDashboard, }); this.timeWindows = timeWindows; @@ -240,6 +253,24 @@ export default { v-if="environmentsEndpoint" class="dropdowns d-flex align-items-center justify-content-between" > +
+ + + + {{ dashboard.display_name || dashboard.path }} + + +
{{ s__('Metrics|Environment') }} { const el = document.getElementById('prometheus-graphs'); if (el && el.dataset) { - store.dispatch( - 'monitoringDashboard/setDashboardEnabled', - gon.features.environmentMetricsUsePrometheusEndpoint, - ); + store.dispatch('monitoringDashboard/setFeatureFlags', { + prometheusEndpointEnabled: gon.features.environmentMetricsUsePrometheusEndpoint, + multipleDashboardsEnabled: gon.features.environmentMetricsShowMultipleDashboards, + }); + + const [currentDashboard] = getParameterValues('dashboard'); // eslint-disable-next-line no-new new Vue({ @@ -20,6 +23,7 @@ export default (props = {}) => { return createElement(Dashboard, { props: { ...el.dataset, + currentDashboard, hasMetrics: parseBoolean(el.dataset.hasMetrics), ...props, }, diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js index f41e215cb5d..0fa2a5d6370 100644 --- a/app/assets/javascripts/monitoring/stores/actions.js +++ b/app/assets/javascripts/monitoring/stores/actions.js @@ -35,14 +35,24 @@ export const setEndpoints = ({ commit }, endpoints) => { commit(types.SET_ENDPOINTS, endpoints); }; -export const setDashboardEnabled = ({ commit }, enabled) => { - commit(types.SET_DASHBOARD_ENABLED, enabled); +export const setFeatureFlags = ( + { commit }, + { prometheusEndpointEnabled, multipleDashboardsEnabled }, +) => { + commit(types.SET_DASHBOARD_ENABLED, prometheusEndpointEnabled); + commit(types.SET_MULTIPLE_DASHBOARDS_ENABLED, multipleDashboardsEnabled); }; export const requestMetricsDashboard = ({ commit }) => { commit(types.REQUEST_METRICS_DATA); }; -export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => { +export const receiveMetricsDashboardSuccess = ( + { state, commit, dispatch }, + { response, params }, +) => { + if (state.multipleDashboardsEnabled) { + commit(types.SET_ALL_DASHBOARDS, response.all_dashboards); + } commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard.panel_groups); dispatch('fetchPrometheusMetrics', params); }; @@ -95,6 +105,11 @@ export const fetchMetricsData = ({ state, dispatch }, params) => { export const fetchDashboard = ({ state, dispatch }, params) => { dispatch('requestMetricsDashboard'); + if (state.currentDashboard) { + // eslint-disable-next-line no-param-reassign + params.dashboard = state.currentDashboard; + } + return axios .get(state.dashboardEndpoint, { params }) .then(resp => resp.data) diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js index 63894e83362..2c78a0b9315 100644 --- a/app/assets/javascripts/monitoring/stores/mutation_types.js +++ b/app/assets/javascripts/monitoring/stores/mutation_types.js @@ -10,6 +10,8 @@ export const RECEIVE_ENVIRONMENTS_DATA_FAILURE = 'RECEIVE_ENVIRONMENTS_DATA_FAIL export const SET_QUERY_RESULT = 'SET_QUERY_RESULT'; export const SET_TIME_WINDOW = 'SET_TIME_WINDOW'; export const SET_DASHBOARD_ENABLED = 'SET_DASHBOARD_ENABLED'; +export const SET_MULTIPLE_DASHBOARDS_ENABLED = 'SET_MULTIPLE_DASHBOARDS_ENABLED'; +export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS'; export const SET_ENDPOINTS = 'SET_ENDPOINTS'; export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE'; export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE'; diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js index d4b816e2717..a85a7723c1f 100644 --- a/app/assets/javascripts/monitoring/stores/mutations.js +++ b/app/assets/javascripts/monitoring/stores/mutations.js @@ -74,10 +74,14 @@ export default { state.environmentsEndpoint = endpoints.environmentsEndpoint; state.deploymentsEndpoint = endpoints.deploymentsEndpoint; state.dashboardEndpoint = endpoints.dashboardEndpoint; + state.currentDashboard = endpoints.currentDashboard; }, [types.SET_DASHBOARD_ENABLED](state, enabled) { state.useDashboardEndpoint = enabled; }, + [types.SET_MULTIPLE_DASHBOARDS_ENABLED](state, enabled) { + state.multipleDashboardsEnabled = enabled; + }, [types.SET_GETTING_STARTED_EMPTY_STATE](state) { state.emptyState = 'gettingStarted'; }, @@ -85,4 +89,7 @@ export default { state.showEmptyState = true; state.emptyState = 'noData'; }, + [types.SET_ALL_DASHBOARDS](state, dashboards) { + state.allDashboards = dashboards; + }, }; diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js index c33529cd588..de711d6ccae 100644 --- a/app/assets/javascripts/monitoring/stores/state.js +++ b/app/assets/javascripts/monitoring/stores/state.js @@ -8,10 +8,13 @@ export default () => ({ deploymentsEndpoint: null, dashboardEndpoint: invalidUrl, useDashboardEndpoint: false, + multipleDashboardsEnabled: false, emptyState: 'gettingStarted', showEmptyState: true, groups: [], deploymentData: [], environments: [], metricsWithData: [], + allDashboards: [], + currentDashboard: null, }); diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js index cf72cce1781..ab8360193be 100644 --- a/spec/javascripts/monitoring/dashboard_spec.js +++ b/spec/javascripts/monitoring/dashboard_spec.js @@ -10,6 +10,7 @@ import { mockApiEndpoint, environmentData, singleGroupResponse, + dashboardGitResponse, } from './mock_data'; const propsData = { @@ -308,10 +309,6 @@ describe('Dashboard', () => { spyOn(component.$store, 'dispatch').and.stub(); const getTimeDiffSpy = spyOnDependency(Dashboard, 'getTimeDiff'); - component.$store.commit( - `monitoringDashboard/${types.SET_ENVIRONMENTS_ENDPOINT}`, - '/environments', - ); component.$store.commit( `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, environmentData, @@ -430,4 +427,49 @@ describe('Dashboard', () => { }); }); }); + + describe('Dashboard dropdown', () => { + beforeEach(() => { + mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); + + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { + ...propsData, + hasMetrics: true, + showPanels: false, + }, + store, + }); + + component.$store.dispatch('monitoringDashboard/setFeatureFlags', { + prometheusEndpoint: false, + multipleDashboardsEnabled: true, + }); + + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, + environmentData, + ); + + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, + singleGroupResponse, + ); + + component.$store.commit( + `monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, + dashboardGitResponse, + ); + }); + + it('shows the dashboard dropdown', done => { + setTimeout(() => { + const dashboardDropdown = component.$el.querySelector('.js-dashboards-dropdown'); + + expect(dashboardDropdown).not.toEqual(null); + done(); + }); + }); + }); }); diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 82e42fe9ade..7bbb215475a 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -922,3 +922,16 @@ export const metricsDashboardResponse = { }, status: 'success', }; + +export const dashboardGitResponse = [ + { + path: 'config/prometheus/common_metrics.yml', + display_name: 'Common Metrics', + default: true, + }, + { + path: '.gitlab/dashboards/super.yml', + display_name: 'Custom Dashboard 1', + default: false, + }, +]; diff --git a/spec/javascripts/monitoring/store/actions_spec.js b/spec/javascripts/monitoring/store/actions_spec.js index 083a01c4d74..677455275de 100644 --- a/spec/javascripts/monitoring/store/actions_spec.js +++ b/spec/javascripts/monitoring/store/actions_spec.js @@ -22,6 +22,7 @@ import { environmentData, metricsDashboardResponse, metricsGroupsAPIResponse, + dashboardGitResponse, } from '../mock_data'; describe('Monitoring store actions', () => { @@ -212,17 +213,19 @@ describe('Monitoring store actions', () => { describe('receiveMetricsDashboardSuccess', () => { let commit; let dispatch; + let state; beforeEach(() => { commit = jasmine.createSpy(); dispatch = jasmine.createSpy(); + state = storeState(); }); it('stores groups ', () => { const params = {}; const response = metricsDashboardResponse; - receiveMetricsDashboardSuccess({ commit, dispatch }, { response, params }); + receiveMetricsDashboardSuccess({ state, commit, dispatch }, { response, params }); expect(commit).toHaveBeenCalledWith( types.RECEIVE_METRICS_DATA_SUCCESS, @@ -231,6 +234,18 @@ describe('Monitoring store actions', () => { expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetrics', params); }); + + it('sets the dashboards loaded from the repository', () => { + const params = {}; + const response = metricsDashboardResponse; + + response.all_dashboards = dashboardGitResponse; + state.multipleDashboardsEnabled = true; + + receiveMetricsDashboardSuccess({ state, commit, dispatch }, { response, params }); + + expect(commit).toHaveBeenCalledWith(types.SET_ALL_DASHBOARDS, dashboardGitResponse); + }); }); describe('receiveMetricsDashboardFailure', () => { diff --git a/spec/javascripts/monitoring/store/mutations_spec.js b/spec/javascripts/monitoring/store/mutations_spec.js index 02ff5847b34..91580366531 100644 --- a/spec/javascripts/monitoring/store/mutations_spec.js +++ b/spec/javascripts/monitoring/store/mutations_spec.js @@ -1,7 +1,12 @@ import mutations from '~/monitoring/stores/mutations'; import * as types from '~/monitoring/stores/mutation_types'; import state from '~/monitoring/stores/state'; -import { metricsGroupsAPIResponse, deploymentData, metricsDashboardResponse } from '../mock_data'; +import { + metricsGroupsAPIResponse, + deploymentData, + metricsDashboardResponse, + dashboardGitResponse, +} from '../mock_data'; describe('Monitoring mutations', () => { let stateCopy; @@ -156,4 +161,12 @@ describe('Monitoring mutations', () => { expect(stateCopy.metricsWithData).toEqual([]); }); }); + + describe('SET_ALL_DASHBOARDS', () => { + it('stores the dashboards loaded from the git repository', () => { + mutations[types.SET_ALL_DASHBOARDS](stateCopy, dashboardGitResponse); + + expect(stateCopy.allDashboards).toEqual(dashboardGitResponse); + }); + }); }); -- cgit v1.2.1