From 3fb0db611b5faa615565d5cd9a839a33fac06a88 Mon Sep 17 00:00:00 2001 From: Julia Miocene <jmiocene@gitlab.com> Date: Wed, 14 Feb 2024 01:33:03 +0000 Subject: [PATCH] Improve environments dashboard Changelog: changed --- .../components/dashboard/dashboard.vue | 58 ++++++----- .../components/dashboard/dashboard.vue | 79 ++++++++------- .../__snapshots__/dashboard_spec.js.snap | 99 ------------------- .../components/dashboard_spec.js | 92 +++++++++-------- .../components/dashboard/dashboard_spec.js | 80 ++++++++------- locale/gitlab.pot | 3 - 6 files changed, 168 insertions(+), 243 deletions(-) delete mode 100644 ee/spec/frontend/environments_dashboard/components/__snapshots__/dashboard_spec.js.snap diff --git a/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue b/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue index 2d468583e80af..212155ea51850 100644 --- a/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue +++ b/ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue @@ -96,6 +96,9 @@ export default { this.paginateDashboard(newPage); }, }, + showDashboard() { + return this.projects.length || this.isLoadingProjects; + }, projectsPerPage() { return this.projectsPage.pageInfo.perPage; }, @@ -160,7 +163,7 @@ export default { </script> <template> - <div class="environments-dashboard"> + <div v-if="showDashboard" class="environments-dashboard"> <gl-modal :modal-id="$options.modalId" :title="$options.addProjectsModalHeader" @@ -193,14 +196,17 @@ export default { /> </gl-modal> <div class="page-title-holder flex-fill d-flex gl-align-items-center"> - <h1 class="js-dashboard-title page-title gl-font-size-h-display text-nowrap flex-fill"> + <h1 + class="page-title gl-font-size-h-display text-nowrap flex-fill" + data-testid="dashboard-title" + > {{ $options.dashboardHeader }} </h1> - <gl-button v-gl-modal="$options.modalId" class="js-add-projects-button" variant="confirm"> + <gl-button v-gl-modal="$options.modalId" data-testid="add-projects-button" variant="confirm"> {{ $options.addProjectsButton }} </gl-button> </div> - <p class="mt-2 mb-4 js-page-limits-message"> + <p class="gl-mt-3 gl-mb-6" data-testid="page-limits-message"> <gl-sprintf :message="$options.informationText"> <template #link="{ content }"> <gl-link :href="environmentsDashboardHelpPath" target="_blank"> @@ -234,26 +240,30 @@ export default { </div> <gl-dashboard-skeleton v-else-if="isLoadingProjects" /> - - <gl-empty-state - v-else - :title="$options.emptyDashboardHeader" - :svg-path="emptyDashboardSvgPath" - :svg-height="150" - > - <template #description> - {{ $options.emptyDashboardDocs }} - <gl-link :href="emptyDashboardHelpPath" class="js-documentation-link">{{ - $options.viewDocumentationButton - }}</gl-link - >. - </template> - <template #actions> - <gl-button v-gl-modal="$options.modalId" variant="confirm" class="js-add-projects-button"> - {{ s__('ModalButton|Add projects') }} - </gl-button> - </template> - </gl-empty-state> </div> </div> + <gl-empty-state + v-else + :title="$options.emptyDashboardHeader" + :description="$options.emptyDashboardDocs" + :svg-path="emptyDashboardSvgPath" + > + <template #actions> + <gl-button + v-gl-modal="$options.modalId" + variant="confirm" + class="gl-mb-3 gl-mx-2" + data-testid="add-projects-button" + > + {{ $options.addProjectsButton }} + </gl-button> + <gl-button + :href="emptyDashboardHelpPath" + class="gl-mb-3 gl-mx-2" + data-testid="documentation-link" + > + {{ $options.viewDocumentationButton }} + </gl-button> + </template> + </gl-empty-state> </template> diff --git a/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue b/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue index 7baf0fa801c84..6032dcc6e8462 100644 --- a/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue +++ b/ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue @@ -17,9 +17,18 @@ import ProjectSelector from '~/vue_shared/components/project_selector/project_se import DashboardProject from './project.vue'; export default { + title: s__('OperationsDashboard|Operations Dashboard'), informationText: s__( 'OperationsDashboard|The Operations and Environments dashboards share the same list of projects. When you add or remove a project from one, GitLab adds or removes the project from the other. %{linkStart}More information%{linkEnd}', ), + moreInformationButton: s__('OperationsDashboard|More information'), + addProjectsSubmitButton: s__('OperationsDashboard|Add projects'), + addProjectsModalHeader: s__('OperationsDashboard|Add projects'), + dashboardHeader: s__('OperationsDashboard|Operations Dashboard'), + emptyStateTitle: s__(`OperationsDashboard|Add a project to the dashboard`), + emptyStateDescription: s__( + `OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses.`, + ), components: { DashboardProject, GlDashboardSkeleton, @@ -74,6 +83,9 @@ export default { this.setProjects(projects); }, }, + showDashboard() { + return this.projects.length || this.isLoadingProjects; + }, isSearchingProjects() { return this.searchCount > 0; }, @@ -82,7 +94,7 @@ export default { }, actionPrimary() { return { - text: s__('OperationsDashboard|Add projects'), + text: this.addProjectsSubmitButton, attributes: { disabled: this.okDisabled, variant: 'confirm', @@ -135,10 +147,10 @@ export default { </script> <template> - <div class="operations-dashboard"> + <div v-if="showDashboard" class="operations-dashboard"> <gl-modal :modal-id="$options.modalId" - :title="s__('OperationsDashboard|Add projects')" + :title="$options.addProjectsModalHeader" :action-primary="actionPrimary" :action-cancel="$options.modal.actionCancel" data-testid="add-projects-modal" @@ -161,8 +173,11 @@ export default { </gl-modal> <div class="page-title-holder flex-fill d-flex gl-align-items-center"> - <h1 class="js-dashboard-title page-title gl-font-size-h-display text-nowrap flex-fill"> - {{ s__('OperationsDashboard|Operations Dashboard') }} + <h1 + class="page-title gl-font-size-h-display text-nowrap flex-fill" + data-testid="dashboard-title" + > + {{ $options.title }} </h1> <gl-button v-if="projects.length" @@ -171,7 +186,7 @@ export default { category="primary" data-testid="add-projects-button" > - {{ s__('OperationsDashboard|Add projects') }} + {{ $options.addProjectsSubmitButton }} </gl-button> </div> <p class="gl-mt-2 gl-mb-4"> @@ -196,34 +211,30 @@ export default { </vue-draggable> <gl-dashboard-skeleton v-else-if="isLoadingProjects" /> - - <gl-empty-state - v-else - :title="s__(`OperationsDashboard|Add a project to the dashboard`)" - :svg-path="emptyDashboardSvgPath" - :svg-height="150" - > - <template #description> - {{ - s__( - `OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses.`, - ) - }} - <gl-link :href="emptyDashboardHelpPath" data-testid="documentation-link">{{ - s__('OperationsDashboard|More information') - }}</gl-link - >. - </template> - <template #actions> - <gl-button - v-gl-modal="$options.modalId" - variant="confirm" - data-testid="add-projects-button" - > - {{ s__('OperationsDashboard|Add projects') }} - </gl-button> - </template> - </gl-empty-state> </div> </div> + <gl-empty-state + v-else + :title="$options.emptyStateTitle" + :description="$options.emptyStateDescription" + :svg-path="emptyDashboardSvgPath" + > + <template #actions> + <gl-button + v-gl-modal="$options.modalId" + variant="confirm" + data-testid="add-projects-button" + class="gl-mb-3 gl-mx-2" + > + {{ $options.addProjectsSubmitButton }} + </gl-button> + <gl-button + :href="emptyDashboardHelpPath" + data-testid="documentation-link" + class="gl-mb-3 gl-mx-2" + > + {{ $options.moreInformationButton }} + </gl-button> + </template> + </gl-empty-state> </template> diff --git a/ee/spec/frontend/environments_dashboard/components/__snapshots__/dashboard_spec.js.snap b/ee/spec/frontend/environments_dashboard/components/__snapshots__/dashboard_spec.js.snap deleted file mode 100644 index d68cbec111ca3..0000000000000 --- a/ee/spec/frontend/environments_dashboard/components/__snapshots__/dashboard_spec.js.snap +++ /dev/null @@ -1,99 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`dashboard should match the snapshot 1`] = ` -<div - class="environments-dashboard" -> - <gl-modal-stub - arialabel="" - dismisslabel="Close" - modalclass="" - modalid="add-projects-modal" - ok-disabled="true" - ok-title="Add projects" - size="md" - title="Add projects" - titletag="h4" - > - <p> - This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. - <gl-link-stub - href="/help/user/operations_dashboard/index.html" - target="_blank" - > - More information - </gl-link-stub> - </p> - <project-selector-stub - maxlistheight="402" - projectsearchresults="" - selectedprojects="" - totalresults="0" - /> - </gl-modal-stub> - <div - class="d-flex flex-fill gl-align-items-center page-title-holder" - > - <h1 - class="flex-fill gl-font-size-h-display js-dashboard-title page-title text-nowrap" - > - Environments Dashboard - </h1> - <gl-button-stub - buttontextclasses="" - category="primary" - class="js-add-projects-button" - icon="" - role="button" - size="medium" - tabindex="0" - variant="confirm" - > - Add projects - </gl-button-stub> - </div> - <p - class="js-page-limits-message mb-4 mt-2" - > - This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. - <gl-link-stub - href="/help/user/operations_dashboard/index.html" - target="_blank" - > - More information - </gl-link-stub> - </p> - <div - class="gl-mt-3" - > - <gl-empty-state-stub - contentclass="" - invertindarkmode="true" - svgheight="150" - svgpath="/assets/illustrations/empty-state/empty-radar-md.svg" - title="Add a project to the dashboard" - > - The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses. - <gl-link-stub - class="js-documentation-link" - href="/help/user/operations_dashboard/index.html" - > - View documentation - </gl-link-stub> - . - <gl-button-stub - buttontextclasses="" - category="primary" - class="js-add-projects-button" - icon="" - role="button" - size="medium" - tabindex="0" - variant="confirm" - > - Add projects - </gl-button-stub> - </gl-empty-state-stub> - </div> -</div> -`; diff --git a/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js b/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js index eaa38fa100689..7ffc3b4fc7354 100644 --- a/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js +++ b/ee/spec/frontend/environments_dashboard/components/dashboard_spec.js @@ -1,8 +1,8 @@ import { GlButton, GlEmptyState, GlModal, GlSprintf, GlLink, GlPagination } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; // eslint-disable-next-line no-restricted-imports import Vuex from 'vuex'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import component from 'ee/environments_dashboard/components/dashboard/dashboard.vue'; import Environment from 'ee/environments_dashboard/components/dashboard/environment.vue'; import ProjectHeader from 'ee/environments_dashboard/components/dashboard/project_header.vue'; @@ -50,7 +50,7 @@ describe('dashboard', () => { environmentsDashboardHelpPath: '/help/user/operations_dashboard/index.html', }; - wrapper = shallowMount(component, { + wrapper = shallowMountExtended(component, { propsData, store, stubs: { GlSprintf }, @@ -62,53 +62,24 @@ describe('dashboard', () => { }); const findPagination = () => wrapper.findComponent(GlPagination); + const findDashboardTitle = () => wrapper.findByTestId('dashboard-title'); + const findPageLimitsMessage = () => wrapper.findByTestId('page-limits-message'); - it('should match the snapshot', () => { - expect(wrapper.element).toMatchSnapshot(); - }); - - it('renders the dashboard title', () => { - expect(wrapper.find('.js-dashboard-title').text()).toBe('Environments Dashboard'); - }); - - it('should render the empty state component', () => { - expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true); - }); - - it('should not render pagination in empty state', () => { - expect(findPagination().exists()).toBe(false); - }); - - describe('page limits information message', () => { - let message; - - beforeEach(() => { - message = wrapper.find('.js-page-limits-message'); - }); - - it('renders the message', () => { - expect(trimText(message.text())).toBe( - 'This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. More information', - ); + describe('empty state', () => { + it('should render the empty state component', () => { + expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true); }); - it('includes the correct documentation link in the message', () => { - const helpLink = message.findComponent(GlLink); - - expect(helpLink.text()).toBe('More information'); - expect(helpLink.attributes('href')).toBe(propsData.environmentsDashboardHelpPath); + it('should not the render title', () => { + expect(findDashboardTitle().exists()).toBe(false); }); - }); - - describe('add projects button', () => { - let button; - beforeEach(() => { - button = wrapper.findComponent(GlButton); + it('should not the render description', () => { + expect(findPageLimitsMessage().exists()).toBe(false); }); - it('is labelled correctly', () => { - expect(button.text()).toBe('Add projects'); + it('should not render pagination', () => { + expect(findPagination().exists()).toBe(false); }); }); @@ -125,6 +96,43 @@ describe('dashboard', () => { ]; }); + it('renders the dashboard title', () => { + expect(findDashboardTitle().text()).toBe('Environments Dashboard'); + }); + + describe('page limits information message', () => { + let message; + + beforeEach(() => { + message = findPageLimitsMessage(); + }); + + it('renders the message', () => { + expect(trimText(message.text())).toBe( + 'This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. More information', + ); + }); + + it('includes the correct documentation link in the message', () => { + const helpLink = message.findComponent(GlLink); + + expect(helpLink.text()).toBe('More information'); + expect(helpLink.attributes('href')).toBe(propsData.environmentsDashboardHelpPath); + }); + }); + + describe('add projects button', () => { + let button; + + beforeEach(() => { + button = wrapper.findComponent(GlButton); + }); + + it('is labelled correctly', () => { + expect(button.text()).toBe('Add projects'); + }); + }); + describe('project header', () => { it('should have one project header per project', () => { const headers = wrapper.findAllComponents(ProjectHeader); diff --git a/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js b/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js index c4721a635d03a..698785370e7a2 100644 --- a/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js +++ b/ee/spec/frontend/operations/components/dashboard/dashboard_spec.js @@ -59,18 +59,50 @@ describe('dashboard component', () => { mockAxios.restore(); }); - it('renders dashboard title', () => { - const dashboardTitle = wrapper.element.querySelector('.js-dashboard-title'); + describe('when no projects have been added', () => { + beforeEach(() => { + store.state.projects = []; + store.state.isLoadingProjects = false; + }); + + it('should render the empty state', () => { + expect(findEmptyState().exists()).toBe(true); + }); - expect(dashboardTitle.innerText.trim()).toEqual(mockText.DASHBOARD_TITLE); + it('should link to the documentation', () => { + const link = wrapper.findByTestId('documentation-link'); + + expect(link.exists()).toBe(true); + expect(link.attributes().href).toEqual(emptyDashboardHelpPath); + }); + + it('should render the add projects button', () => { + const button = findAddProjectButton(); + + expect(button.exists()).toBe(true); + expect(button.text()).toEqual('Add projects'); + }); }); - describe('add projects button', () => { - it('renders add projects text', () => { - expect(findAddProjectButton().text()).toBe(mockText.ADD_PROJECTS); + describe('wrapped components', () => { + const projectCount = 3; + + beforeEach(() => { + store.state.projects = mockProjectData(projectCount); + wrapper = mountComponent(); }); - describe('when a project is added', () => { + describe('dashboard layout', () => { + it('renders dashboard title', () => { + const dashboardTitle = wrapper.findByTestId('dashboard-title'); + + expect(dashboardTitle.text()).toEqual(mockText.DASHBOARD_TITLE); + }); + + it('renders add projects text', () => { + expect(findAddProjectButton().text()).toBe(mockText.ADD_PROJECTS); + }); + it('immediately requests the project list again', async () => { mockAxios.reset(); mockAxios @@ -89,17 +121,8 @@ describe('dashboard component', () => { expect(findAllProjects()).toHaveLength(2); }); }); - }); - describe('wrapped components', () => { describe('dashboard project component', () => { - const projectCount = 1; - - beforeEach(() => { - store.state.projects = mockProjectData(projectCount); - wrapper = mountComponent(); - }); - it('includes a dashboard project component for each project', () => { expect(findAllProjects()).toHaveLength(projectCount); }); @@ -189,30 +212,5 @@ describe('dashboard component', () => { expect(store.state.selectedProjects).toHaveLength(0); }); }); - - describe('when no projects have been added', () => { - beforeEach(() => { - store.state.projects = []; - store.state.isLoadingProjects = false; - }); - - it('should render the empty state', () => { - expect(findEmptyState().exists()).toBe(true); - }); - - it('should link to the documentation', () => { - const link = findEmptyState().find('[data-testid="documentation-link"]'); - - expect(link.exists()).toBe(true); - expect(link.attributes().href).toEqual(emptyDashboardHelpPath); - }); - - it('should render the add projects button', () => { - const button = findAddProjectButton(); - - expect(button.exists()).toBe(true); - expect(button.text()).toEqual('Add projects'); - }); - }); }); }); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a54584ff1b2b0..5d03e45772e69 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -31694,9 +31694,6 @@ msgstr "" msgid "Modal updated" msgstr "" -msgid "ModalButton|Add projects" -msgstr "" - msgid "Modal|Close" msgstr "" -- GitLab