Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(editor): Allow resources to move between personal and team projects #10683

Merged
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
952962c
fix(editor): Allow resources to move between personal and team projects
cstuncsik Sep 5, 2024
2e60301
fix(editor): Remove resource moving confirmation modal
cstuncsik Sep 5, 2024
b710d8e
fix(editor): Remove resource moving confirmation modal
cstuncsik Sep 5, 2024
b511b24
fix(editor): Update move resource success toast message
cstuncsik Sep 5, 2024
0fbb4cd
fix(editor): Type error and unit test
cstuncsik Sep 5, 2024
cf21509
fix(editor): Update resource moving E2E test
cstuncsik Sep 9, 2024
c5e73a0
allow transferring workflows from any project type to any other proje…
despairblue Sep 9, 2024
fdfc2a4
clean up the tests
despairblue Sep 9, 2024
a2023cb
allow transferring credentials from any project type to any other pro…
despairblue Sep 9, 2024
253eaa9
fix(editor): Remove View project link from toast when the target proj…
cstuncsik Sep 10, 2024
2619298
test(editor): Extend resource moving E2E tests
cstuncsik Sep 10, 2024
a2a8c3b
test(editor): Add resource moving component tests
cstuncsik Sep 10, 2024
b292ba2
fix(editor): Use the correct list of projects
cstuncsik Sep 12, 2024
0a01f3f
fix(editor): Fix unit test and lint issue
cstuncsik Sep 12, 2024
8efdad5
fix(editor): Fix sharing
cstuncsik Sep 13, 2024
a95908a
fix(editor): Fix linting
cstuncsik Sep 13, 2024
84a00d2
fix(editor): Fix workflow sharing
cstuncsik Sep 13, 2024
8a8fdd7
fix(editor): Fix workflow filtering
cstuncsik Sep 13, 2024
f26febd
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 16, 2024
2b2bc62
fix(editor): Fix project display name
cstuncsik Sep 17, 2024
e87013a
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 17, 2024
36a4b72
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 17, 2024
3fab9fd
fix(editor): Truncating long project names
cstuncsik Sep 17, 2024
e5232e0
fix(editor): Truncating long node name
cstuncsik Sep 17, 2024
07c3ddf
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 18, 2024
2f35e46
fix(editor): Update unit test
cstuncsik Sep 18, 2024
81427f4
fix(editor): Add no available projects state to move modal
cstuncsik Sep 18, 2024
677d1ae
fix(editor): Truncate project name in cards
cstuncsik Sep 18, 2024
8901a7c
fix(editor): Fix unit test
cstuncsik Sep 18, 2024
e2fc7d3
fix(editor): Add select placeholder
cstuncsik Sep 18, 2024
44e05c9
fix(editor): Increase toast timeout
cstuncsik Sep 18, 2024
e6c01ff
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 23, 2024
02120c0
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 24, 2024
c02411d
fix(editor): Allow changing foreign credential in a node if the workf…
cstuncsik Sep 24, 2024
89afde3
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 25, 2024
77c4ea7
Merge remote-tracking branch 'origin/master' into pay-1847-allow-user…
cstuncsik Sep 26, 2024
e2ccc77
test(editor): Add e2e test to check if team project member can change…
cstuncsik Sep 26, 2024
85d89a3
test(editor): Enable all tests
cstuncsik Sep 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions cypress/composables/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ export const addProjectMember = (email: string, role?: string) => {
}
};
export const getResourceMoveModal = () => cy.getByTestId('project-move-resource-modal');
export const getResourceMoveConfirmModal = () =>
cy.getByTestId('project-move-resource-confirm-modal');
export const getProjectMoveSelect = () => cy.getByTestId('project-move-resource-modal-select');

