Commit 1dbe1911 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '217758-reduce-metrics-dashboard-loading' into 'master'

Replace loading state with an icon, show dashboard skeleton earlier

See merge request gitlab-org/gitlab!36399
parents a6a3355d 87d384a6
......@@ -161,7 +161,6 @@ export default {
...mapState('monitoringDashboard', [
'dashboard',
'emptyState',
'showEmptyState',
'expandedPanel',
'variables',
'links',
......@@ -169,6 +168,9 @@ export default {
'hasDashboardValidationWarnings',
]),
...mapGetters('monitoringDashboard', ['selectedDashboard', 'getMetricStates']),
shouldShowEmptyState() {
return Boolean(this.emptyState);
},
shouldShowVariablesSection() {
return Boolean(this.variables.length);
},
......@@ -277,6 +279,14 @@ export default {
}
return null;
},
/**
* Return true if the entire group is loading.
* @param {String} groupKey - Identifier for group
* @returns {boolean}
*/
isGroupLoading(groupKey) {
return this.groupSingleEmptyState(groupKey) === metricStates.LOADING;
},
/**
* A group should be not collapsed if any metric is loaded (OK)
*
......@@ -412,9 +422,9 @@ export default {
@dateTimePickerInvalid="onDateTimePickerInvalid"
@setRearrangingPanels="onSetRearrangingPanels"
/>
<variables-section v-if="shouldShowVariablesSection && !showEmptyState" />
<links-section v-if="shouldShowLinksSection && !showEmptyState" />
<div v-if="!showEmptyState">
<template v-if="!shouldShowEmptyState">
<variables-section v-if="shouldShowVariablesSection" />
<links-section v-if="shouldShowLinksSection" />
<dashboard-panel
v-show="expandedPanel.panel"
ref="expandedPanel"
......@@ -449,6 +459,7 @@ export default {
:key="`${groupData.group}.${groupData.priority}`"
:name="groupData.group"
:show-panels="showPanels"
:is-loading="isGroupLoading(groupData.key)"
:collapse-group="collapseGroup(groupData.key)"
>
<vue-draggable
......@@ -506,7 +517,7 @@ export default {
</div>
</graph-group>
</div>
</div>
</template>
<empty-state
v-else
:selected-state="emptyState"
......
......@@ -119,10 +119,10 @@ export default {
},
computed: {
...mapState('monitoringDashboard', [
'emptyState',
'environmentsLoading',
'currentEnvironmentName',
'isUpdatingStarredValue',
'showEmptyState',
'dashboardTimezone',
'projectPath',
'canAccessOperationsSettings',
......@@ -132,13 +132,16 @@ export default {
isOutOfTheBoxDashboard() {
return this.selectedDashboard?.out_of_the_box_dashboard;
},
shouldShowEmptyState() {
return Boolean(this.emptyState);
},
shouldShowEnvironmentsDropdownNoMatchedMsg() {
return !this.environmentsLoading && this.filteredEnvironments.length === 0;
},
addingMetricsAvailable() {
return (
this.customMetricsAvailable &&
!this.showEmptyState &&
!this.shouldShowEmptyState &&
// Custom metrics only avaialble on system dashboards because
// they are stored in the database. This can be improved. See:
// https://gitlab.com/gitlab-org/gitlab/-/issues/28241
......@@ -146,7 +149,7 @@ export default {
);
},
showRearrangePanelsBtn() {
return !this.showEmptyState && this.rearrangePanelsAvailable;
return !this.shouldShowEmptyState && this.rearrangePanelsAvailable;
},
displayUtc() {
return this.dashboardTimezone === timezones.UTC;
......
<script>
import { GlEmptyState } from '@gitlab/ui';
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import { __ } from '~/locale';
import { dashboardEmptyStates } from '../constants';
export default {
components: {
GlLoadingIcon,
GlEmptyState,
},
props: {
selectedState: {
type: String,
required: true,
validator: state => Object.values(dashboardEmptyStates).includes(state),
},
documentationPath: {
type: String,
required: true,
......@@ -22,10 +28,6 @@ export default {
required: false,
default: '',
},
selectedState: {
type: String,
required: true,
},
emptyGettingStartedSvgPath: {
type: String,
required: true,
......@@ -54,52 +56,49 @@ export default {
},
data() {
return {
/**
* Possible empty states.
* Keys in each state must match GlEmptyState props
*/
states: {
[dashboardEmptyStates.GETTING_STARTED]: {
svgUrl: this.emptyGettingStartedSvgPath,
svgPath: this.emptyGettingStartedSvgPath,
title: __('Get started with performance monitoring'),
description: __(`Stay updated about the performance and health
of your environment by configuring Prometheus to monitor your deployments.`),
buttonText: __('Install on clusters'),
buttonPath: this.clustersPath,
primaryButtonText: __('Install on clusters'),
primaryButtonLink: this.clustersPath,
secondaryButtonText: __('Configure existing installation'),
secondaryButtonPath: this.settingsPath,
},
[dashboardEmptyStates.LOADING]: {
svgUrl: this.emptyLoadingSvgPath,
title: __('Waiting for performance data'),
description: __(`Creating graphs uses the data from the Prometheus server.
If this takes a long time, ensure that data is available.`),
buttonText: __('View documentation'),
buttonPath: this.documentationPath,
secondaryButtonText: '',
secondaryButtonPath: '',
secondaryButtonLink: this.settingsPath,
},
[dashboardEmptyStates.NO_DATA]: {
svgUrl: this.emptyNoDataSvgPath,
svgPath: this.emptyNoDataSvgPath,
title: __('No data found'),
description: __(`You are connected to the Prometheus server, but there is currently
no data to display.`),
buttonText: __('Configure Prometheus'),
buttonPath: this.settingsPath,
primaryButtonText: __('Configure Prometheus'),
primaryButtonLink: this.settingsPath,
secondaryButtonText: '',
secondaryButtonPath: '',
secondaryButtonLink: '',
},
[dashboardEmptyStates.UNABLE_TO_CONNECT]: {
svgUrl: this.emptyUnableToConnectSvgPath,
svgPath: this.emptyUnableToConnectSvgPath,
title: __('Unable to connect to Prometheus server'),
description: __(
'Ensure connectivity is available from the GitLab server to the Prometheus server',
),
buttonText: __('View documentation'),
buttonPath: this.documentationPath,
primaryButtonText: __('View documentation'),
primaryButtonLink: this.documentationPath,
secondaryButtonText: __('Configure Prometheus'),
secondaryButtonPath: this.settingsPath,
secondaryButtonLink: this.settingsPath,
},
},
};
},
computed: {
isLoading() {
return this.selectedState === dashboardEmptyStates.LOADING;
},
currentState() {
return this.states[this.selectedState];
},
......@@ -108,14 +107,8 @@ export default {
</script>
<template>
<gl-empty-state
:title="currentState.title"
:description="currentState.description"
:primary-button-text="currentState.buttonText"
:primary-button-link="currentState.buttonPath"
:secondary-button-text="currentState.secondaryButtonText"
:secondary-button-link="currentState.secondaryButtonPath"
:svg-path="currentState.svgUrl"
:compact="compact"
/>
<div>
<gl-loading-icon v-if="isLoading" size="xl" class="gl-my-9" />
<gl-empty-state v-if="currentState" v-bind="currentState" :compact="compact" />
</div>
</template>
<script>
import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
export default {
components: {
Icon,
GlLoadingIcon,
GlIcon,
},
props: {
name: {
......@@ -15,6 +16,11 @@ export default {
required: false,
default: true,
},
isLoading: {
type: Boolean,
required: false,
default: false,
},
/**
* Initial value of collapse on mount.
*/
......@@ -55,15 +61,18 @@ export default {
<div v-if="showPanels" ref="graph-group" class="card prometheus-panel">
<div class="card-header d-flex align-items-center">
<h4 class="flex-grow-1">{{ name }}</h4>
<gl-loading-icon v-if="isLoading" name="loading" />
<a
data-testid="group-toggle-button"
:aria-label="__('Toggle collapse')"
:icon="caretIcon"
role="button"
class="js-graph-group-toggle gl-text-gray-900"
class="js-graph-group-toggle gl-display-flex gl-ml-2 gl-text-gray-900"
tabindex="0"
@click="collapse"
@keyup.enter="collapse"
>
<icon :size="16" :aria-label="__('Toggle collapse')" :name="caretIcon" />
<gl-icon :name="caretIcon" />
</a>
</div>
<div
......
......@@ -40,7 +40,6 @@ export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS';
export const SET_ENDPOINTS = 'SET_ENDPOINTS';
export const SET_INITIAL_STATE = 'SET_INITIAL_STATE';
export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE';
export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE';
export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER';
export const SET_PANEL_GROUP_METRICS = 'SET_PANEL_GROUP_METRICS';
export const SET_ENVIRONMENTS_FILTER = 'SET_ENVIRONMENTS_FILTER';
......
......@@ -59,7 +59,6 @@ export default {
*/
[types.REQUEST_METRICS_DASHBOARD](state) {
state.emptyState = dashboardEmptyStates.LOADING;
state.showEmptyState = true;
},
[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboardYML) {
const { dashboard, panelGroups, variables, links } = mapToDashboardViewModel(dashboardYML);
......@@ -72,13 +71,14 @@ export default {
if (!state.dashboard.panelGroups.length) {
state.emptyState = dashboardEmptyStates.NO_DATA;
} else {
state.emptyState = null;
}
},
[types.RECEIVE_METRICS_DASHBOARD_FAILURE](state, error) {
state.emptyState = error
? dashboardEmptyStates.UNABLE_TO_CONNECT
: dashboardEmptyStates.NO_DATA;
state.showEmptyState = true;
},
[types.REQUEST_DASHBOARD_STARRING](state) {
......@@ -152,9 +152,6 @@ export default {
const metric = findMetricInDashboard(metricId, state.dashboard);
metric.loading = false;
state.showEmptyState = false;
state.emptyState = null;
if (!data.result || data.result.length === 0) {
metric.state = metricStates.NO_DATA;
metric.result = null;
......@@ -184,13 +181,8 @@ export default {
state.timeRange = timeRange;
},
[types.SET_GETTING_STARTED_EMPTY_STATE](state) {
state.showEmptyState = true;
state.emptyState = dashboardEmptyStates.GETTING_STARTED;
},
[types.SET_NO_DATA_EMPTY_STATE](state) {
state.showEmptyState = true;
state.emptyState = dashboardEmptyStates.NO_DATA;
},
[types.SET_ALL_DASHBOARDS](state, dashboards) {
state.allDashboards = dashboards || [];
},
......
......@@ -21,8 +21,13 @@ export default () => ({
// Dashboard data
hasDashboardValidationWarnings: false,
/**
* {?String} If set, dashboard should display a global
* empty state, there is no way to interact (yet)
* with the dashboard.
*/
emptyState: dashboardEmptyStates.GETTING_STARTED,
showEmptyState: true,
showErrorBanner: true,
isUpdatingStarredValue: false,
dashboard: {
......
......@@ -76,9 +76,11 @@ module Clusters
'clusters-path': clusterable.index_path,
'dashboard-endpoint': clusterable.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster-ultimate'),
'add-dashboard-documentation-path': help_page_path('user/project/integrations/prometheus.md', anchor: 'adding-a-new-dashboard-to-your-project'),
'empty-getting-started-svg-path': image_path('illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': image_path('illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': image_path('illustrations/monitoring/no_data.svg'),
'empty-no-data-small-svg-path': image_path('illustrations/chart-empty-state-small.svg'),
'empty-unable-to-connect-svg-path': image_path('illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
......
---
title: Replace initial dashboard loading state with a loading spinner, show dashboard
skeleton earlier with smaller loading indicators
merge_request: 36399
author:
type: changed
......@@ -141,10 +141,6 @@ exports[`Dashboard template matches the default snapshot 1`] = `
/>
</div>
<!---->
<!---->
<empty-state-stub
clusterspath="/monitoring/monitor-project/-/clusters"
documentationpath="/help/administration/monitoring/prometheus/index.md"
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EmptyState shows gettingStarted state 1`] = `
<gl-empty-state-stub
description="Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
primarybuttonlink="/clustersPath"
primarybuttontext="Install on clusters"
secondarybuttonlink="/settingsPath"
secondarybuttontext="Configure existing installation"
svgpath="/path/to/getting-started.svg"
title="Get started with performance monitoring"
/>
`;
exports[`EmptyState shows loading state 1`] = `
<gl-empty-state-stub
description="Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
primarybuttonlink="/documentationPath"
primarybuttontext="View documentation"
secondarybuttonlink=""
secondarybuttontext=""
svgpath="/path/to/loading.svg"
title="Waiting for performance data"
/>
<div>
<!---->
<gl-empty-state-stub
description="Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
primarybuttonlink="/clustersPath"
primarybuttontext="Install on clusters"
secondarybuttonlink="/settingsPath"
secondarybuttontext="Configure existing installation"
svgpath="/path/to/getting-started.svg"
title="Get started with performance monitoring"
/>
</div>
`;
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"
/>
<div>
<!---->
<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"
/>
</div>
`;
exports[`EmptyState shows unableToConnect state 1`] = `
<gl-empty-state-stub
description="Ensure connectivity is available from the GitLab server to the Prometheus server"
primarybuttonlink="/documentationPath"
primarybuttontext="View documentation"
secondarybuttonlink="/settingsPath"
secondarybuttontext="Configure Prometheus"
svgpath="/path/to/unable-to-connect.svg"
title="Unable to connect to Prometheus server"
/>
<div>
<!---->
<gl-empty-state-stub
description="Ensure connectivity is available from the GitLab server to the Prometheus server"
primarybuttonlink="/documentationPath"
primarybuttontext="View documentation"
secondarybuttonlink="/settingsPath"
secondarybuttontext="Configure Prometheus"
svgpath="/path/to/unable-to-connect.svg"
title="Unable to connect to Prometheus server"
/>
</div>
`;
......@@ -143,7 +143,7 @@ describe('Dashboard', () => {
setupStoreWithData(store);
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.showEmptyState).toEqual(false);
expect(wrapper.vm.emptyState).toBeNull();
expect(wrapper.findAll('.prometheus-panel')).toHaveLength(0);
});
});
......@@ -455,6 +455,33 @@ describe('Dashboard', () => {
});
});
describe('when all panels in the first group are loading', () => {
const findGroupAt = i => wrapper.findAll(GraphGroup).at(i);
beforeEach(() => {
setupStoreWithDashboard(store);
const { panels } = store.state.monitoringDashboard.dashboard.panelGroups[0];
panels.forEach(({ metrics }) => {
store.commit(`monitoringDashboard/${types.REQUEST_METRIC_RESULT}`, {
metricId: metrics[0].metricId,
});
});
createShallowWrapper();
return wrapper.vm.$nextTick();
});
it('a loading icon appears in the first group', () => {
expect(findGroupAt(0).props('isLoading')).toBe(true);
});
it('a loading icon does not appear in the second group', () => {
expect(findGroupAt(1).props('isLoading')).toBe(false);
});
});
describe('when all requests have been commited by the store', () => {
beforeEach(() => {
store.commit(`monitoringDashboard/${types.SET_INITIAL_STATE}`, {
......@@ -478,6 +505,16 @@ describe('Dashboard', () => {
});
});
it('it does not show loading icons in any group', () => {
setupStoreWithData(store);
wrapper.vm.$nextTick(() => {
wrapper.findAll(GraphGroup).wrappers.forEach(groupWrapper => {
expect(groupWrapper.props('isLoading')).toBe(false);
});
});
});
// Note: This test is not working, .active does not show the active environment
// eslint-disable-next-line jest/no-disabled-tests
it.skip('renders the environments dropdown with a single active element', () => {
......
import { shallowMount } from '@vue/test-utils';
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import { dashboardEmptyStates } from '~/monitoring/constants';
import EmptyState from '~/monitoring/components/empty_state.vue';
function createComponent(props) {
return shallowMount(EmptyState, {
propsData: {
...props,
settingsPath: '/settingsPath',
clustersPath: '/clustersPath',
documentationPath: '/documentationPath',
......@@ -14,22 +14,24 @@ function createComponent(props) {
emptyNoDataSvgPath: '/path/to/no-data.svg',
emptyNoDataSmallSvgPath: '/path/to/no-data-small.svg',
emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
...props,
},
});
}
describe('EmptyState', () => {
it('shows gettingStarted state', () => {
it('shows loading state with a loading icon', () => {
const wrapper = createComponent({
selectedState: dashboardEmptyStates.GETTING_STARTED,
selectedState: dashboardEmptyStates.LOADING,
});
expect(wrapper.element).toMatchSnapshot();
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
expect(wrapper.find(GlEmptyState).exists()).toBe(false);
});
it('shows loading state', () => {
it('shows gettingStarted state', () => {
const wrapper = createComponent({
selectedState: dashboardEmptyStates.LOADING,
selectedState: dashboardEmptyStates.GETTING_STARTED,
});
expect(wrapper.element).toMatchSnapshot();
......
import { shallowMount } from '@vue/test-utils';
import GraphGroup from '~/monitoring/components/graph_group.vue';
import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
describe('Graph group component', () => {
let wrapper;
const findGroup = () => wrapper.find({ ref: 'graph-group' });
const findContent = () => wrapper.find({ ref: 'graph-group-content' });
const findCaretIcon = () => wrapper.find(Icon);
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findCaretIcon = () => wrapper.find(GlIcon);
const findToggleButton = () => wrapper.find('[data-testid="group-toggle-button"]');
const createComponent = propsData => {
......@@ -28,15 +29,19 @@ describe('Graph group component', () => {
});
});
it('should not show a loading icon', () => {
expect(findLoadingIcon().exists()).toBe(false);
});
it('should show the angle-down caret icon', () => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().props('name')).toBe('angle-down');
});
it('should show the angle-right caret icon when the user collapses the group', () => {
wrapper.vm.collapse();
findToggleButton().trigger('click');
return wrapper.vm.$nextTick(() => {
return wrapper.vm.$nextTick().then(() => {
expect(findContent().isVisible()).toBe(false);
expect(findCaretIcon().props('name')).toBe('angle-right');
});
......@@ -53,77 +58,94 @@ describe('Graph group component', () => {
collapseGroup: true,
});
return wrapper.vm.$nextTick(() => {
return wrapper.vm.$nextTick().then(() => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().props('name')).toBe('angle-down');
});
});
});
describe('When group is collapsed', () => {
beforeEach(() => {
createComponent({
name: 'panel',
collapseGroup: true,
});
describe('When group is collapsed', () => {
beforeEach(() => {
createComponent({
name: 'panel',
collapseGroup: true,
});
});
it('should show the angle-down caret icon when collapseGroup is true', () => {
expect(wrapper.vm.caretIcon).toBe('angle-right');
});
it('should show the angle-down caret icon when collapseGroup is true', () => {
expect(findCaretIcon().props('name')).toBe('angle-right');
});
it('should show the angle-right caret icon when collapseGroup is false', () => {
wrapper.vm.collapse();
it('should show the angle-right caret icon when collapseGroup is false', () => {
findToggleButton().trigger('click');
expect(wrapper.vm.caretIcon).toBe('angle-down');
return wrapper.vm.$nextTick().then(() => {
expect(findCaretIcon().props('name')).toBe('angle-down');
});
});
it('should call collapse the graph group content when enter is pressed on the caret icon', () => {
const graphGroupContent = findContent();
const button = findToggleButton();
it('should call collapse the graph group content when enter is pressed on the caret icon', () => {
const graphGroupContent = findContent();
const button = findToggleButton();
button.trigger('keyup.enter');
button.trigger('keyup.enter');
expect(graphGroupContent.isVisible()).toBe(false);
expect(graphGroupContent.isVisible()).toBe(false);
});
});
describe('When groups can not be collapsed', () => {
beforeEach(() => {
createComponent({
name: 'panel',
showPanels: false,
collapseGroup: false,
});
});
describe('When groups can not be collapsed', () => {
beforeEach(() => {
createComponent({
name: 'panel',
showPanels: false,
collapseGroup: false,
});
it('should not have a container when showPanels is false', () => {
expect(findGroup().exists()).toBe(false);
expect(findContent().exists()).toBe(true);
});
});
describe('When group is loading', () => {
beforeEach(() => {
createComponent({
name: 'panel',
isLoading: true,
});
});
it('should not have a container when showPanels is false', () => {
expect(findGroup().exists()).toBe(false);
expect(findContent().exists()).toBe(true);
it('should show a loading icon', () => {
expect(findLoadingIcon().exists()).toBe(true);
});
});
describe('When group does not show a panel heading', () => {
beforeEach(() => {
createComponent({
name: 'panel',
showPanels: false,
collapseGroup: false,
});
});
describe('When group does not show a panel heading', () => {
beforeEach(() => {
createComponent({
name: 'panel',
showPanels: false,
collapseGroup: false,
});
it('should collapse the panel content', () => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().exists()).toBe(false);
});
it('should show the panel content when collapse is set to false', () => {
wrapper.setProps({
collapseGroup: false,
});
it('should collapse the panel content', () => {
return wrapper.vm.$nextTick().then(() => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().exists()).toBe(false);
});
it('should show the panel content when clicked', () => {
wrapper.vm.collapse();
return wrapper.vm.$nextTick(() => {
expect(findContent().isVisible()).toBe(true);
expect(findCaretIcon().exists()).toBe(false);
});
});
});
});
});
......@@ -15,7 +15,7 @@ describe('Links Section component', () => {
const setState = links => {
store.state.monitoringDashboard = {
...store.state.monitoringDashboard,
showEmptyState: false,
emptyState: null,
links,
};
};
......
......@@ -29,7 +29,7 @@ describe('Metrics dashboard/variables section component', () => {
beforeEach(() => {
store = createStore();
store.state.monitoringDashboard.showEmptyState = false;
store.state.monitoringDashboard.emptyState = null;
});
it('does not show the variables section', () => {
......@@ -70,7 +70,7 @@ describe('Metrics dashboard/variables section component', () => {
monitoringDashboard: {
namespaced: true,
state: {
showEmptyState: false,
emptyState: null,
variables: storeVariables,
},
actions: {
......
......@@ -20,7 +20,6 @@ describe('Monitoring mutations', () => {
mutations[types.REQUEST_METRICS_DASHBOARD](stateCopy);
expect(stateCopy.emptyState).toBe(dashboardEmptyStates.LOADING);
expect(stateCopy.showEmptyState).toBe(true);
});
});
......@@ -98,14 +97,12 @@ describe('Monitoring mutations', () => {
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);
});
});
......@@ -292,13 +289,10 @@ describe('Monitoring mutations', () => {
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, dashboard);
});
it('stores a loading state on a metric', () => {
expect(stateCopy.showEmptyState).toBe(true);
mutations[types.REQUEST_METRIC_RESULT](stateCopy, {
metricId,
});
expect(stateCopy.showEmptyState).toBe(true);
expect(getMetric()).toEqual(
expect.objectContaining({
loading: true,
......@@ -311,17 +305,6 @@ describe('Monitoring mutations', () => {
beforeEach(() => {
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, dashboard);
});
it('clears empty state', () => {
expect(stateCopy.showEmptyState).toBe(true);
mutations[types.RECEIVE_METRIC_RESULT_SUCCESS](stateCopy, {
metricId,
data,
});
expect(stateCopy.showEmptyState).toBe(false);
expect(stateCopy.emptyState).toBe(null);
});
it('adds results to the store', () => {
expect(getMetric().result).toBe(null);
......@@ -345,16 +328,6 @@ describe('Monitoring mutations', () => {
beforeEach(() => {
mutations[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](stateCopy, dashboard);
});
it('maintains the loading state when a metric fails', () => {
expect(stateCopy.showEmptyState).toBe(true);
mutations[types.RECEIVE_METRIC_RESULT_FAILURE](stateCopy, {
metricId,
error: 'an error',
});
expect(stateCopy.showEmptyState).toBe(true);
});
it('stores a timeout error in a metric', () => {
mutations[types.RECEIVE_METRIC_RESULT_FAILURE](stateCopy, {
......
......@@ -265,9 +265,11 @@ RSpec.describe Clusters::ClusterPresenter do
is_expected.to include('clusters-path': clusterable_presenter.index_path,
'dashboard-endpoint': clusterable_presenter.metrics_dashboard_path(cluster),
'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster-ultimate'),
'add-dashboard-documentation-path': help_page_path('user/project/integrations/prometheus.md', anchor: 'adding-a-new-dashboard-to-your-project'),
'empty-getting-started-svg-path': match_asset_path('/assets/illustrations/monitoring/getting_started.svg'),
'empty-loading-svg-path': match_asset_path('/assets/illustrations/monitoring/loading.svg'),
'empty-no-data-svg-path': match_asset_path('/assets/illustrations/monitoring/no_data.svg'),
'empty-no-data-small-svg-path': match_asset_path('illustrations/chart-empty-state-small.svg'),
'empty-unable-to-connect-svg-path': match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'),
'settings-path': '',
'project-path': '',
......
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