fix(editor): Make resource locator work with data tables (no-changelog) (#18899)

This commit is contained in:
Jaakko Husso
2025-08-28 11:38:47 +03:00
committed by GitHub
parent d244b99484
commit ab7998b441
7 changed files with 36 additions and 4 deletions

View File

@@ -6,4 +6,5 @@ export class ResourceLocatorRequestDto extends BaseDynamicParametersRequestDto.e
methodName: z.string(),
filter: z.string().optional(),
paginationToken: z.string().optional(),
projectId: z.string().optional(),
}) {}

View File

@@ -10,6 +10,7 @@ import type { INodePropertyOptions, NodeParameterValueType } from 'n8n-workflow'
import { DynamicNodeParametersService } from '@/services/dynamic-node-parameters.service';
import { getBase } from '@/workflow-execute-additional-data';
import { userHasScopes } from '@/permissions.ee/check-access';
@RestController('/dynamic-node-parameters')
export class DynamicNodeParametersController {
@@ -70,10 +71,22 @@ export class DynamicNodeParametersController {
credentials,
currentNodeParameters,
nodeTypeAndVersion,
projectId,
} = payload;
const additionalData = await getBase(req.user.id, currentNodeParameters);
if (projectId) {
if (await userHasScopes(req.user, ['dataStore:listProject'], false, { projectId })) {
// Project ID is currently only added on the additionalData if the user
// has data store listing permission for that project. We should consider
// turning this into a more general check, but as of now data stores are
// the only nodes with project specific resource locators where we want to ensure
// that only data stores belonging to their respective projects are shown.
additionalData.dataStoreProjectId = projectId;
}
}
return await this.service.getResourceLocatorResults(
methodName,
path,

View File

@@ -47,9 +47,10 @@ export class DataStoreProxyService implements DataStoreProxyProvider {
async getDataStoreAggregateProxy(
workflow: Workflow,
node: INode,
dataStoreProjectId?: string,
): Promise<IDataStoreProjectAggregateService> {
this.validateRequest(node);
const projectId = await this.getProjectId(workflow);
const projectId = dataStoreProjectId ?? (await this.getProjectId(workflow));
return this.makeAggregateOperations(projectId);
}
@@ -58,9 +59,10 @@ export class DataStoreProxyService implements DataStoreProxyProvider {
workflow: Workflow,
node: INode,
dataStoreId: string,
dataStoreProjectId?: string,
): Promise<IDataStoreProjectService> {
this.validateRequest(node);
const projectId = await this.getProjectId(workflow);
const projectId = dataStoreProjectId ?? (await this.getProjectId(workflow));
return this.makeDataStoreOperations(projectId, dataStoreId);
}

View File

@@ -8,6 +8,7 @@ declare module 'n8n-workflow' {
hooks?: ExecutionLifecycleHooks;
externalSecretsProxy: ExternalSecretsProxy;
dataStoreProxyProvider?: DataStoreProxyProvider;
dataStoreProjectId?: string;
}
}

View File

@@ -14,8 +14,17 @@ export function getDataStoreHelperFunctions(
const dataStoreProxyProvider = additionalData.dataStoreProxyProvider;
return {
getDataStoreAggregateProxy: async () =>
await dataStoreProxyProvider.getDataStoreAggregateProxy(workflow, node),
await dataStoreProxyProvider.getDataStoreAggregateProxy(
workflow,
node,
additionalData.dataStoreProjectId,
),
getDataStoreProxy: async (dataStoreId: string) =>
await dataStoreProxyProvider.getDataStoreProxy(workflow, node, dataStoreId),
await dataStoreProxyProvider.getDataStoreProxy(
workflow,
node,
dataStoreId,
additionalData.dataStoreProjectId,
),
};
}

View File

@@ -55,6 +55,7 @@ import {
} from '../../utils/fromAIOverrideUtils';
import { N8nNotice } from '@n8n/design-system';
import { completeExpressionSyntax } from '@/utils/expressions';
import { useProjectsStore } from '@/stores/projects.store';
/**
* Regular expression to check if the error message contains credential-related phrases.
@@ -144,6 +145,7 @@ const ndvStore = useNDVStore();
const rootStore = useRootStore();
const uiStore = useUIStore();
const workflowsStore = useWorkflowsStore();
const projectsStore = useProjectsStore();
const appName = computed(() => {
if (!props.node) {
@@ -270,6 +272,7 @@ const currentRequestParams = computed(() => {
parameters: props.node?.parameters ?? {},
credentials: props.node?.credentials ?? {},
filter: searchFilter.value,
projectId: projectsStore.currentProjectId,
};
});
@@ -722,6 +725,7 @@ async function loadResources() {
methodName: loadOptionsMethod,
currentNodeParameters: resolvedNodeParameters,
credentials: props.node.credentials,
projectId: projectsStore.currentProjectId,
};
if (params.filter) {

View File

@@ -924,11 +924,13 @@ export type DataStoreProxyProvider = {
getDataStoreAggregateProxy(
workflow: Workflow,
node: INode,
dataStoreProjectId?: string,
): Promise<IDataStoreProjectAggregateService>;
getDataStoreProxy(
workflow: Workflow,
node: INode,
dataStoreId: string,
dataStoreProjectId?: string,
): Promise<IDataStoreProjectService>;
};