export function createProject(name: string) {
Expand Down
191 changes: 139 additions & 52 deletions cypress/e2e/39-projects.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import * as projects from '../composables/projects';
import { INSTANCE_MEMBERS, MANUAL_TRIGGER_NODE_NAME, NOTION_NODE_NAME } from '../constants';
import {
INSTANCE_ADMIN,
INSTANCE_MEMBERS,
INSTANCE_OWNER,
MANUAL_TRIGGER_NODE_NAME,
NOTION_NODE_NAME,
} from '../constants';
import {
WorkflowsPage,
WorkflowPage,
Expand Down Expand Up @@ -481,54 +487,93 @@ describe('Projects', { disableAutoLogin: true }, () => {
projects
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Next")')
.find('button:contains("Move workflow")')
.should('be.disabled');
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 2)
.first()
.should('contain.text', 'Project 1')
.should('have.length', 5)
.filter(':contains("Project 1")')
.click();
projects.getResourceMoveModal().find('button:contains("Next")').click();
projects.getResourceMoveModal().find('button:contains("Move workflow")').click();

workflowsPage.getters
.workflowCards()
.should('have.length', 3)
.filter(':contains("Owned by me")')
.should('not.exist');

// Move the workflow from Project 1 to Project 2
projects.getMenuItems().first().click();
workflowsPage.getters.workflowCards().should('have.length', 2);
workflowsPage.getters.workflowCardActions('Workflow in Home project').click();
workflowsPage.getters.workflowMoveButton().click();

projects
.getResourceMoveConfirmModal()
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Confirm")')
.find('button:contains("Move workflow")')
.should('be.disabled');

projects
.getResourceMoveConfirmModal()
.find('input[type="checkbox"]')
.first()
.parents('label')
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 5)
.filter(':contains("Project 2")')
.click();
projects.getResourceMoveModal().find('button:contains("Move workflow")').click();

// Move the workflow from Project 2 to a member user
projects.getMenuItems().last().click();
workflowsPage.getters.workflowCards().should('have.length', 2);
workflowsPage.getters.workflowCardActions('Workflow in Home project').click();
workflowsPage.getters.workflowMoveButton().click();

projects
.getResourceMoveConfirmModal()
.find('button:contains("Confirm")')
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Move workflow")')
.should('be.disabled');
projects
.getResourceMoveConfirmModal()
.find('input[type="checkbox"]')
.last()
.parents('label')
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 5)
.filter(`:contains("${INSTANCE_MEMBERS[0].email}")`)
.click();

projects.getResourceMoveModal().find('button:contains("Move workflow")').click();
workflowsPage.getters.workflowCards().should('have.length', 1);

// Move the workflow from member user back to Home
projects.getHomeButton().click();
workflowsPage.getters
.workflowCards()
.should('have.length', 3)
.filter(':has(.n8n-badge:contains("Project"))')
.should('have.length', 2);
workflowsPage.getters.workflowCardActions('Workflow in Home project').click();
workflowsPage.getters.workflowMoveButton().click();

projects
.getResourceMoveConfirmModal()
.find('button:contains("Confirm")')
.should('not.be.disabled')
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Move workflow")')
.should('be.disabled');
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 5)
.filter(`:contains("${INSTANCE_OWNER.email}")`)
.click();

projects.getResourceMoveModal().find('button:contains("Move workflow")').click();
workflowsPage.getters
.workflowCards()
.should('have.length', 3)
.filter(':contains("Owned by me")')
.should('not.exist');
.should('have.length', 1);

