Skip to content

Commit

Permalink
fix(editor): Project related frontend fixes (no-changelog) (#9482)
Browse files Browse the repository at this point in the history
  • Loading branch information
cstuncsik authored May 22, 2024
1 parent 62ee796 commit 8f55bb1
Show file tree
Hide file tree
Showing 16 changed files with 170 additions and 41 deletions.
75 changes: 73 additions & 2 deletions cypress/e2e/39-projects.cy.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import { INSTANCE_ADMIN, INSTANCE_MEMBERS } from '../constants';
import { WorkflowsPage, WorkflowPage, CredentialsModal, CredentialsPage } from '../pages';
import {
WorkflowsPage,
WorkflowPage,
CredentialsModal,
CredentialsPage,
WorkflowExecutionsTab,
} from '../pages';
import * as projects from '../composables/projects';

const workflowsPage = new WorkflowsPage();
const workflowPage = new WorkflowPage();
const credentialsPage = new CredentialsPage();
const credentialsModal = new CredentialsModal();
const executionsTab = new WorkflowExecutionsTab();

describe('Projects', () => {
beforeEach(() => {
cy.resetDatabase();
cy.enableFeature('sharing');
cy.enableFeature('advancedPermissions');
cy.enableFeature('projectRole:admin');
cy.enableFeature('projectRole:editor');
cy.changeQuota('maxTeamProjects', -1);
});

it('should handle workflows and credentials', () => {
it('should handle workflows and credentials and menu items', () => {
cy.signin(INSTANCE_ADMIN);
cy.visit(workflowsPage.url);
workflowsPage.getters.workflowCards().should('not.have.length');
Expand Down Expand Up @@ -147,5 +155,68 @@ describe('Projects', () => {
cy.wait('@credentialsList').then((interception) => {
expect(interception.request.url).not.to.contain('filter');
});

let menuItems = cy.getByTestId('menu-item');

menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Home")[class*=active_]').should('exist');

projects.getMenuItems().first().click();

menuItems = cy.getByTestId('menu-item');

menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Development")[class*=active_]').should('exist');

cy.intercept('GET', '/rest/workflows/*').as('loadWorkflow');
workflowsPage.getters.workflowCards().first().click();

cy.wait('@loadWorkflow');
menuItems = cy.getByTestId('menu-item');

menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Development")[class*=active_]').should('exist');

cy.intercept('GET', '/rest/executions*').as('loadExecutions');
executionsTab.actions.switchToExecutionsTab();

cy.wait('@loadExecutions');
menuItems = cy.getByTestId('menu-item');

menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Development")[class*=active_]').should('exist');

executionsTab.actions.switchToEditorTab();

menuItems = cy.getByTestId('menu-item');

menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Development")[class*=active_]').should('exist');

cy.getByTestId('menu-item').filter(':contains("Variables")').click();
cy.getByTestId('unavailable-resources-list').should('be.visible');

menuItems = cy.getByTestId('menu-item');

menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Variables")[class*=active_]').should('exist');

projects.getHomeButton().click();
menuItems = cy.getByTestId('menu-item');

menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Home")[class*=active_]').should('exist');

workflowsPage.getters.workflowCards().should('have.length', 2).first().click();

cy.wait('@loadWorkflow');
cy.getByTestId('execute-workflow-button').should('be.visible');

menuItems = cy.getByTestId('menu-item');
menuItems.filter(':contains("Home")[class*=active_]').should('not.exist');

menuItems = cy.getByTestId('menu-item');
menuItems.filter('[class*=active_]').should('have.length', 1);
menuItems.filter(':contains("Development")[class*=active_]').should('exist');
});
});
5 changes: 4 additions & 1 deletion packages/editor-ui/src/__tests__/data/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import type {
ProjectSharingData,
ProjectType,
} from '@/features/projects/projects.types';
import { ProjectTypes } from '@/features/projects/projects.utils';

export const createProjectSharingData = (projectType?: ProjectType): ProjectSharingData => ({
id: faker.string.uuid(),
name: faker.lorem.words({ min: 1, max: 3 }),
type: projectType || 'personal',
type: projectType ?? ProjectTypes.Personal,
createdAt: faker.date.past().toISOString(),
updatedAt: faker.date.recent().toISOString(),
});

export const createProjectListItem = (projectType?: ProjectType): ProjectListItem => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ import type { CredentialScope } from '@n8n/permissions';
import type { EventBus } from 'n8n-design-system/utils';
import { useRolesStore } from '@/stores/roles.store';
import type { RoleMap } from '@/types/roles.types';
import { ProjectTypes } from '@/features/projects/projects.utils';

export default defineComponent({
name: 'CredentialSharing',
Expand Down Expand Up @@ -178,7 +179,7 @@ export default defineComponent({
);
},
isHomeTeamProject(): boolean {
return this.homeProject?.type === 'team';
return this.homeProject?.type === ProjectTypes.Team;
},
numberOfMembersInHomeTeamProject(): number {
return this.teamProject?.relations.length ?? 0;
Expand Down
3 changes: 2 additions & 1 deletion packages/editor-ui/src/components/WorkflowSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ import type { WorkflowScope } from '@n8n/permissions';
import { getWorkflowPermissions } from '@/permissions';
import { useExternalHooks } from '@/composables/useExternalHooks';
import { useSourceControlStore } from '@/stores/sourceControl.store';
import { ProjectTypes } from '@/features/projects/projects.utils';
export default defineComponent({
name: 'WorkflowSettings',
Expand Down Expand Up @@ -604,7 +605,7 @@ export default defineComponent({
{
key: 'workflowsFromSameOwner',
value: this.$locale.baseText(
this.workflow.homeProject?.type === 'personal'
this.workflow.homeProject?.type === ProjectTypes.Personal
? 'workflowSettings.callerPolicy.options.workflowsFromPersonalProject'
: 'workflowSettings.callerPolicy.options.workflowsFromTeamProject',
{
Expand Down
3 changes: 2 additions & 1 deletion packages/editor-ui/src/components/WorkflowShareModal.ee.vue
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ import type {
} from '@/features/projects/projects.types';
import { useRolesStore } from '@/stores/roles.store';
import type { RoleMap } from '@/types/roles.types';
import { ProjectTypes } from '@/features/projects/projects.utils';

export default defineComponent({
name: 'WorkflowShareModal',
Expand Down Expand Up @@ -238,7 +239,7 @@ export default defineComponent({
);
},
isHomeTeamProject(): boolean {
return this.workflow.homeProject?.type === 'team';
return this.workflow.homeProject?.type === ProjectTypes.Team;
},
numberOfMembersInHomeTeamProject(): number {
return this.teamProject?.relations.length ?? 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
class="pt-2xs"
:projects="projectsStore.projects"
:placeholder="$locale.baseText('forms.resourceFiltersDropdown.owner.placeholder')"
:empty-options-text="$locale.baseText('projects.sharing.noMatchingProjects')"
@update:model-value="setKeyValue('homeProject', ($event as ProjectSharingData).id)"
/>
</enterprise-edition>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { useI18n } from '@/composables/useI18n';
import { splitName } from '@/features/projects/projects.utils';
import { ProjectTypes, splitName } from '@/features/projects/projects.utils';
import type { ICredentialsResponse, IWorkflowDb } from '@/Interface';
import type { Project } from '@/features/projects/projects.types';
Expand Down Expand Up @@ -29,9 +29,12 @@ const badgeText = computed(() => {
});
const badgeIcon = computed(() => {
if (props.resource.sharedWithProjects?.length && props.resource.homeProject?.type !== 'team') {
if (
props.resource.sharedWithProjects?.length &&
props.resource.homeProject?.type !== ProjectTypes.Team
) {
return 'user-friends';
} else if (props.resource.homeProject?.type === 'team') {
} else if (props.resource.homeProject?.type === ProjectTypes.Team) {
return 'archive';
} else {
return '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ const onDelete = () => {
<n8n-text color="text-dark">{{
locale.baseText('projects.settings.delete.question.transfer.title')
}}</n8n-text>
<ProjectSharing v-model="selectedProject" class="pt-2xs" :projects="props.projects" />
<ProjectSharing
v-model="selectedProject"
class="pt-2xs"
:projects="props.projects"
:empty-options-text="locale.baseText('projects.sharing.noMatchingProjects')"
/>
</div>
<el-radio
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts" setup>
import { ref, computed, onMounted, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useRouter } from 'vue-router';
import type { IMenuItem } from 'n8n-design-system/types';
import { useI18n } from '@/composables/useI18n';
import { VIEWS } from '@/constants';
Expand All @@ -16,7 +16,6 @@ type Props = {
const props = defineProps<Props>();
const route = useRoute();
const router = useRouter();
const locale = useI18n();
const toast = useToast();
Expand All @@ -42,24 +41,6 @@ const addProject = computed<IMenuItem>(() => ({
isLoading: isCreatingProject.value,
}));
const activeTab = computed(() => {
let routes = [VIEWS.HOMEPAGE, VIEWS.WORKFLOWS, VIEWS.CREDENTIALS];
if (projectsStore.currentProjectId === undefined) {
routes = [
...routes,
VIEWS.NEW_WORKFLOW,
VIEWS.WORKFLOW_HISTORY,
VIEWS.WORKFLOW,
VIEWS.EXECUTION_HOME,
];
}
return routes.includes(route.name as VIEWS) ? 'home' : undefined;
});
const isActiveProject = (projectId: string) =>
route?.params?.projectId === projectId || projectsStore.currentProjectId === projectId
? projectId
: undefined;
const getProjectMenuItem = (project: ProjectListItem) => ({
id: project.id,
label: project.name,
Expand Down Expand Up @@ -127,7 +108,7 @@ onMounted(async () => {
:item="home"
:compact="props.collapsed"
:handle-select="homeClicked"
:active-tab="activeTab"
:active-tab="projectsStore.projectNavActiveId"
mode="tabs"
data-test-id="project-home-menu-item"
/>
Expand All @@ -146,7 +127,7 @@ onMounted(async () => {
:item="getProjectMenuItem(project)"
:compact="props.collapsed"
:handle-select="projectClicked"
:active-tab="isActiveProject(project.id)"
:active-tab="projectsStore.projectNavActiveId"
mode="tabs"
data-test-id="project-menu-item"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Props = {
readonly?: boolean;
static?: boolean;
placeholder?: string;
emptyOptionsText?: string;
};
const props = defineProps<Props>();
Expand All @@ -34,6 +35,9 @@ const selectPlaceholder = computed(
? locale.baseText('projects.sharing.placeholder')
: locale.baseText('projects.sharing.placeholder.single')),
);
const noDataText = computed(
() => props.emptyOptionsText ?? locale.baseText('projects.sharing.noMatchingUsers'),
);
const filteredProjects = computed(() =>
props.projects
.filter(
Expand Down Expand Up @@ -101,7 +105,7 @@ watch(
:filter-method="setFilter"
:placeholder="selectPlaceholder"
:default-first-option="true"
:no-data-text="locale.baseText('projects.sharing.noMatchingProjects')"
:no-data-text="noDataText"
size="large"
:disabled="props.readonly"
@update:model-value="onProjectSelected"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const processedName = computed(() => splitName(props.project.name ?? ''));
<div :class="$style.projectInfo" data-test-id="project-sharing-info">
<div>
<N8nAvatar :first-name="processedName.firstName" :last-name="processedName.lastName" />
<div class="flex flex-col">
<div :class="$style.text">
<p v-if="processedName.firstName || processedName.lastName">
{{ processedName.firstName }} {{ processedName.lastName }}
</p>
Expand Down Expand Up @@ -54,4 +54,9 @@ const processedName = computed(() => splitName(props.project.name ?? ''));
line-height: var(--font-line-height-loose);
}
}
.text {
display: flex;
flex-direction: column;
}
</style>
Loading

0 comments on commit 8f55bb1

Please sign in to comment.