mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-24 23:22:38 +08:00
fix(editor): Use workflow-scoped credential fetch in node credential picker (#31938)
This commit is contained in:
+37
-2
@@ -21,6 +21,7 @@ import { useNDVStore } from '@/features/ndv/shared/ndv.store';
|
||||
import { useUIStore } from '@/app/stores/ui.store';
|
||||
import { useSettingsStore } from '@/app/stores/settings.store';
|
||||
import { useNodeTypesStore } from '@/app/stores/nodeTypes.store';
|
||||
import { useWorkflowsStore } from '@/app/stores/workflows.store';
|
||||
import { useAiGateway } from '@/app/composables/useAiGateway';
|
||||
import { WorkflowDocumentStoreKey } from '@/app/constants/injectionKeys';
|
||||
import {
|
||||
@@ -153,6 +154,7 @@ describe('NodeCredentials', () => {
|
||||
let uiStore: ReturnType<typeof mockedStore<typeof useUIStore>>;
|
||||
let projectsStore: ReturnType<typeof mockedStore<typeof useProjectsStore>>;
|
||||
let settingsStore: ReturnType<typeof mockedStore<typeof useSettingsStore>>;
|
||||
let workflowsStore: ReturnType<typeof mockedStore<typeof useWorkflowsStore>>;
|
||||
let workflowDocumentStore: ReturnType<typeof useWorkflowDocumentStore>;
|
||||
let workflowDocumentStoreRef: ReturnType<
|
||||
typeof shallowRef<ReturnType<typeof useWorkflowDocumentStore> | null>
|
||||
@@ -190,11 +192,15 @@ describe('NodeCredentials', () => {
|
||||
|
||||
credentialsStore = mockedStore(useCredentialsStore);
|
||||
// Component triggers this on mount; avoid a real XHR with stubActions: false.
|
||||
credentialsStore.fetchAllCredentials = vi.fn().mockResolvedValue([]);
|
||||
credentialsStore.fetchAllCredentialsForWorkflow = vi.fn().mockResolvedValue([]);
|
||||
|
||||
ndvStore = mockedStore(useNDVStore, createWorkflowDocumentId('1'));
|
||||
uiStore = mockedStore(useUIStore);
|
||||
projectsStore = mockedStore(useProjectsStore);
|
||||
settingsStore = mockedStore(useSettingsStore);
|
||||
workflowsStore = mockedStore(useWorkflowsStore);
|
||||
|
||||
workflowsStore.isNewWorkflow = false;
|
||||
|
||||
projectsStore.currentProject = { id: 'default', scopes: ['credential:create'] } as Project;
|
||||
settingsStore.settings = {
|
||||
@@ -231,7 +237,36 @@ describe('NodeCredentials', () => {
|
||||
|
||||
renderComponent();
|
||||
|
||||
expect(credentialsStore.fetchAllCredentials).toHaveBeenCalled();
|
||||
expect(credentialsStore.fetchAllCredentialsForWorkflow).toHaveBeenCalledWith({
|
||||
workflowId: '1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch credentials scoped to the project for an unsaved workflow', () => {
|
||||
workflowsStore.isNewWorkflow = true;
|
||||
projectsStore.currentProject = { id: 'project-1' } as Project;
|
||||
ndvStore.activeNode = httpNode;
|
||||
credentialsStore.state.credentials = {};
|
||||
|
||||
renderComponent();
|
||||
|
||||
expect(credentialsStore.fetchAllCredentialsForWorkflow).toHaveBeenCalledWith({
|
||||
projectId: 'project-1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should fall back to the personal project for an unsaved workflow without a current project', () => {
|
||||
workflowsStore.isNewWorkflow = true;
|
||||
projectsStore.currentProject = null;
|
||||
projectsStore.personalProject = { id: 'personal-project' } as Project;
|
||||
ndvStore.activeNode = httpNode;
|
||||
credentialsStore.state.credentials = {};
|
||||
|
||||
renderComponent();
|
||||
|
||||
expect(credentialsStore.fetchAllCredentialsForWorkflow).toHaveBeenCalledWith({
|
||||
projectId: 'personal-project',
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore managed credentials in the dropdown if active node is the HTTP node', async () => {
|
||||
|
||||
+18
-3
@@ -32,6 +32,7 @@ import { injectNDVStore } from '@/features/ndv/shared/ndv.store';
|
||||
import { useNodeTypesStore } from '@/app/stores/nodeTypes.store';
|
||||
import { useUIStore } from '@/app/stores/ui.store';
|
||||
import { useProjectsStore } from '@/features/collaboration/projects/projects.store';
|
||||
import { useWorkflowsStore } from '@/app/stores/workflows.store';
|
||||
import { assert } from '@n8n/utils/assert';
|
||||
import { isEmpty } from '@/app/utils/typesUtils';
|
||||
import { getResourcePermissions } from '@n8n/permissions';
|
||||
@@ -97,6 +98,7 @@ const nodeTypesStore = useNodeTypesStore();
|
||||
const ndvStore = injectNDVStore();
|
||||
const uiStore = useUIStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const workflowDocumentStore = props.standalone ? undefined : injectWorkflowDocumentStore();
|
||||
const { isEnabled: isDynamicCredentialsEnabled } = useDynamicCredentials();
|
||||
|
||||
@@ -256,6 +258,18 @@ watch(
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function getCredentialFetchScope(): { workflowId: string } | { projectId: string } | undefined {
|
||||
const workflowId = workflowDocumentStore?.value.workflowId;
|
||||
if (workflowId && !workflowsStore.isNewWorkflow) {
|
||||
return { workflowId };
|
||||
}
|
||||
|
||||
const projectId =
|
||||
props.projectId ?? projectsStore.currentProject?.id ?? projectsStore.personalProject?.id;
|
||||
|
||||
return projectId ? { projectId } : undefined;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
credentialsStore.$onAction(({ name, after, args }) => {
|
||||
const listeningForActions = ['createNewCredential', 'updateCredential', 'deleteCredential'];
|
||||
@@ -325,9 +339,10 @@ onMounted(() => {
|
||||
|
||||
ndvEventBus.on('credential.createNew', onCreateAndAssignNewCredential);
|
||||
|
||||
void credentialsStore.fetchAllCredentials({
|
||||
projectId: projectsStore.currentProject?.id,
|
||||
});
|
||||
const scope = getCredentialFetchScope();
|
||||
if (scope) {
|
||||
void credentialsStore.fetchAllCredentialsForWorkflow(scope);
|
||||
}
|
||||
|
||||
void aiGateway.fetchConfig();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user