// Move the credential from Project 1 to Project 2
projects.getMenuItems().first().click();
workflowsPage.getters.workflowCards().should('have.length', 2);
projects.getProjectTabCredentials().click();
credentialsPage.getters.credentialCards().should('have.length', 1);
credentialsPage.getters.credentialCardActions('Credential in Project 1').click();
Expand All @@ -537,48 +582,90 @@ describe('Projects', { disableAutoLogin: true }, () => {
projects
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Next")')
.find('button:contains("Move credential")')
.should('be.disabled');
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 1)
.first()
.should('contain.text', 'Project 2')
.should('have.length', 5)
.filter(':contains("Project 2")')
.click();
projects.getResourceMoveModal().find('button:contains("Next")').click();
projects.getResourceMoveModal().find('button:contains("Move credential")').click();

credentialsPage.getters.credentialCards().should('not.have.length');

// Move the credential from Project 2 to admin user
projects.getMenuItems().last().click();
projects.getProjectTabCredentials().click();
credentialsPage.getters.credentialCards().should('have.length', 2);

credentialsPage.getters.credentialCardActions('Credential in Project 1').click();
credentialsPage.getters.credentialMoveButton().click();

projects
.getResourceMoveConfirmModal()
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Confirm")')
.find('button:contains("Move credential")')
.should('be.disabled');

projects
.getResourceMoveConfirmModal()
.find('input[type="checkbox"]')
.first()
.parents('label')
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 5)
.filter(`:contains("${INSTANCE_ADMIN.email}")`)
.click();
projects.getResourceMoveModal().find('button:contains("Move credential")').click();
credentialsPage.getters.credentialCards().should('have.length', 1);

// Move the credential from admin user back to instance owner
projects.getHomeButton().click();
projects.getProjectTabCredentials().click();
credentialsPage.getters.credentialCards().should('have.length', 3);

credentialsPage.getters.credentialCardActions('Credential in Project 1').click();
credentialsPage.getters.credentialMoveButton().click();

projects
.getResourceMoveConfirmModal()
.find('button:contains("Confirm")')
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Move credential")')
.should('be.disabled');
projects
.getResourceMoveConfirmModal()
.find('input[type="checkbox"]')
.last()
.parents('label')
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 5)
.filter(`:contains("${INSTANCE_OWNER.email}")`)
.click();
projects.getResourceMoveModal().find('button:contains("Move credential")').click();

credentialsPage.getters
.credentialCards()
.should('have.length', 3)
.filter(':contains("Owned by me")')
.should('have.length', 2);

// Move the credential from admin user back to its original project (Project 1)
credentialsPage.getters.credentialCardActions('Credential in Project 1').click();
credentialsPage.getters.credentialMoveButton().click();

projects
.getResourceMoveConfirmModal()
.find('button:contains("Confirm")')
.should('not.be.disabled')
.getResourceMoveModal()
.should('be.visible')
.find('button:contains("Move credential")')
.should('be.disabled');
projects.getProjectMoveSelect().click();
getVisibleSelect()
.find('li')
.should('have.length', 5)
.filter(':contains("Project 1")')
.click();
credentialsPage.getters.credentialCards().should('not.have.length');
projects.getMenuItems().last().click();
projects.getResourceMoveModal().find('button:contains("Move credential")').click();

projects.getMenuItems().first().click();
projects.getProjectTabCredentials().click();
credentialsPage.getters.credentialCards().should('have.length', 2);
credentialsPage.getters
.credentialCards()
.filter(':contains("Credential in Project 1")')
.should('have.length', 1);
});

it('should handle viewer role', () => {
Expand Down
8 changes: 0 additions & 8 deletions packages/cli/src/credentials/credentials.service.ee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,6 @@ export class EnterpriseCredentialsService {
"You can't transfer a credential into the project that's already owning it.",
);
}
if (sourceProject.type !== 'team' && sourceProject.type !== 'personal') {
throw new TransferCredentialError(
'You can only transfer credentials out of personal or team projects.',
);
}
if (destinationProject.type !== 'team') {
throw new TransferCredentialError('You can only transfer credentials into team projects.');
}

await this.sharedCredentialsRepository.manager.transaction(async (trx) => {
// 6. transfer the credential
Expand Down
8 changes: 0 additions & 8 deletions packages/cli/src/workflows/workflow.service.ee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,6 @@ export class EnterpriseWorkflowService {
"You can't transfer a workflow into the project that's already owning it.",
);
}
if (sourceProject.type !== 'team' && sourceProject.type !== 'personal') {
throw new TransferWorkflowError(
'You can only transfer workflows out of personal or team projects.',
);
}
if (destinationProject.type !== 'team') {
throw new TransferWorkflowError('You can only transfer workflows into team projects.');
}

// 6. deactivate workflow if necessary
const wasActive = workflow.active;
Expand Down
Loading