mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
fix(editor): Show shared with me only on multi user instances (#16770)
This commit is contained in:
@@ -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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user