Commit 2125551c authored by Miguel Rincon's avatar Miguel Rincon

Add constants for empty dashboard states

This change adds constants to designate specific global empty states.

It also adds tests to ensure empty state change work correctly.
parent 0ccea59d
<script>
import { GlEmptyState } from '@gitlab/ui';
import { __ } from '~/locale';
import { dashboardEmptyStates } from '../constants';
export default {
components: {
......@@ -54,7 +55,7 @@ export default {
data() {
return {
states: {
gettingStarted: {
[dashboardEmptyStates.GETTING_STARTED]: {
svgUrl: this.emptyGettingStartedSvgPath,
title: __('Get started with performance monitoring'),
description: __(`Stay updated about the performance and health
......@@ -64,7 +65,7 @@ export default {
secondaryButtonText: __('Configure existing installation'),
secondaryButtonPath: this.settingsPath,
},
loading: {
[dashboardEmptyStates.LOADING]: {
svgUrl: this.emptyLoadingSvgPath,
title: __('Waiting for performance data'),
description: __(`Creating graphs uses the data from the Prometheus server.
......@@ -74,7 +75,7 @@ export default {
secondaryButtonText: '',
secondaryButtonPath: '',
},
noData: {
[dashboardEmptyStates.NO_DATA]: {
svgUrl: this.emptyNoDataSvgPath,
title: __('No data found'),
description: __(`You are connected to the Prometheus server, but there is currently
......@@ -84,7 +85,7 @@ export default {
secondaryButtonText: '',
secondaryButtonPath: '',
},
unableToConnect: {
[dashboardEmptyStates.UNABLE_TO_CONNECT]: {
svgUrl: this.emptyUnableToConnectSvgPath,
title: __('Unable to connect to Prometheus server'),
description: __(
......
export const PROMETHEUS_TIMEOUT = 120000; // TWO_MINUTES
export const dashboardEmptyStates = {
GETTING_STARTED: 'gettingStarted',
LOADING: 'loading',
NO_DATA: 'noData',
UNABLE_TO_CONNECT: 'unableToConnect',
};
/**
* States and error states in Prometheus Queries (PromQL) for metrics
*/
......
......@@ -4,7 +4,7 @@ import * as types from './mutation_types';
import { mapToDashboardViewModel, normalizeQueryResponseData } from './utils';
import httpStatusCodes from '~/lib/utils/http_status';
import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils';
import { endpointKeys, initialStateKeys, metricStates } from '../constants';
import { dashboardEmptyStates, endpointKeys, initialStateKeys, metricStates } from '../constants';
import { optionsFromSeriesData } from './variable_mapping';
/**
......@@ -58,7 +58,7 @@ export default {
* Dashboard panels structure and global state
*/
[types.REQUEST_METRICS_DASHBOARD](state) {
state.emptyState = 'loading';
state.emptyState = dashboardEmptyStates.LOADING;
state.showEmptyState = true;
},
[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboardYML) {
......@@ -71,11 +71,13 @@ export default {
state.links = links;
if (!state.dashboard.panelGroups.length) {
state.emptyState = 'noData';
state.emptyState = dashboardEmptyStates.NO_DATA;
}
},
[types.RECEIVE_METRICS_DASHBOARD_FAILURE](state, error) {
state.emptyState = error ? 'unableToConnect' : 'noData';
state.emptyState = error
? dashboardEmptyStates.UNABLE_TO_CONNECT
: dashboardEmptyStates.NO_DATA;
state.showEmptyState = true;
},
......@@ -151,6 +153,8 @@ export default {
metric.loading = false;
state.showEmptyState = false;
state.emptyState = null;
if (!data.result || data.result.length === 0) {
metric.state = metricStates.NO_DATA;
metric.result = null;
......@@ -180,11 +184,12 @@ export default {
state.timeRange = timeRange;
},
[types.SET_GETTING_STARTED_EMPTY_STATE](state) {
state.emptyState = 'gettingStarted';
state.showEmptyState = true;
state.emptyState = dashboardEmptyStates.GETTING_STARTED;
},
[types.SET_NO_DATA_EMPTY_STATE](state) {
state.showEmptyState = true;
state.emptyState = 'noData';
state.emptyState = dashboardEmptyStates.NO_DATA;
},
[types.SET_ALL_DASHBOARDS](state, dashboards) {
state.allDashboards = dashboards || [];
......
import invalidUrl from '~/lib/utils/invalid_url';
import { timezones } from '../format_date';
import { dashboardEmptyStates } from '../constants';
export default () => ({
// API endpoints
......@@ -20,7 +21,7 @@ export default () => ({
// Dashboard data
hasDashboardValidationWarnings: false,
emptyState: 'gettingStarted',
emptyState: dashboardEmptyStates.GETTING_STARTED,
showEmptyState: true,
showErrorBanner: true,
isUpdatingStarredValue: false,
......
......@@ -24,6 +24,18 @@ exports[`EmptyState shows loading state 1`] = `
/>
`;
exports[`EmptyState shows noData state 1`] = `
<gl-empty-state-stub
description="You are connected to the Prometheus server, but there is currently no data to display."
primarybuttonlink="/settingsPath"
primarybuttontext="Configure Prometheus"
secondarybuttonlink=""
secondarybuttontext=""
svgpath="/path/to/no-data.svg"
title="No data found"
/>
`;
exports[`EmptyState shows unableToConnect state 1`] = `
<gl-empty-state-stub
description="Ensure connectivity is available from the GitLab server to the Prometheus server"
......
......@@ -6,7 +6,7 @@ import { objectToQuery } from '~/lib/utils/url_utility';
import VueDraggable from 'vuedraggable';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { metricStates } from '~/monitoring/constants';
import { dashboardEmptyStates, metricStates } from '~/monitoring/constants';
import Dashboard from '~/monitoring/components/dashboard.vue';
import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
......@@ -126,13 +126,13 @@ describe('Dashboard', () => {
});
it('shows up a loading state', () => {
store.state.monitoringDashboard.emptyState = 'loading';
store.state.monitoringDashboard.emptyState = dashboardEmptyStates.LOADING;
createShallowWrapper({ hasMetrics: true });
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find(EmptyState).exists()).toBe(true);
expect(wrapper.find(EmptyState).props('selectedState')).toBe('loading');
expect(wrapper.find(EmptyState).props('selectedState')).toBe(dashboardEmptyStates.LOADING);
});
});
......
import { shallowMount } from '@vue/test-utils';
import { dashboardEmptyStates } from '~/monitoring/constants';
import EmptyState from '~/monitoring/components/empty_state.vue';
function createComponent(props) {
......@@ -20,7 +21,7 @@ function createComponent(props) {
describe('EmptyState', () => {
it('shows gettingStarted state', () => {
const wrapper = createComponent({
selectedState: 'gettingStarted',
selectedState: dashboardEmptyStates.GETTING_STARTED,
});
expect(wrapper.element).toMatchSnapshot();
......@@ -28,7 +29,7 @@ describe('EmptyState', () => {
it('shows loading state', () => {
const wrapper = createComponent({
selectedState: 'loading',
selectedState: dashboardEmptyStates.LOADING,
});
expect(wrapper.element).toMatchSnapshot();
......@@ -36,7 +37,15 @@ describe('EmptyState', () => {
it('shows unableToConnect state', () => {
const wrapper = createComponent({
selectedState: 'unableToConnect',
selectedState: dashboardEmptyStates.UNABLE_TO_CONNECT,
});
expect(wrapper.element).toMatchSnapshot();
});
it('shows noData state', () => {
const wrapper = createComponent({
selectedState: dashboardEmptyStates.NO_DATA,
});
expect(wrapper.element).toMatchSnapshot();
......
......@@ -3,7 +3,7 @@ import httpStatusCodes from '~/lib/utils/http_status';
import mutations from '~/monitoring/stores/mutations';
import * as types from '~/monitoring/stores/mutation_types';
import state from '~/monitoring/stores/state';
import { metricStates } from '~/monitoring/constants';
import { dashboardEmptyStates, metricStates } from '~/monitoring/constants';
import { deploymentData, dashboardGitResponse, storeTextVariables } from '../mock_data';
import { metricsDashboardPayload } from '../fixture_data';
......@@ -15,6 +15,15 @@ describe('Monitoring mutations', () => {
stateCopy = state();
});
describe('REQUEST_METRICS_DASHBOARD', () => {
it('sets an empty loading state', () => {
mutations[types.REQUEST_METRICS_DASHBOARD](stateCopy);
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.LOADING);
expect(stateCopy.showEmptyState).toBe(true);
});
});
describe('RECEIVE_METRICS_DASHBOARD_SUCCESS', () => {
let payload;
const getGroups = () => stateCopy.dashboard.panelGroups;
......@@ -23,6 +32,18 @@ describe('Monitoring mutations', () => {
stateCopy.dashboard.panelGroups = [];
payload = metricsDashboardPayload;
});
it('sets an empty noData state when the dashboard is empty', () => {
const emptyDashboardPayload = {
...payload,
panel_groups: [],
};
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, emptyDashboardPayload);
const groups = getGroups();
expect(groups).toEqual([]);
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.NO_DATA);
});
it('adds a key to the group', () => {
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, payload);
const groups = getGroups();
......@@ -72,6 +93,22 @@ describe('Monitoring mutations', () => {
});
});
describe('RECEIVE_METRICS_DASHBOARD_FAILURE', () => {
it('sets an empty noData state when an empty error occurs', () => {
mutations[types.RECEIVE_METRICS_DASHBOARD_FAILURE](stateCopy);
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.NO_DATA);
expect(stateCopy.showEmptyState).toBe(true);
});
it('sets an empty unableToConnect state when an error occurs', () => {
mutations[types.RECEIVE_METRICS_DASHBOARD_FAILURE](stateCopy, 'myerror');
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.UNABLE_TO_CONNECT);
expect(stateCopy.showEmptyState).toBe(true);
});
});
describe('Dashboard starring mutations', () => {
it('REQUEST_DASHBOARD_STARRING', () => {
stateCopy = { isUpdatingStarredValue: false };
......@@ -283,6 +320,7 @@ describe('Monitoring mutations', () => {
});
expect(stateCopy.showEmptyState).toBe(false);
expect(stateCopy.emptyState).toBe(null);
});
it('adds results to the store', () => {
......
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