fix(editor): Show shared with me only on multi user instances (#16770)

This commit is contained in:
Nikhil Kuriakose
2025-07-03 09:07:11 +02:00
committed by GitHub
parent e54613f75f
commit 29bf4a46bd
2 changed files with 56 additions and 2 deletions

View File

@@ -6,6 +6,7 @@ import { createProjectListItem } from '@/__tests__/data/projects';
import ProjectsNavigation from '@/components/Projects/ProjectNavigation.vue'; import ProjectsNavigation from '@/components/Projects/ProjectNavigation.vue';
import { useProjectsStore } from '@/stores/projects.store'; import { useProjectsStore } from '@/stores/projects.store';
import { useSettingsStore } from '@/stores/settings.store'; import { useSettingsStore } from '@/stores/settings.store';
import { useUsersStore } from '@/stores/users.store';
vi.mock('vue-router', async () => { vi.mock('vue-router', async () => {
const actual = await vi.importActual('vue-router'); const actual = await vi.importActual('vue-router');
@@ -64,6 +65,7 @@ const renderComponent = createComponentRenderer(ProjectsNavigation, {
let projectsStore: ReturnType<typeof mockedStore<typeof useProjectsStore>>; let projectsStore: ReturnType<typeof mockedStore<typeof useProjectsStore>>;
let settingsStore: ReturnType<typeof mockedStore<typeof useSettingsStore>>; let settingsStore: ReturnType<typeof mockedStore<typeof useSettingsStore>>;
let usersStore: ReturnType<typeof mockedStore<typeof useUsersStore>>;
const personalProjects = Array.from({ length: 3 }, createProjectListItem); const personalProjects = Array.from({ length: 3 }, createProjectListItem);
const teamProjects = Array.from({ length: 3 }, () => createProjectListItem('team')); const teamProjects = Array.from({ length: 3 }, () => createProjectListItem('team'));
@@ -74,6 +76,7 @@ describe('ProjectsNavigation', () => {
projectsStore = mockedStore(useProjectsStore); projectsStore = mockedStore(useProjectsStore);
settingsStore = mockedStore(useSettingsStore); settingsStore = mockedStore(useSettingsStore);
usersStore = mockedStore(useUsersStore);
}); });
it('should not throw an error', () => { it('should not throw an error', () => {
@@ -226,4 +229,43 @@ describe('ProjectsNavigation', () => {
expect(getByTestId('add-first-project-button')).toBeVisible(); expect(getByTestId('add-first-project-button')).toBeVisible();
expect(getByTestId('add-first-project-button').classList.contains('collapsed')).toBe(true); expect(getByTestId('add-first-project-button').classList.contains('collapsed')).toBe(true);
}); });
it('should not render shared menu item when only one verified user', async () => {
// Only one verified user
usersStore.allUsers = [
{ id: '1', isPendingUser: false, isDefaultUser: false, mfaEnabled: false },
{ id: '2', isPendingUser: true, isDefaultUser: false, mfaEnabled: false },
];
projectsStore.teamProjectsLimit = -1;
projectsStore.isTeamProjectFeatureEnabled = true;
const { queryByTestId } = renderComponent({
props: {
collapsed: false,
},
});
// The shared menu item should not be rendered
expect(queryByTestId('project-shared-menu-item')).not.toBeInTheDocument();
});
it('should render shared menu item when more than one verified user', async () => {
// Only one verified user
usersStore.allUsers = [
{ id: '1', isPendingUser: false, isDefaultUser: false, mfaEnabled: false },
{ id: '2', isPendingUser: true, isDefaultUser: false, mfaEnabled: false },
{ id: '3', isPendingUser: false, isDefaultUser: false, mfaEnabled: false },
];
projectsStore.teamProjectsLimit = -1;
projectsStore.isTeamProjectFeatureEnabled = true;
const { getByTestId } = renderComponent({
props: {
collapsed: false,
},
});
// The shared menu item should not be rendered
expect(getByTestId('project-shared-menu-item')).toBeInTheDocument();
});
}); });

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue'; import { computed, onBeforeMount } from 'vue';
import type { IMenuItem } from '@n8n/design-system/types'; import type { IMenuItem } from '@n8n/design-system/types';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
@@ -7,6 +7,7 @@ import { useProjectsStore } from '@/stores/projects.store';
import type { ProjectListItem } from '@/types/projects.types'; import type { ProjectListItem } from '@/types/projects.types';
import { useGlobalEntityCreation } from '@/composables/useGlobalEntityCreation'; import { useGlobalEntityCreation } from '@/composables/useGlobalEntityCreation';
import { useSettingsStore } from '@/stores/settings.store'; import { useSettingsStore } from '@/stores/settings.store';
import { useUsersStore } from '@/stores/users.store';
type Props = { type Props = {
collapsed: boolean; collapsed: boolean;
@@ -20,10 +21,14 @@ const globalEntityCreation = useGlobalEntityCreation();
const projectsStore = useProjectsStore(); const projectsStore = useProjectsStore();
const settingsStore = useSettingsStore(); const settingsStore = useSettingsStore();
const usersStore = useUsersStore();
const isCreatingProject = computed(() => globalEntityCreation.isCreatingProject.value); const isCreatingProject = computed(() => globalEntityCreation.isCreatingProject.value);
const displayProjects = computed(() => globalEntityCreation.displayProjects.value); const displayProjects = computed(() => globalEntityCreation.displayProjects.value);
const isFoldersFeatureEnabled = computed(() => settingsStore.isFoldersFeatureEnabled); const isFoldersFeatureEnabled = computed(() => settingsStore.isFoldersFeatureEnabled);
const hasMultipleVerifiedUsers = computed(
() => usersStore.allUsers.filter((user) => user.isPendingUser === false).length > 1,
);
const home = computed<IMenuItem>(() => ({ const home = computed<IMenuItem>(() => ({
id: 'home', id: 'home',
@@ -78,6 +83,10 @@ const activeTabId = computed(() => {
: projectsStore.projectNavActiveId) ?? undefined : projectsStore.projectNavActiveId) ?? undefined
); );
}); });
onBeforeMount(async () => {
await usersStore.fetchUsers();
});
</script> </script>
<template> <template>
@@ -99,7 +108,10 @@ const activeTabId = computed(() => {
data-test-id="project-personal-menu-item" data-test-id="project-personal-menu-item"
/> />
<N8nMenuItem <N8nMenuItem
v-if="projectsStore.isTeamProjectFeatureEnabled || isFoldersFeatureEnabled" v-if="
(projectsStore.isTeamProjectFeatureEnabled || isFoldersFeatureEnabled) &&
hasMultipleVerifiedUsers
"
:item="shared" :item="shared"
:compact="props.collapsed" :compact="props.collapsed"
:active-tab="activeTabId" :active-tab="activeTabId"