mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 20:54:07 -08:00
fix(editor): Filter credentials by project ID also for new workflow (#9615)
This commit is contained in:
parent
e7f616290f
commit
c92765dcdb
|
@ -1,18 +1,21 @@
|
||||||
import { INSTANCE_ADMIN, INSTANCE_MEMBERS } from '../constants';
|
import { INSTANCE_ADMIN, INSTANCE_MEMBERS, INSTANCE_OWNER, MANUAL_TRIGGER_NODE_NAME, NOTION_NODE_NAME } from '../constants';
|
||||||
import {
|
import {
|
||||||
WorkflowsPage,
|
WorkflowsPage,
|
||||||
WorkflowPage,
|
WorkflowPage,
|
||||||
CredentialsModal,
|
CredentialsModal,
|
||||||
CredentialsPage,
|
CredentialsPage,
|
||||||
WorkflowExecutionsTab,
|
WorkflowExecutionsTab,
|
||||||
|
NDV,
|
||||||
} from '../pages';
|
} from '../pages';
|
||||||
import * as projects from '../composables/projects';
|
import * as projects from '../composables/projects';
|
||||||
|
import { getVisibleSelect } from '../utils';
|
||||||
|
|
||||||
const workflowsPage = new WorkflowsPage();
|
const workflowsPage = new WorkflowsPage();
|
||||||
const workflowPage = new WorkflowPage();
|
const workflowPage = new WorkflowPage();
|
||||||
const credentialsPage = new CredentialsPage();
|
const credentialsPage = new CredentialsPage();
|
||||||
const credentialsModal = new CredentialsModal();
|
const credentialsModal = new CredentialsModal();
|
||||||
const executionsTab = new WorkflowExecutionsTab();
|
const executionsTab = new WorkflowExecutionsTab();
|
||||||
|
const ndv = new NDV();
|
||||||
|
|
||||||
describe('Projects', () => {
|
describe('Projects', () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
|
@ -150,9 +153,9 @@ describe('Projects', () => {
|
||||||
projects.getHomeButton().click();
|
projects.getHomeButton().click();
|
||||||
workflowsPage.getters.workflowCards().should('have.length', 2);
|
workflowsPage.getters.workflowCards().should('have.length', 2);
|
||||||
|
|
||||||
cy.intercept('GET', '/rest/credentials*').as('credentialsListFilterless');
|
cy.intercept('GET', '/rest/credentials*').as('credentialsListUnfiltered');
|
||||||
projects.getProjectTabCredentials().click();
|
projects.getProjectTabCredentials().click();
|
||||||
cy.wait('@credentialsListFilterless').then((interception) => {
|
cy.wait('@credentialsListUnfiltered').then((interception) => {
|
||||||
expect(interception.request.url).not.to.contain('filter');
|
expect(interception.request.url).not.to.contain('filter');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -228,4 +231,140 @@ describe('Projects', () => {
|
||||||
projects.getAddProjectButton().should('not.exist');
|
projects.getAddProjectButton().should('not.exist');
|
||||||
projects.getMenuItems().should('not.exist');
|
projects.getMenuItems().should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when starting from scratch', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.resetDatabase();
|
||||||
|
cy.enableFeature('sharing');
|
||||||
|
cy.enableFeature('advancedPermissions');
|
||||||
|
cy.enableFeature('projectRole:admin');
|
||||||
|
cy.enableFeature('projectRole:editor');
|
||||||
|
cy.changeQuota('maxTeamProjects', -1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should filter credentials by project ID when creating new workflow or hard reloading an opened workflow', () => {
|
||||||
|
cy.signin(INSTANCE_OWNER);
|
||||||
|
cy.visit(workflowsPage.url);
|
||||||
|
|
||||||
|
// Create a project and add a credential to it
|
||||||
|
cy.intercept('POST', '/rest/projects').as('projectCreate');
|
||||||
|
projects.getAddProjectButton().should('contain', 'Add project').should('be.visible').click();
|
||||||
|
cy.wait('@projectCreate');
|
||||||
|
projects.getMenuItems().should('have.length', 1);
|
||||||
|
projects.getMenuItems().first().click();
|
||||||
|
projects.getProjectTabCredentials().click();
|
||||||
|
credentialsPage.getters.credentialCards().should('not.have.length');
|
||||||
|
|
||||||
|
credentialsPage.getters.emptyListCreateCredentialButton().click();
|
||||||
|
credentialsModal.getters.newCredentialModal().should('be.visible');
|
||||||
|
credentialsModal.getters.newCredentialTypeSelect().should('be.visible');
|
||||||
|
credentialsModal.getters.newCredentialTypeOption('Notion API').click();
|
||||||
|
credentialsModal.getters.newCredentialTypeButton().click();
|
||||||
|
credentialsModal.getters.connectionParameter('Internal Integration Secret').type('1234567890');
|
||||||
|
credentialsModal.actions.setName('Notion account project 1');
|
||||||
|
|
||||||
|
cy.intercept('POST', '/rest/credentials').as('credentialSave');
|
||||||
|
credentialsModal.actions.save();
|
||||||
|
cy.wait('@credentialSave').then((interception) => {
|
||||||
|
expect(interception.request.body).to.have.property('projectId');
|
||||||
|
});
|
||||||
|
credentialsModal.actions.close();
|
||||||
|
|
||||||
|
// Create another project and add a credential to it
|
||||||
|
projects.getAddProjectButton().click();
|
||||||
|
cy.wait('@projectCreate');
|
||||||
|
projects.getMenuItems().should('have.length', 2);
|
||||||
|
projects.getMenuItems().last().click();
|
||||||
|
projects.getProjectTabCredentials().click();
|
||||||
|
credentialsPage.getters.credentialCards().should('not.have.length');
|
||||||
|
|
||||||
|
credentialsPage.getters.emptyListCreateCredentialButton().click();
|
||||||
|
credentialsModal.getters.newCredentialModal().should('be.visible');
|
||||||
|
credentialsModal.getters.newCredentialTypeSelect().should('be.visible');
|
||||||
|
credentialsModal.getters.newCredentialTypeOption('Notion API').click();
|
||||||
|
credentialsModal.getters.newCredentialTypeButton().click();
|
||||||
|
credentialsModal.getters.connectionParameter('Internal Integration Secret').type('1234567890');
|
||||||
|
credentialsModal.actions.setName('Notion account project 2');
|
||||||
|
|
||||||
|
credentialsModal.actions.save();
|
||||||
|
cy.wait('@credentialSave').then((interception) => {
|
||||||
|
expect(interception.request.body).to.have.property('projectId');
|
||||||
|
});
|
||||||
|
credentialsModal.actions.close();
|
||||||
|
|
||||||
|
// Create a credential in Home project
|
||||||
|
projects.getHomeButton().click();
|
||||||
|
projects.getProjectTabCredentials().click();
|
||||||
|
|
||||||
|
credentialsPage.getters.credentialCards().should('have.length', 2);
|
||||||
|
|
||||||
|
credentialsPage.getters.createCredentialButton().click();
|
||||||
|
credentialsModal.getters.newCredentialModal().should('be.visible');
|
||||||
|
credentialsModal.getters.newCredentialTypeSelect().should('be.visible');
|
||||||
|
credentialsModal.getters.newCredentialTypeOption('Notion API').click();
|
||||||
|
credentialsModal.getters.newCredentialTypeButton().click();
|
||||||
|
credentialsModal.getters.connectionParameter('Internal Integration Secret').type('1234567890');
|
||||||
|
credentialsModal.actions.setName('Notion account personal project');
|
||||||
|
|
||||||
|
cy.intercept('POST', '/rest/credentials').as('credentialSave');
|
||||||
|
credentialsModal.actions.save();
|
||||||
|
cy.wait('@credentialSave')
|
||||||
|
credentialsModal.actions.close();
|
||||||
|
|
||||||
|
// Go to the first project and create a workflow
|
||||||
|
projects.getMenuItems().first().click();
|
||||||
|
workflowsPage.getters.workflowCards().should('not.have.length');
|
||||||
|
workflowsPage.getters.newWorkflowButtonCard().click();
|
||||||
|
workflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
|
||||||
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
||||||
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
|
getVisibleSelect().find('li').should('have.length', 2).first().should('contain.text', 'Notion account project 1');
|
||||||
|
ndv.getters.backToCanvas().click();
|
||||||
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
|
||||||
|
cy.reload();
|
||||||
|
workflowPage.getters.canvasNodeByName(NOTION_NODE_NAME).should('be.visible').dblclick();
|
||||||
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
|
getVisibleSelect().find('li').should('have.length', 2).first().should('contain.text', 'Notion account project 1');
|
||||||
|
ndv.getters.backToCanvas().click();
|
||||||
|
|
||||||
|
// Go to the second project and create a workflow
|
||||||
|
projects.getMenuItems().last().click();
|
||||||
|
workflowsPage.getters.workflowCards().should('not.have.length');
|
||||||
|
workflowsPage.getters.newWorkflowButtonCard().click();
|
||||||
|
workflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
|
||||||
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
||||||
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
|
getVisibleSelect().find('li').should('have.length', 2).first().should('contain.text', 'Notion account project 2');
|
||||||
|
ndv.getters.backToCanvas().click();
|
||||||
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
|
||||||
|
cy.reload();
|
||||||
|
workflowPage.getters.canvasNodeByName(NOTION_NODE_NAME).should('be.visible').dblclick();
|
||||||
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
|
getVisibleSelect().find('li').should('have.length', 2).first().should('contain.text', 'Notion account project 2');
|
||||||
|
ndv.getters.backToCanvas().click();
|
||||||
|
|
||||||
|
// Go to the Home project and create a workflow
|
||||||
|
projects.getHomeButton().click();
|
||||||
|
projects.getProjectTabCredentials().click();
|
||||||
|
credentialsPage.getters.credentialCards().should('have.length', 3);
|
||||||
|
|
||||||
|
projects.getProjectTabWorkflows().click();
|
||||||
|
workflowsPage.getters.workflowCards().should('have.length', 2);
|
||||||
|
workflowsPage.getters.createWorkflowButton().click();
|
||||||
|
workflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME);
|
||||||
|
workflowPage.actions.addNodeToCanvas(NOTION_NODE_NAME, true, true);
|
||||||
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
|
getVisibleSelect().find('li').should('have.length', 2).first().should('contain.text', 'Notion account personal project');
|
||||||
|
ndv.getters.backToCanvas().click();
|
||||||
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
|
||||||
|
cy.reload();
|
||||||
|
workflowPage.getters.canvasNodeByName(NOTION_NODE_NAME).should('be.visible').dblclick();
|
||||||
|
workflowPage.getters.nodeCredentialsSelect().first().click();
|
||||||
|
getVisibleSelect().find('li').should('have.length', 2).first().should('contain.text', 'Notion account personal project');
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,9 +28,10 @@ export async function getCredentialsNewName(
|
||||||
export async function getAllCredentials(
|
export async function getAllCredentials(
|
||||||
context: IRestApiContext,
|
context: IRestApiContext,
|
||||||
filter?: object,
|
filter?: object,
|
||||||
|
includeScopes?: boolean,
|
||||||
): Promise<ICredentialsResponse[]> {
|
): Promise<ICredentialsResponse[]> {
|
||||||
return await makeRestApiRequest(context, 'GET', '/credentials', {
|
return await makeRestApiRequest(context, 'GET', '/credentials', {
|
||||||
includeScopes: true,
|
...(includeScopes ? { includeScopes } : {}),
|
||||||
...(filter ? { filter } : {}),
|
...(filter ? { filter } : {}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,10 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
|
||||||
const credentialTypes = await getCredentialTypes(rootStore.getBaseUrl);
|
const credentialTypes = await getCredentialTypes(rootStore.getBaseUrl);
|
||||||
this.setCredentialTypes(credentialTypes);
|
this.setCredentialTypes(credentialTypes);
|
||||||
},
|
},
|
||||||
async fetchAllCredentials(projectId?: string): Promise<ICredentialsResponse[]> {
|
async fetchAllCredentials(
|
||||||
|
projectId?: string,
|
||||||
|
includeScopes = true,
|
||||||
|
): Promise<ICredentialsResponse[]> {
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
|
@ -257,6 +260,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, {
|
||||||
const credentials = await getAllCredentials(
|
const credentials = await getAllCredentials(
|
||||||
rootStore.getRestApiContext,
|
rootStore.getRestApiContext,
|
||||||
isEmpty(filter) ? undefined : filter,
|
isEmpty(filter) ? undefined : filter,
|
||||||
|
includeScopes,
|
||||||
);
|
);
|
||||||
this.setCredentials(credentials);
|
this.setCredentials(credentials);
|
||||||
return credentials;
|
return credentials;
|
||||||
|
|
|
@ -3794,7 +3794,6 @@ export default defineComponent({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.loadCredentials();
|
|
||||||
// Load a workflow
|
// Load a workflow
|
||||||
let workflowId = null as string | null;
|
let workflowId = null as string | null;
|
||||||
if (this.$route.params.name) {
|
if (this.$route.params.name) {
|
||||||
|
@ -3838,6 +3837,7 @@ export default defineComponent({
|
||||||
await this.newWorkflow();
|
await this.newWorkflow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await this.loadCredentials();
|
||||||
this.historyStore.reset();
|
this.historyStore.reset();
|
||||||
this.uiStore.nodeViewInitialized = true;
|
this.uiStore.nodeViewInitialized = true;
|
||||||
document.addEventListener('keydown', this.keyDown);
|
document.addEventListener('keydown', this.keyDown);
|
||||||
|
@ -4789,11 +4789,20 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
async loadCredentials(): Promise<void> {
|
async loadCredentials(): Promise<void> {
|
||||||
const workflow = this.workflowsStore.getWorkflowById(this.currentWorkflow);
|
const workflow = this.workflowsStore.getWorkflowById(this.currentWorkflow);
|
||||||
const projectId =
|
let projectId: string | undefined;
|
||||||
workflow?.homeProject?.type === ProjectTypes.Personal
|
if (workflow) {
|
||||||
|
projectId =
|
||||||
|
workflow.homeProject?.type === ProjectTypes.Personal
|
||||||
? this.projectsStore.personalProject?.id
|
? this.projectsStore.personalProject?.id
|
||||||
: workflow?.homeProject?.id;
|
: workflow?.homeProject?.id ?? this.projectsStore.currentProjectId;
|
||||||
await this.credentialsStore.fetchAllCredentials(projectId);
|
} else {
|
||||||
|
const queryParam =
|
||||||
|
typeof this.$route.query?.projectId === 'string'
|
||||||
|
? this.$route.query?.projectId
|
||||||
|
: undefined;
|
||||||
|
projectId = queryParam ?? this.projectsStore.personalProject?.id;
|
||||||
|
}
|
||||||
|
await this.credentialsStore.fetchAllCredentials(projectId, false);
|
||||||
},
|
},
|
||||||
async loadVariables(): Promise<void> {
|
async loadVariables(): Promise<void> {
|
||||||
await this.environmentsStore.fetchAllVariables();
|
await this.environmentsStore.fetchAllVariables();
|
||||||
|
|
Loading…
Reference in a new issue