feat(editor): Update ownership pills (#11155)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions

This commit is contained in:
Raúl Gómez Morales 2024-10-28 08:48:51 +01:00 committed by GitHub
parent 351134f786
commit 8147038cf8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 110 additions and 43 deletions

View file

@ -259,7 +259,7 @@ describe('Sharing', { disableAutoLogin: true }, () => {
credentialsPage.getters
.credentialCards()
.should('have.length', 2)
.filter(':contains("Owned by me")')
.filter(':contains("Personal")')
.should('have.length', 1);
});
});

View file

@ -15,12 +15,8 @@ import {
NDV,
MainSidebar,
} from '../pages';
import {
getVisibleDropdown,
getVisibleModalOverlay,
getVisibleSelect,
getVisiblePopper,
} from '../utils';
import { clearNotifications } from '../pages/notifications';
import { getVisibleDropdown, getVisibleModalOverlay, getVisibleSelect } from '../utils';
const workflowsPage = new WorkflowsPage();
const workflowPage = new WorkflowPage();
@ -453,38 +449,48 @@ describe('Projects', { disableAutoLogin: true }, () => {
workflowsPage.getters.workflowCards().should('not.have.length');
workflowsPage.getters.newWorkflowButtonCard().click();
projects.createWorkflow('Test_workflow_1.json', 'Workflow in Home project');
clearNotifications();
projects.getHomeButton().click();
projects.getProjectTabCredentials().should('be.visible').click();
credentialsPage.getters.emptyListCreateCredentialButton().click();
projects.createCredential('Credential in Home project');
clearNotifications();
// Create a project and add a credential and a workflow to it
projects.createProject('Project 1');
clearNotifications();
projects.getProjectTabCredentials().click();
credentialsPage.getters.emptyListCreateCredentialButton().click();
projects.createCredential('Credential in Project 1');
clearNotifications();
projects.getProjectTabWorkflows().click();
workflowsPage.getters.newWorkflowButtonCard().click();
projects.createWorkflow('Test_workflow_1.json', 'Workflow in Project 1');
clearNotifications();
// Create another project and add a credential and a workflow to it
projects.createProject('Project 2');
clearNotifications();
projects.getProjectTabCredentials().click();
credentialsPage.getters.emptyListCreateCredentialButton().click();
projects.createCredential('Credential in Project 2');
clearNotifications();
projects.getProjectTabWorkflows().click();
workflowsPage.getters.newWorkflowButtonCard().click();
projects.createWorkflow('Test_workflow_1.json', 'Workflow in Project 2');
clearNotifications();
// Move the workflow owned by me from Home to Project 1
// Move the workflow Personal from Home to Project 1
projects.getHomeButton().click();
workflowsPage.getters
.workflowCards()
.should('have.length', 3)
.filter(':contains("Owned by me")')
.filter(':contains("Personal")')
.should('exist');
workflowsPage.getters.workflowCardActions('Workflow in Home project').click();
workflowsPage.getters.workflowMoveButton().click();
@ -501,11 +507,12 @@ describe('Projects', { disableAutoLogin: true }, () => {
.filter(':contains("Project 1")')
.click();
projects.getResourceMoveModal().find('button:contains("Move workflow")').click();
clearNotifications();
workflowsPage.getters
.workflowCards()
.should('have.length', 3)
.filter(':contains("Owned by me")')
.filter(':contains("Personal")')
.should('not.exist');
// Move the workflow from Project 1 to Project 2
@ -532,6 +539,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
workflowsPage.getters.workflowCards().should('have.length', 2);
workflowsPage.getters.workflowCardActions('Workflow in Home project').click();
workflowsPage.getters.workflowMoveButton().click();
clearNotifications();
projects
.getResourceMoveModal()
@ -571,10 +579,11 @@ describe('Projects', { disableAutoLogin: true }, () => {
.click();
projects.getResourceMoveModal().find('button:contains("Move workflow")').click();
clearNotifications();
workflowsPage.getters
.workflowCards()
.should('have.length', 3)
.filter(':contains("Owned by me")')
.filter(':contains("Personal")')
.should('have.length', 1);
// Move the credential from Project 1 to Project 2
@ -584,9 +593,6 @@ describe('Projects', { disableAutoLogin: true }, () => {
credentialsPage.getters.credentialCardActions('Credential in Project 1').click();
credentialsPage.getters.credentialMoveButton().click();
// wait for all poppers to be gone
getVisiblePopper().should('have.length', 0);
projects
.getResourceMoveModal()
.should('be.visible')
@ -599,7 +605,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
.filter(':contains("Project 2")')
.click();
projects.getResourceMoveModal().find('button:contains("Move credential")').click();
clearNotifications();
credentialsPage.getters.credentialCards().should('not.have.length');
// Move the credential from Project 2 to admin user
@ -610,9 +616,6 @@ describe('Projects', { disableAutoLogin: true }, () => {
credentialsPage.getters.credentialCardActions('Credential in Project 1').click();
credentialsPage.getters.credentialMoveButton().click();
// wait for all poppers to be gone
getVisiblePopper().should('have.length', 0);
projects
.getResourceMoveModal()
.should('be.visible')
@ -635,9 +638,6 @@ describe('Projects', { disableAutoLogin: true }, () => {
credentialsPage.getters.credentialCardActions('Credential in Project 1').click();
credentialsPage.getters.credentialMoveButton().click();
// wait for all poppers to be gone
getVisiblePopper().should('have.length', 0);
projects
.getResourceMoveModal()
.should('be.visible')
@ -651,13 +651,12 @@ describe('Projects', { disableAutoLogin: true }, () => {
.click();
projects.getResourceMoveModal().find('button:contains("Move credential")').click();
// wait for all poppers to be gone
getVisiblePopper().should('have.length', 0);
clearNotifications();
credentialsPage.getters
.credentialCards()
.should('have.length', 3)
.filter(':contains("Owned by me")')
.filter(':contains("Personal")')
.should('have.length', 2);
// Move the credential from admin user back to its original project (Project 1)
@ -716,7 +715,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
workflowsPage.getters
.workflowCards()
.should('have.length', 1)
.filter(':contains("Owned by me")')
.filter(':contains("Personal")')
.should('exist');
workflowsPage.getters.workflowCardActions('My workflow').click();
workflowsPage.getters.workflowMoveButton().click();
@ -737,7 +736,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
workflowsPage.getters
.workflowCards()
.should('have.length', 1)
.filter(':contains("Owned by me")')
.filter(':contains("Personal")')
.should('not.exist');
//Log out with instance owner and log in with the member user

View file

@ -5,7 +5,7 @@ import { truncate } from 'n8n-design-system';
const renderComponent = createComponentRenderer(ProjectCardBadge);
describe('ProjectCardBadge', () => {
it('should show "Owned by me" badge if there is no homeProject', () => {
it('should show "Personal" badge if there is no homeProject', () => {
const { getByText } = renderComponent({
props: {
resource: {},
@ -13,15 +13,16 @@ describe('ProjectCardBadge', () => {
},
});
expect(getByText('Owned by me')).toBeVisible();
expect(getByText('Personal')).toBeVisible();
});
it('should show "Owned by me" badge if homeProject ID equals personalProject ID', () => {
it('should show "Personal" badge if homeProject ID equals personalProject ID', () => {
const { getByText } = renderComponent({
props: {
resource: {
homeProject: {
id: '1',
name: 'John',
},
},
resourceType: 'workflow',
@ -31,7 +32,27 @@ describe('ProjectCardBadge', () => {
},
});
expect(getByText('Owned by me')).toBeVisible();
expect(getByText('Personal')).toBeVisible();
});
it('should show shared with count', () => {
const { getByText } = renderComponent({
props: {
resource: {
sharedWithProjects: [{}, {}, {}],
homeProject: {
id: '1',
name: 'John',
},
},
resourceType: 'workflow',
personalProject: {
id: '1',
},
},
});
expect(getByText('+ 3')).toBeVisible();
});
test.each([

View file

@ -52,12 +52,17 @@ const projectState = computed(() => {
}
return ProjectState.Unknown;
});
const numberOfMembersInHomeTeamProject = computed(
() => props.resource.sharedWithProjects?.length ?? 0,
);
const badgeText = computed(() => {
if (
projectState.value === ProjectState.Owned ||
projectState.value === ProjectState.SharedOwned
) {
return i18n.baseText('generic.ownedByMe');
return i18n.baseText('projects.menu.personal');
} else {
const { name, email } = splitName(props.resource.homeProject?.name ?? '');
return name ?? email ?? '';
@ -65,12 +70,12 @@ const badgeText = computed(() => {
});
const badgeIcon = computed(() => {
switch (projectState.value) {
case ProjectState.SharedPersonal:
case ProjectState.Owned:
case ProjectState.SharedOwned:
return 'user-friends';
return 'user';
case ProjectState.Team:
case ProjectState.SharedTeam:
return 'archive';
return 'layer-group';
default:
return '';
}
@ -81,6 +86,7 @@ const badgeTooltip = computed(() => {
return i18n.baseText('projects.badge.tooltip.sharedOwned', {
interpolate: {
resourceTypeLabel: props.resourceTypeLabel,
count: numberOfMembersInHomeTeamProject.value,
},
});
case ProjectState.SharedPersonal:
@ -88,6 +94,7 @@ const badgeTooltip = computed(() => {
interpolate: {
resourceTypeLabel: props.resourceTypeLabel,
name: badgeText.value,
count: numberOfMembersInHomeTeamProject.value,
},
});
case ProjectState.Personal:
@ -109,6 +116,7 @@ const badgeTooltip = computed(() => {
interpolate: {
resourceTypeLabel: props.resourceTypeLabel,
name: badgeText.value,
count: numberOfMembersInHomeTeamProject.value,
},
});
default:
@ -118,14 +126,53 @@ const badgeTooltip = computed(() => {
</script>
<template>
<N8nTooltip :disabled="!badgeTooltip" placement="top">
<N8nBadge v-if="badgeText" class="mr-xs" theme="tertiary" bold data-test-id="card-badge">
<span v-n8n-truncate:20>{{ badgeText }}</span>
<N8nIcon v-if="badgeIcon" :icon="badgeIcon" size="small" class="ml-5xs" />
</N8nBadge>
<div class="mr-xs">
<N8nBadge
v-if="badgeText"
:class="$style.badge"
theme="tertiary"
bold
data-test-id="card-badge"
>
<N8nIcon v-if="badgeIcon" :icon="badgeIcon" size="small" class="mr-3xs" />
<span v-n8n-truncate:20>{{ badgeText }}</span>
</N8nBadge>
<N8nBadge
v-if="numberOfMembersInHomeTeamProject"
:class="[$style.badge, $style.countBadge]"
theme="tertiary"
bold
>
+ {{ numberOfMembersInHomeTeamProject }}
</N8nBadge>
</div>
<template #content>
{{ badgeTooltip }}
</template>
</N8nTooltip>
</template>
<style lang="scss" module></style>
<style lang="scss" module>
.badge {
padding: var(--spacing-4xs) var(--spacing-2xs);
background-color: var(--color-background-xlight);
border-color: var(--color-foreground-base);
z-index: 1;
position: relative;
height: 23px;
:global(.n8n-text) {
color: var(--color-text-base);
}
}
.countBadge {
margin-left: -5px;
z-index: 0;
position: relative;
height: 23px;
:global(.n8n-text) {
color: var(--color-text-light);
}
}
</style>

View file

@ -71,7 +71,7 @@
"generic.seePlans": "See plans",
"generic.loading": "Loading",
"generic.and": "and",
"generic.ownedByMe": "Owned by me",
"generic.ownedByMe": "(You)",
"generic.moreInfo": "More info",
"generic.next": "Next",
"about.aboutN8n": "About n8n",
@ -2543,11 +2543,11 @@
"projects.move.resource.success.message": "{resourceName} {resourceTypeLabel} was moved to {targetProjectName}. {workflow} {link}",
"projects.move.resource.success.message.workflow": "Please double check any credentials this workflow is using are also shared with {targetProjectName}.",
"projects.move.resource.success.link": "View {targetProjectName}",
"projects.badge.tooltip.sharedOwned": "This {resourceTypeLabel} is owned by you and shared with one or more projects or users",
"projects.badge.tooltip.sharedPersonal": "This {resourceTypeLabel} is owned by {name} and shared with one or more projects or users",
"projects.badge.tooltip.sharedOwned": "This {resourceTypeLabel} is owned by you and shared with {count} users",
"projects.badge.tooltip.sharedPersonal": "This {resourceTypeLabel} is owned by {name} and shared with {count} users",
"projects.badge.tooltip.personal": "This {resourceTypeLabel} is owned by {name}",
"projects.badge.tooltip.team": "This {resourceTypeLabel} is owned and accessible by the {name} project.",
"projects.badge.tooltip.sharedTeam": "This {resourceTypeLabel} is owned and accessible by the {name} project and shared with one or more projects or users",
"projects.badge.tooltip.sharedTeam": "This {resourceTypeLabel} is owned by the {name} project and accessible by {count} users",
"mfa.setup.invalidAuthenticatorCode": "{code} is not a valid number",
"mfa.setup.invalidCode": "Two-factor code failed. Please try again.",
"mfa.code.modal.title": "Two-factor authentication",