mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
fix: Expose projectId for remaining Data Table contexts (no-changelog) (#19058)
This commit is contained in:
@@ -15,4 +15,5 @@ export class BaseDynamicParametersRequestDto extends Z.class({
|
|||||||
credentials: z.record(z.string(), z.any()).optional() satisfies z.ZodType<
|
credentials: z.record(z.string(), z.any()).optional() satisfies z.ZodType<
|
||||||
INodeCredentials | undefined
|
INodeCredentials | undefined
|
||||||
>,
|
>,
|
||||||
|
projectId: z.string().optional(),
|
||||||
}) {}
|
}) {}
|
||||||
|
|||||||
@@ -6,5 +6,4 @@ export class ResourceLocatorRequestDto extends BaseDynamicParametersRequestDto.e
|
|||||||
methodName: z.string(),
|
methodName: z.string(),
|
||||||
filter: z.string().optional(),
|
filter: z.string().optional(),
|
||||||
paginationToken: z.string().optional(),
|
paginationToken: z.string().optional(),
|
||||||
projectId: z.string().optional(),
|
|
||||||
}) {}
|
}) {}
|
||||||
|
|||||||
@@ -29,10 +29,22 @@ export class DynamicNodeParametersController {
|
|||||||
path,
|
path,
|
||||||
methodName,
|
methodName,
|
||||||
loadOptions,
|
loadOptions,
|
||||||
|
projectId,
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
const additionalData = await getBase(req.user.id, currentNodeParameters);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (methodName) {
|
if (methodName) {
|
||||||
return await this.service.getOptionsViaMethodName(
|
return await this.service.getOptionsViaMethodName(
|
||||||
methodName,
|
methodName,
|
||||||
@@ -105,10 +117,22 @@ export class DynamicNodeParametersController {
|
|||||||
_res: Response,
|
_res: Response,
|
||||||
@Body payload: ResourceMapperFieldsRequestDto,
|
@Body payload: ResourceMapperFieldsRequestDto,
|
||||||
) {
|
) {
|
||||||
const { path, methodName, credentials, currentNodeParameters, nodeTypeAndVersion } = payload;
|
const { path, methodName, credentials, currentNodeParameters, nodeTypeAndVersion, projectId } =
|
||||||
|
payload;
|
||||||
|
|
||||||
const additionalData = await getBase(req.user.id, currentNodeParameters);
|
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.getResourceMappingFields(
|
return await this.service.getResourceMappingFields(
|
||||||
methodName,
|
methodName,
|
||||||
path,
|
path,
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ import CssEditor from './CssEditor/CssEditor.vue';
|
|||||||
import { useFocusPanelStore } from '@/stores/focusPanel.store';
|
import { useFocusPanelStore } from '@/stores/focusPanel.store';
|
||||||
import ExperimentalEmbeddedNdvMapper from '@/components/canvas/experimental/components/ExperimentalEmbeddedNdvMapper.vue';
|
import ExperimentalEmbeddedNdvMapper from '@/components/canvas/experimental/components/ExperimentalEmbeddedNdvMapper.vue';
|
||||||
import { useExperimentalNdvStore } from '@/components/canvas/experimental/experimentalNdv.store';
|
import { useExperimentalNdvStore } from '@/components/canvas/experimental/experimentalNdv.store';
|
||||||
|
import { useProjectsStore } from '@/stores/projects.store';
|
||||||
|
|
||||||
type Picker = { $emit: (arg0: string, arg1: Date) => void };
|
type Picker = { $emit: (arg0: string, arg1: Date) => void };
|
||||||
|
|
||||||
@@ -152,6 +153,7 @@ const nodeTypesStore = useNodeTypesStore();
|
|||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
const focusPanelStore = useFocusPanelStore();
|
const focusPanelStore = useFocusPanelStore();
|
||||||
const experimentalNdvStore = useExperimentalNdvStore();
|
const experimentalNdvStore = useExperimentalNdvStore();
|
||||||
|
const projectsStore = useProjectsStore();
|
||||||
|
|
||||||
const expressionLocalResolveCtx = inject(ExpressionLocalResolveContextSymbol, undefined);
|
const expressionLocalResolveCtx = inject(ExpressionLocalResolveContextSymbol, undefined);
|
||||||
|
|
||||||
@@ -688,6 +690,7 @@ async function loadRemoteParameterOptions() {
|
|||||||
loadOptions,
|
loadOptions,
|
||||||
currentNodeParameters: resolvedNodeParameters,
|
currentNodeParameters: resolvedNodeParameters,
|
||||||
credentials: node.value.credentials,
|
credentials: node.value.credentials,
|
||||||
|
projectId: projectsStore.currentProjectId,
|
||||||
});
|
});
|
||||||
|
|
||||||
remoteParameterOptions.value = remoteParameterOptions.value.concat(options);
|
remoteParameterOptions.value = remoteParameterOptions.value.concat(options);
|
||||||
|
|||||||
@@ -4,13 +4,17 @@ import {
|
|||||||
UPDATED_SCHEMA,
|
UPDATED_SCHEMA,
|
||||||
} from './__tests__/utils/ResourceMapper.utils';
|
} from './__tests__/utils/ResourceMapper.utils';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import { cleanupAppModals, createAppModals, waitAllPromises } from '@/__tests__/utils';
|
import type { MockedStore } from '@/__tests__/utils';
|
||||||
|
import { cleanupAppModals, createAppModals, mockedStore, waitAllPromises } from '@/__tests__/utils';
|
||||||
import ResourceMapper from '@/components/ResourceMapper/ResourceMapper.vue';
|
import ResourceMapper from '@/components/ResourceMapper/ResourceMapper.vue';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { createComponentRenderer } from '@/__tests__/render';
|
import { createComponentRenderer } from '@/__tests__/render';
|
||||||
import type { MockInstance } from 'vitest';
|
import type { MockInstance } from 'vitest';
|
||||||
|
import { useProjectsStore } from '@/stores/projects.store';
|
||||||
|
|
||||||
let nodeTypeStore: ReturnType<typeof useNodeTypesStore>;
|
let nodeTypeStore: ReturnType<typeof useNodeTypesStore>;
|
||||||
|
let projectsStore: MockedStore<typeof useProjectsStore>;
|
||||||
|
|
||||||
let fetchFieldsSpy: MockInstance;
|
let fetchFieldsSpy: MockInstance;
|
||||||
|
|
||||||
const renderComponent = createComponentRenderer(ResourceMapper, DEFAULT_SETUP);
|
const renderComponent = createComponentRenderer(ResourceMapper, DEFAULT_SETUP);
|
||||||
@@ -25,6 +29,8 @@ describe('ResourceMapper.vue', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
createAppModals();
|
createAppModals();
|
||||||
|
projectsStore = mockedStore(useProjectsStore);
|
||||||
|
projectsStore.currentProjectId = 'aProjectId';
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
|||||||
import { useDocumentVisibility } from '@/composables/useDocumentVisibility';
|
import { useDocumentVisibility } from '@/composables/useDocumentVisibility';
|
||||||
import { N8nButton, N8nCallout, N8nNotice } from '@n8n/design-system';
|
import { N8nButton, N8nCallout, N8nNotice } from '@n8n/design-system';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import { useProjectsStore } from '@/stores/projects.store';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
parameter: INodeProperties;
|
parameter: INodeProperties;
|
||||||
@@ -46,6 +47,7 @@ type Props = {
|
|||||||
const nodeTypesStore = useNodeTypesStore();
|
const nodeTypesStore = useNodeTypesStore();
|
||||||
const ndvStore = useNDVStore();
|
const ndvStore = useNDVStore();
|
||||||
const workflowsStore = useWorkflowsStore();
|
const workflowsStore = useWorkflowsStore();
|
||||||
|
const projectsStore = useProjectsStore();
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
teleported: true,
|
teleported: true,
|
||||||
@@ -310,6 +312,7 @@ const createRequestParams = (methodName: string) => {
|
|||||||
path: props.path,
|
path: props.path,
|
||||||
methodName,
|
methodName,
|
||||||
credentials: props.node.credentials,
|
credentials: props.node.credentials,
|
||||||
|
projectId: projectsStore.currentProjectId,
|
||||||
};
|
};
|
||||||
|
|
||||||
return requestParams;
|
return requestParams;
|
||||||
|
|||||||
Reference in New Issue
Block a user