From 5d19e8f2b45dc1abc5a8253f9e3a0fdacb1ebd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20G=C3=B3mez=20Morales?= Date: Thu, 31 Oct 2024 12:43:25 +0100 Subject: [PATCH] feat(editor): Add descriptive header to projects /workflow (#11203) --- .../src/components/layouts/PageViewLayout.vue | 4 +- .../layouts/ResourceListHeader.test.ts | 20 +++++++ .../components/layouts/ResourceListHeader.vue | 43 +++++++++++++++ .../layouts/ResourcesListLayout.test.ts | 52 ++++++++++++++++++- .../layouts/ResourcesListLayout.vue | 38 +++++++++++++- .../editor-ui/src/views/ProjectSettings.vue | 28 +++++++++- .../editor-ui/src/views/WorkflowsView.test.ts | 8 +-- 7 files changed, 182 insertions(+), 11 deletions(-) create mode 100644 packages/editor-ui/src/components/layouts/ResourceListHeader.test.ts create mode 100644 packages/editor-ui/src/components/layouts/ResourceListHeader.vue diff --git a/packages/editor-ui/src/components/layouts/PageViewLayout.vue b/packages/editor-ui/src/components/layouts/PageViewLayout.vue index abb1ba02a04b6..f5cd733a15ea0 100644 --- a/packages/editor-ui/src/components/layouts/PageViewLayout.vue +++ b/packages/editor-ui/src/components/layouts/PageViewLayout.vue @@ -27,11 +27,11 @@ export default defineComponent({ diff --git a/packages/editor-ui/src/components/layouts/ResourcesListLayout.test.ts b/packages/editor-ui/src/components/layouts/ResourcesListLayout.test.ts index b7130c0c9a4df..2b213a97b9384 100644 --- a/packages/editor-ui/src/components/layouts/ResourcesListLayout.test.ts +++ b/packages/editor-ui/src/components/layouts/ResourcesListLayout.test.ts @@ -1,7 +1,12 @@ -import { setActivePinia, createPinia } from 'pinia'; +import { setActivePinia } from 'pinia'; +import { createTestingPinia } from '@pinia/testing'; +import { within, waitFor } from '@testing-library/vue'; import { createComponentRenderer } from '@/__tests__/render'; import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue'; import type router from 'vue-router'; +import { mockedStore } from '@/__tests__/utils'; +import { useProjectsStore } from '@/stores/projects.store'; +import { type Project, ProjectTypes } from '@/types/projects.types'; vi.mock('vue-router', async (importOriginal) => { const { RouterLink } = await importOriginal(); @@ -18,7 +23,8 @@ const renderComponent = createComponentRenderer(ResourcesListLayout); describe('ResourcesListLayout', () => { beforeEach(() => { - setActivePinia(createPinia()); + const pinia = createTestingPinia(); + setActivePinia(pinia); }); it('should render loading skeleton', () => { @@ -30,4 +36,46 @@ describe('ResourcesListLayout', () => { expect(container.querySelectorAll('.el-skeleton__p')).toHaveLength(25); }); + + describe('header', () => { + it('should render the correct icon', async () => { + const projects = mockedStore(useProjectsStore); + const { getByTestId } = renderComponent(); + + expect(getByTestId('list-layout-header').querySelector('.fa-home')).toBeVisible(); + + projects.currentProject = { type: ProjectTypes.Personal } as Project; + + await waitFor(() => + expect(getByTestId('list-layout-header').querySelector('.fa-user')).toBeVisible(), + ); + + const projectName = 'My Project'; + projects.currentProject = { name: projectName } as Project; + + await waitFor(() => + expect(getByTestId('list-layout-header').querySelector('.fa-layer-group')).toBeVisible(), + ); + }); + + it('should render the correct title', async () => { + const projects = mockedStore(useProjectsStore); + const { getByTestId } = renderComponent(); + + expect(within(getByTestId('list-layout-header')).getByText('Home')).toBeVisible(); + + projects.currentProject = { type: ProjectTypes.Personal } as Project; + + await waitFor(() => + expect(within(getByTestId('list-layout-header')).getByText('Personal')).toBeVisible(), + ); + + const projectName = 'My Project'; + projects.currentProject = { name: projectName } as Project; + + await waitFor(() => + expect(within(getByTestId('list-layout-header')).getByText(projectName)).toBeVisible(), + ); + }); + }); }); diff --git a/packages/editor-ui/src/components/layouts/ResourcesListLayout.vue b/packages/editor-ui/src/components/layouts/ResourcesListLayout.vue index 74f3c7d7d35b8..aa506f0128ebf 100644 --- a/packages/editor-ui/src/components/layouts/ResourcesListLayout.vue +++ b/packages/editor-ui/src/components/layouts/ResourcesListLayout.vue @@ -2,16 +2,18 @@ import { computed, defineComponent, nextTick, ref, onMounted, watch } from 'vue'; import type { PropType } from 'vue'; -import type { ProjectSharingData } from '@/types/projects.types'; +import { type ProjectSharingData, ProjectTypes } from '@/types/projects.types'; import PageViewLayout from '@/components/layouts/PageViewLayout.vue'; import PageViewLayoutList from '@/components/layouts/PageViewLayoutList.vue'; import ResourceFiltersDropdown from '@/components/forms/ResourceFiltersDropdown.vue'; +import ResourceListHeader from '@/components/layouts/ResourceListHeader.vue'; import { useUsersStore } from '@/stores/users.store'; import type { DatatableColumn } from 'n8n-design-system'; import { useI18n } from '@/composables/useI18n'; import { useDebounce } from '@/composables/useDebounce'; import { useTelemetry } from '@/composables/useTelemetry'; import { useRoute } from 'vue-router'; +import { useProjectsStore } from '@/stores/projects.store'; // eslint-disable-next-line unused-imports/no-unused-imports, @typescript-eslint/no-unused-vars import type { BaseTextKey } from '@/plugins/i18n'; @@ -44,6 +46,7 @@ export default defineComponent({ PageViewLayout, PageViewLayoutList, ResourceFiltersDropdown, + ResourceListHeader, }, props: { resourceKey: { @@ -113,6 +116,7 @@ export default defineComponent({ const i18n = useI18n(); const { callDebounced } = useDebounce(); const usersStore = useUsersStore(); + const projectsStore = useProjectsStore(); const telemetry = useTelemetry(); const sortBy = ref(props.sortOptions[0]); @@ -339,10 +343,31 @@ export default defineComponent({ } }); + const headerIcon = computed(() => { + if (projectsStore.currentProject?.type === ProjectTypes.Personal) { + return 'user'; + } else if (projectsStore.currentProject?.name) { + return 'layer-group'; + } else { + return 'home'; + } + }); + + const projectName = computed(() => { + if (!projectsStore.currentProject) { + return i18n.baseText('projects.menu.home'); + } else if (projectsStore.currentProject.type === ProjectTypes.Personal) { + return i18n.baseText('projects.menu.personal'); + } else { + return projectsStore.currentProject.name; + } + }); + return { i18n, search, usersStore, + projectsStore, filterKeys, currentPage, rowsPerPage, @@ -362,6 +387,8 @@ export default defineComponent({ setCurrentPage, setRowsPerPage, onSearch, + headerIcon, + projectName, }; }, }); @@ -369,7 +396,14 @@ export default defineComponent({