diff --git a/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.test.ts b/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.test.ts index 5af5d46ee1a..a196838757d 100644 --- a/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.test.ts +++ b/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.test.ts @@ -176,6 +176,23 @@ describe('ProjectsNavigation', () => { expect(getByText('Projects')).toBeVisible(); }); + it('should render a fallback icon for projects with no icon set', async () => { + projectsStore.teamProjectsLimit = -1; + const projectWithoutIcon = createProjectListItem('team'); + projectWithoutIcon.icon = null; + projectsStore.myProjects = [projectWithoutIcon]; + + const { getAllByTestId } = renderComponent({ + props: { + collapsed: false, + }, + }); + + const items = getAllByTestId('project-menu-item'); + expect(items).toHaveLength(1); + expect(items[0].querySelector('svg')).toBeInTheDocument(); + }); + it('should not render shared menu item when only one verified user', async () => { // Only one verified user usersStore.allUsers = [ diff --git a/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.vue b/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.vue index bf66cfbe366..0a3825747b1 100644 --- a/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.vue +++ b/packages/frontend/editor-ui/src/features/collaboration/projects/components/ProjectNavigation.vue @@ -9,6 +9,7 @@ import type { IMenuItem } from '@n8n/design-system/types'; import { useI18n } from '@n8n/i18n'; import { computed, onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'; import { useProjectsStore } from '../projects.store'; +import { DEFAULT_PROJECT_ICON } from '../projects.constants'; import type { ProjectListItem } from '../projects.types'; import { CHAT_VIEW } from '@/features/ai/chatHub/constants'; import { useFavoritesStore } from '@/app/stores/favorites.store'; @@ -91,7 +92,7 @@ const shared = computed(() => ({ const getProjectMenuItem = (project: ProjectListItem): IMenuItem => ({ id: project.id, label: project.name ?? '', - icon: project.icon as IMenuItem['icon'], + icon: (project.icon as IMenuItem['icon']) ?? DEFAULT_PROJECT_ICON, route: { to: { name: VIEWS.PROJECTS_WORKFLOWS, diff --git a/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.test.ts b/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.test.ts index c3544c93468..509c774a3fc 100644 --- a/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.test.ts +++ b/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.test.ts @@ -99,7 +99,10 @@ describe('useFavoriteNavItems', () => { const { favoriteProjectItems } = useFavoriteNavItems(); - expect(favoriteProjectItems.value[0].menuItem.icon).toBe('layers'); + expect(favoriteProjectItems.value[0].menuItem.icon).toEqual({ + type: 'icon', + value: 'layers', + }); }); it('should use raw resourceId as item id (no prefix)', () => { diff --git a/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.ts b/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.ts index a7db79e96e7..a24b4bd3841 100644 --- a/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.ts +++ b/packages/frontend/editor-ui/src/features/collaboration/projects/composables/useFavoriteNavItems.ts @@ -3,6 +3,7 @@ import type { IMenuItem } from '@n8n/design-system/types'; import { VIEWS } from '@/app/constants'; import { useFavoritesStore } from '@/app/stores/favorites.store'; import { useProjectsStore } from '../projects.store'; +import { DEFAULT_PROJECT_ICON } from '../projects.constants'; import type { Project } from '../projects.types'; import { DATA_TABLE_DETAILS } from '@/features/core/dataTable/constants'; import type { FavoriteResourceType } from '@/app/api/favorites'; @@ -46,7 +47,7 @@ export function useFavoriteNavItems() { menuItem: { id: f.resourceId, label: f.resourceName, - icon: (project?.icon as IMenuItem['icon']) ?? ('layers' as IMenuItem['icon']), + icon: (project?.icon as IMenuItem['icon']) ?? DEFAULT_PROJECT_ICON, route: { to: { name: VIEWS.PROJECTS_WORKFLOWS, params: { projectId: f.resourceId } } }, }, resourceId: f.resourceId, diff --git a/packages/frontend/editor-ui/src/features/collaboration/projects/projects.constants.ts b/packages/frontend/editor-ui/src/features/collaboration/projects/projects.constants.ts index 65907d273e2..409ae69729e 100644 --- a/packages/frontend/editor-ui/src/features/collaboration/projects/projects.constants.ts +++ b/packages/frontend/editor-ui/src/features/collaboration/projects/projects.constants.ts @@ -1 +1,5 @@ +import type { IconOrEmoji } from '@n8n/design-system/components/N8nIconPicker/types'; + export const PROJECT_MOVE_RESOURCE_MODAL = 'projectMoveResourceModal'; + +export const DEFAULT_PROJECT_ICON: IconOrEmoji = { type: 'icon', value: 'layers' }; diff --git a/packages/frontend/editor-ui/src/features/collaboration/projects/views/ProjectSettings.vue b/packages/frontend/editor-ui/src/features/collaboration/projects/views/ProjectSettings.vue index 304763bf8a9..3fe8af064a6 100644 --- a/packages/frontend/editor-ui/src/features/collaboration/projects/views/ProjectSettings.vue +++ b/packages/frontend/editor-ui/src/features/collaboration/projects/views/ProjectSettings.vue @@ -7,6 +7,7 @@ import { useDebounceFn } from '@vueuse/core'; import { useUsersStore } from '@/features/settings/users/users.store'; import { useI18n } from '@n8n/i18n'; import { type ResourceCounts, useProjectsStore } from '../projects.store'; +import { DEFAULT_PROJECT_ICON } from '../projects.constants'; import type { Project, ProjectRelation, ProjectMemberData } from '../projects.types'; import { useToast } from '@/app/composables/useToast'; import { DEBOUNCE_TIME, getDebounceTime, VIEWS } from '@/app/constants'; @@ -84,10 +85,7 @@ const suppressNextSync = ref(false); const nameInput = ref | null>(null); -const projectIcon = ref({ - type: 'icon', - value: 'layers', -}); +const projectIcon = ref({ ...DEFAULT_PROJECT_ICON }); const search = ref(''); const membersTableState = ref({