fix(editor): Follow-up fixes to projects side menu (#11327)

This commit is contained in:
Csaba Tuncsik
2024-10-22 10:19:01 +02:00
committed by GitHub
parent 0fa2e8ca85
commit 4dde772814
4 changed files with 50 additions and 13 deletions

View File

@@ -147,7 +147,8 @@ describe('ProjectsNavigation', () => {
expect(uiStore.goToUpgrade).toHaveBeenCalledWith('rbac', 'upgrade-rbac'); expect(uiStore.goToUpgrade).toHaveBeenCalledWith('rbac', 'upgrade-rbac');
}); });
it('should show "Projects" title and projects if the user has access to any team project', async () => { it('should show "Projects" title and Personal project when the feature is enabled', async () => {
projectsStore.isTeamProjectFeatureEnabled = true;
projectsStore.myProjects = [...personalProjects, ...teamProjects]; projectsStore.myProjects = [...personalProjects, ...teamProjects];
const { getByRole, getAllByTestId, getByTestId } = renderComponent({ const { getByRole, getAllByTestId, getByTestId } = renderComponent({
@@ -158,11 +159,12 @@ describe('ProjectsNavigation', () => {
expect(getByRole('heading', { level: 3, name: 'Projects' })).toBeVisible(); expect(getByRole('heading', { level: 3, name: 'Projects' })).toBeVisible();
expect(getByTestId('project-personal-menu-item')).toBeVisible(); expect(getByTestId('project-personal-menu-item')).toBeVisible();
expect(getByTestId('project-personal-menu-item').querySelector('svg')).toBeVisible();
expect(getAllByTestId('project-menu-item')).toHaveLength(teamProjects.length); expect(getAllByTestId('project-menu-item')).toHaveLength(teamProjects.length);
}); });
it('should not show "Projects" title when the menu is collapsed', async () => { it('should not show "Projects" title when the menu is collapsed', async () => {
projectsStore.myProjects = [...personalProjects, ...teamProjects]; projectsStore.isTeamProjectFeatureEnabled = true;
const { queryByRole } = renderComponent({ const { queryByRole } = renderComponent({
props: { props: {
@@ -173,8 +175,8 @@ describe('ProjectsNavigation', () => {
expect(queryByRole('heading', { level: 3, name: 'Projects' })).not.toBeInTheDocument(); expect(queryByRole('heading', { level: 3, name: 'Projects' })).not.toBeInTheDocument();
}); });
it('should not show "Projects" title when there are no available projects', async () => { it('should not show "Projects" title when the feature is not enabled', async () => {
projectsStore.myProjects = []; projectsStore.isTeamProjectFeatureEnabled = false;
const { queryByRole } = renderComponent({ const { queryByRole } = renderComponent({
props: { props: {
@@ -184,4 +186,17 @@ describe('ProjectsNavigation', () => {
expect(queryByRole('heading', { level: 3, name: 'Projects' })).not.toBeInTheDocument(); expect(queryByRole('heading', { level: 3, name: 'Projects' })).not.toBeInTheDocument();
}); });
it('should not show project icons when the menu is collapsed', async () => {
projectsStore.isTeamProjectFeatureEnabled = true;
const { getByTestId } = renderComponent({
props: {
collapsed: true,
},
});
expect(getByTestId('project-personal-menu-item')).toBeVisible();
expect(getByTestId('project-personal-menu-item').querySelector('svg')).not.toBeInTheDocument();
});
}); });

View File

@@ -45,7 +45,7 @@ const addProject = computed<IMenuItem>(() => ({
const getProjectMenuItem = (project: ProjectListItem) => ({ const getProjectMenuItem = (project: ProjectListItem) => ({
id: project.id, id: project.id,
label: project.name, label: project.name,
icon: 'layer-group', icon: props.collapsed ? undefined : 'layer-group',
route: { route: {
to: { to: {
name: VIEWS.PROJECTS_WORKFLOWS, name: VIEWS.PROJECTS_WORKFLOWS,
@@ -57,7 +57,7 @@ const getProjectMenuItem = (project: ProjectListItem) => ({
const personalProject = computed<IMenuItem>(() => ({ const personalProject = computed<IMenuItem>(() => ({
id: projectsStore.personalProject?.id ?? '', id: projectsStore.personalProject?.id ?? '',
label: locale.baseText('projects.menu.personal'), label: locale.baseText('projects.menu.personal'),
icon: 'user', icon: props.collapsed ? undefined : 'user',
route: { route: {
to: { to: {
name: VIEWS.PROJECTS_WORKFLOWS, name: VIEWS.PROJECTS_WORKFLOWS,
@@ -119,16 +119,20 @@ onMounted(async () => {
data-test-id="project-home-menu-item" data-test-id="project-home-menu-item"
/> />
</ElMenu> </ElMenu>
<hr v-if="displayProjects.length || canCreateProjects" class="mt-m mb-m" /> <hr v-if="projectsStore.isTeamProjectFeatureEnabled" class="mt-m mb-m" />
<N8nText <N8nText
v-if="!props.collapsed && displayProjects.length" v-if="!props.collapsed && projectsStore.isTeamProjectFeatureEnabled"
:class="$style.projectsLabel" :class="$style.projectsLabel"
tag="h3" tag="h3"
bold bold
> >
<span>{{ locale.baseText('projects.menu.title') }}</span> <span>{{ locale.baseText('projects.menu.title') }}</span>
</N8nText> </N8nText>
<ElMenu v-if="displayProjects.length" :collapse="props.collapsed" :class="$style.projectItems"> <ElMenu
v-if="projectsStore.isTeamProjectFeatureEnabled"
:collapse="props.collapsed"
:class="$style.projectItems"
>
<N8nMenuItem <N8nMenuItem
:item="personalProject" :item="personalProject"
:compact="props.collapsed" :compact="props.collapsed"
@@ -154,7 +158,7 @@ onMounted(async () => {
placement="right" placement="right"
:disabled="projectsStore.canCreateProjects" :disabled="projectsStore.canCreateProjects"
> >
<ElMenu :collapse="props.collapsed" class="pl-xs pr-xs"> <ElMenu :collapse="props.collapsed" class="pl-xs pr-xs mb-m">
<N8nMenuItem <N8nMenuItem
:item="addProject" :item="addProject"
:compact="props.collapsed" :compact="props.collapsed"
@@ -182,7 +186,7 @@ onMounted(async () => {
</i18n-t> </i18n-t>
</template> </template>
</N8nTooltip> </N8nTooltip>
<hr v-if="displayProjects.length || canCreateProjects" class="mt-m mb-m" /> <hr v-if="projectsStore.isTeamProjectFeatureEnabled" class="mb-m" />
</div> </div>
</template> </template>

View File

@@ -4,6 +4,7 @@ import { createComponentRenderer } from '@/__tests__/render';
import { createTestProject } from '@/__tests__/data/projects'; import { createTestProject } from '@/__tests__/data/projects';
import ProjectTabs from '@/components/Projects/ProjectTabs.vue'; import ProjectTabs from '@/components/Projects/ProjectTabs.vue';
import { useProjectsStore } from '@/stores/projects.store'; import { useProjectsStore } from '@/stores/projects.store';
import { ProjectTypes } from '@/types/projects.types';
vi.mock('vue-router', () => { vi.mock('vue-router', () => {
const params = {}; const params = {};
@@ -47,7 +48,7 @@ describe('ProjectTabs', () => {
expect(queryByText('Project settings')).not.toBeInTheDocument(); expect(queryByText('Project settings')).not.toBeInTheDocument();
}); });
it('should render project tab Settings if user has permissions', () => { it('should render project tab Settings if user has permissions and current project is of type Team', () => {
route.params.projectId = '123'; route.params.projectId = '123';
projectsStore.setCurrentProject(createTestProject({ scopes: ['project:update'] })); projectsStore.setCurrentProject(createTestProject({ scopes: ['project:update'] }));
const { getByText } = renderComponent(); const { getByText } = renderComponent();
@@ -66,4 +67,16 @@ describe('ProjectTabs', () => {
expect(getByText('Credentials')).toBeInTheDocument(); expect(getByText('Credentials')).toBeInTheDocument();
expect(queryByText('Project settings')).not.toBeInTheDocument(); expect(queryByText('Project settings')).not.toBeInTheDocument();
}); });
it('should render project tabs without Settings if project is the Personal project', () => {
route.params.projectId = '123';
projectsStore.setCurrentProject(
createTestProject({ type: ProjectTypes.Personal, scopes: ['project:update'] }),
);
const { queryByText, getByText } = renderComponent();
expect(getByText('Workflows')).toBeInTheDocument();
expect(getByText('Credentials')).toBeInTheDocument();
expect(queryByText('Project settings')).not.toBeInTheDocument();
});
}); });

View File

@@ -6,6 +6,7 @@ import { VIEWS } from '@/constants';
import { useI18n } from '@/composables/useI18n'; import { useI18n } from '@/composables/useI18n';
import { useProjectsStore } from '@/stores/projects.store'; import { useProjectsStore } from '@/stores/projects.store';
import { getResourcePermissions } from '@/permissions'; import { getResourcePermissions } from '@/permissions';
import { ProjectTypes } from '@/types/projects.types';
const locale = useI18n(); const locale = useI18n();
const route = useRoute(); const route = useRoute();
@@ -50,7 +51,11 @@ const options = computed(() => {
}, },
]; ];
if (projectId && projectPermissions.value.update) { if (
projectId &&
projectPermissions.value.update &&
projectsStore.currentProject?.type === ProjectTypes.Team
) {
tabs.push({ tabs.push({
label: locale.baseText('projects.settings'), label: locale.baseText('projects.settings'),
value: VIEWS.PROJECT_SETTINGS, value: VIEWS.PROJECT_SETTINGS,