mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
refactor(core): Update dynamic node parameter endpoints to use DTOs (#12379)
This commit is contained in:
parent
f08db47077
commit
1674dd0f88
|
@ -0,0 +1,81 @@
|
|||
import { ActionResultRequestDto } from '../action-result-request.dto';
|
||||
|
||||
describe('ActionResultRequestDto', () => {
|
||||
const baseValidRequest = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
handler: 'testHandler',
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
describe('Valid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'minimal valid request',
|
||||
request: baseValidRequest,
|
||||
},
|
||||
{
|
||||
name: 'request with payload',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
payload: { key: 'value' },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with credentials',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
credentials: { testCredential: { id: 'cred1', name: 'Test Cred' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with current node parameters',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
currentNodeParameters: { param1: 'value1' },
|
||||
},
|
||||
},
|
||||
])('should validate $name', ({ request }) => {
|
||||
const result = ActionResultRequestDto.safeParse(request);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Invalid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'missing path',
|
||||
request: {
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
handler: 'testHandler',
|
||||
},
|
||||
expectedErrorPath: ['path'],
|
||||
},
|
||||
{
|
||||
name: 'missing handler',
|
||||
request: {
|
||||
path: '/test/path',
|
||||
currentNodeParameters: {},
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
},
|
||||
expectedErrorPath: ['handler'],
|
||||
},
|
||||
{
|
||||
name: 'invalid node version',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 0 },
|
||||
},
|
||||
expectedErrorPath: ['nodeTypeAndVersion', 'version'],
|
||||
},
|
||||
])('should fail validation for $name', ({ request, expectedErrorPath }) => {
|
||||
const result = ActionResultRequestDto.safeParse(request);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
|
||||
if (expectedErrorPath) {
|
||||
expect(result.error?.issues[0].path).toEqual(expectedErrorPath);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,90 @@
|
|||
import { OptionsRequestDto } from '../options-request.dto';
|
||||
|
||||
describe('OptionsRequestDto', () => {
|
||||
const baseValidRequest = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
describe('Valid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'minimal valid request',
|
||||
request: baseValidRequest,
|
||||
},
|
||||
{
|
||||
name: 'request with method name',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
methodName: 'testMethod',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with load options',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
loadOptions: {
|
||||
routing: {
|
||||
operations: { someOperation: 'test' },
|
||||
output: { someOutput: 'test' },
|
||||
request: { someRequest: 'test' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with credentials',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
credentials: { testCredential: { id: 'cred1', name: 'Test Cred' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with current node parameters',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
currentNodeParameters: { param1: 'value1' },
|
||||
},
|
||||
},
|
||||
])('should validate $name', ({ request }) => {
|
||||
const result = OptionsRequestDto.safeParse(request);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Invalid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'missing path',
|
||||
request: {
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
},
|
||||
expectedErrorPath: ['path'],
|
||||
},
|
||||
{
|
||||
name: 'missing node type and version',
|
||||
request: {
|
||||
path: '/test/path',
|
||||
},
|
||||
expectedErrorPath: ['nodeTypeAndVersion'],
|
||||
},
|
||||
{
|
||||
name: 'invalid node version',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 0 },
|
||||
},
|
||||
expectedErrorPath: ['nodeTypeAndVersion', 'version'],
|
||||
},
|
||||
])('should fail validation for $name', ({ request, expectedErrorPath }) => {
|
||||
const result = OptionsRequestDto.safeParse(request);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
|
||||
if (expectedErrorPath) {
|
||||
expect(result.error?.issues[0].path).toEqual(expectedErrorPath);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,95 @@
|
|||
import { ResourceLocatorRequestDto } from '../resource-locator-request.dto';
|
||||
|
||||
describe('ResourceLocatorRequestDto', () => {
|
||||
const baseValidRequest = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
methodName: 'testMethod',
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
describe('Valid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'minimal valid request',
|
||||
request: baseValidRequest,
|
||||
},
|
||||
{
|
||||
name: 'request with filter',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
filter: 'testFilter',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with pagination token',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
paginationToken: 'token123',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with credentials',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
credentials: { testCredential: { id: 'cred1', name: 'Test Cred' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with current node parameters',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
currentNodeParameters: { param1: 'value1' },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with a semver node version',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1.1 },
|
||||
},
|
||||
},
|
||||
])('should validate $name', ({ request }) => {
|
||||
const result = ResourceLocatorRequestDto.safeParse(request);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Invalid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'missing path',
|
||||
request: {
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
methodName: 'testMethod',
|
||||
},
|
||||
expectedErrorPath: ['path'],
|
||||
},
|
||||
{
|
||||
name: 'missing method name',
|
||||
request: {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
currentNodeParameters: {},
|
||||
},
|
||||
expectedErrorPath: ['methodName'],
|
||||
},
|
||||
{
|
||||
name: 'invalid node version',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 0 },
|
||||
},
|
||||
expectedErrorPath: ['nodeTypeAndVersion', 'version'],
|
||||
},
|
||||
])('should fail validation for $name', ({ request, expectedErrorPath }) => {
|
||||
const result = ResourceLocatorRequestDto.safeParse(request);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
|
||||
if (expectedErrorPath) {
|
||||
expect(result.error?.issues[0].path).toEqual(expectedErrorPath);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,74 @@
|
|||
import { ResourceMapperFieldsRequestDto } from '../resource-mapper-fields-request.dto';
|
||||
|
||||
describe('ResourceMapperFieldsRequestDto', () => {
|
||||
const baseValidRequest = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
methodName: 'testMethod',
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
describe('Valid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'minimal valid request',
|
||||
request: baseValidRequest,
|
||||
},
|
||||
{
|
||||
name: 'request with credentials',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
credentials: { testCredential: { id: 'cred1', name: 'Test Cred' } },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'request with current node parameters',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
currentNodeParameters: { param1: 'value1' },
|
||||
},
|
||||
},
|
||||
])('should validate $name', ({ request }) => {
|
||||
const result = ResourceMapperFieldsRequestDto.safeParse(request);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Invalid requests', () => {
|
||||
test.each([
|
||||
{
|
||||
name: 'missing path',
|
||||
request: {
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
methodName: 'testMethod',
|
||||
},
|
||||
expectedErrorPath: ['path'],
|
||||
},
|
||||
{
|
||||
name: 'missing method name',
|
||||
request: {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
currentNodeParameters: {},
|
||||
},
|
||||
expectedErrorPath: ['methodName'],
|
||||
},
|
||||
{
|
||||
name: 'invalid node version',
|
||||
request: {
|
||||
...baseValidRequest,
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 0 },
|
||||
},
|
||||
expectedErrorPath: ['nodeTypeAndVersion', 'version'],
|
||||
},
|
||||
])('should fail validation for $name', ({ request, expectedErrorPath }) => {
|
||||
const result = ResourceMapperFieldsRequestDto.safeParse(request);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
|
||||
if (expectedErrorPath) {
|
||||
expect(result.error?.issues[0].path).toEqual(expectedErrorPath);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
import type { IDataObject } from 'n8n-workflow';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { BaseDynamicParametersRequestDto } from './base-dynamic-parameters-request.dto';
|
||||
|
||||
export class ActionResultRequestDto extends BaseDynamicParametersRequestDto.extend({
|
||||
handler: z.string(),
|
||||
payload: z
|
||||
.union([z.object({}).catchall(z.any()) satisfies z.ZodType<IDataObject>, z.string()])
|
||||
.optional(),
|
||||
}) {}
|
|
@ -0,0 +1,18 @@
|
|||
import type { INodeCredentials, INodeParameters, INodeTypeNameVersion } from 'n8n-workflow';
|
||||
import { z } from 'zod';
|
||||
import { Z } from 'zod-class';
|
||||
|
||||
import { nodeVersionSchema } from '../../schemas/nodeVersion.schema';
|
||||
|
||||
export class BaseDynamicParametersRequestDto extends Z.class({
|
||||
path: z.string(),
|
||||
nodeTypeAndVersion: z.object({
|
||||
name: z.string(),
|
||||
version: nodeVersionSchema,
|
||||
}) satisfies z.ZodType<INodeTypeNameVersion>,
|
||||
currentNodeParameters: z.record(z.string(), z.any()) satisfies z.ZodType<INodeParameters>,
|
||||
methodName: z.string().optional(),
|
||||
credentials: z.record(z.string(), z.any()).optional() satisfies z.ZodType<
|
||||
INodeCredentials | undefined
|
||||
>,
|
||||
}) {}
|
|
@ -0,0 +1,18 @@
|
|||
import type { ILoadOptions } from 'n8n-workflow';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { BaseDynamicParametersRequestDto } from './base-dynamic-parameters-request.dto';
|
||||
|
||||
export class OptionsRequestDto extends BaseDynamicParametersRequestDto.extend({
|
||||
loadOptions: z
|
||||
.object({
|
||||
routing: z
|
||||
.object({
|
||||
operations: z.any().optional(),
|
||||
output: z.any().optional(),
|
||||
request: z.any().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional() as z.ZodType<ILoadOptions | undefined>,
|
||||
}) {}
|
|
@ -0,0 +1,9 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { BaseDynamicParametersRequestDto } from './base-dynamic-parameters-request.dto';
|
||||
|
||||
export class ResourceLocatorRequestDto extends BaseDynamicParametersRequestDto.extend({
|
||||
methodName: z.string(),
|
||||
filter: z.string().optional(),
|
||||
paginationToken: z.string().optional(),
|
||||
}) {}
|
|
@ -0,0 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { BaseDynamicParametersRequestDto } from './base-dynamic-parameters-request.dto';
|
||||
|
||||
export class ResourceMapperFieldsRequestDto extends BaseDynamicParametersRequestDto.extend({
|
||||
methodName: z.string(),
|
||||
}) {}
|
|
@ -6,6 +6,11 @@ export { AiFreeCreditsRequestDto } from './ai/ai-free-credits-request.dto';
|
|||
export { LoginRequestDto } from './auth/login-request.dto';
|
||||
export { ResolveSignupTokenQueryDto } from './auth/resolve-signup-token-query.dto';
|
||||
|
||||
export { OptionsRequestDto } from './dynamic-node-parameters/options-request.dto';
|
||||
export { ResourceLocatorRequestDto } from './dynamic-node-parameters/resource-locator-request.dto';
|
||||
export { ResourceMapperFieldsRequestDto } from './dynamic-node-parameters/resource-mapper-fields-request.dto';
|
||||
export { ActionResultRequestDto } from './dynamic-node-parameters/action-result-request.dto';
|
||||
|
||||
export { InviteUsersRequestDto } from './invitation/invite-users-request.dto';
|
||||
export { AcceptInvitationRequestDto } from './invitation/accept-invitation-request.dto';
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { nodeVersionSchema } from '../nodeVersion.schema';
|
||||
|
||||
describe('nodeVersionSchema', () => {
|
||||
describe('valid versions', () => {
|
||||
test.each([
|
||||
[1, 'single digit'],
|
||||
[2, 'single digit'],
|
||||
[1.0, 'major.minor with zero minor'],
|
||||
[1.2, 'major.minor'],
|
||||
[10.5, 'major.minor with double digits'],
|
||||
])('should accept %s as a valid version (%s)', (version) => {
|
||||
const validated = nodeVersionSchema.parse(version);
|
||||
expect(validated).toBe(version);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid versions', () => {
|
||||
test.each([
|
||||
['not-a-number', 'non-number input'],
|
||||
['1.2.3', 'more than two parts'],
|
||||
['1.a', 'non-numeric characters'],
|
||||
['1.2.3', 'more than two parts as string'],
|
||||
])('should reject %s as an invalid version (%s)', (version) => {
|
||||
const check = () => nodeVersionSchema.parse(version);
|
||||
expect(check).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
17
packages/@n8n/api-types/src/schemas/nodeVersion.schema.ts
Normal file
17
packages/@n8n/api-types/src/schemas/nodeVersion.schema.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const nodeVersionSchema = z
|
||||
.number()
|
||||
.min(1)
|
||||
.refine(
|
||||
(val) => {
|
||||
const parts = String(val).split('.');
|
||||
return (
|
||||
(parts.length === 1 && !isNaN(Number(parts[0]))) ||
|
||||
(parts.length === 2 && !isNaN(Number(parts[0])) && !isNaN(Number(parts[1])))
|
||||
);
|
||||
},
|
||||
{
|
||||
message: 'Invalid node version. Must be in format: major.minor',
|
||||
},
|
||||
);
|
|
@ -1,34 +1,223 @@
|
|||
import type {
|
||||
OptionsRequestDto,
|
||||
ResourceLocatorRequestDto,
|
||||
ResourceMapperFieldsRequestDto,
|
||||
ActionResultRequestDto,
|
||||
} from '@n8n/api-types';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { ILoadOptions, IWorkflowExecuteAdditionalData } from 'n8n-workflow';
|
||||
import type {
|
||||
ILoadOptions,
|
||||
IWorkflowExecuteAdditionalData,
|
||||
INodePropertyOptions,
|
||||
NodeParameterValueType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { DynamicNodeParametersController } from '@/controllers/dynamic-node-parameters.controller';
|
||||
import type { DynamicNodeParametersRequest } from '@/requests';
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
import type { DynamicNodeParametersService } from '@/services/dynamic-node-parameters.service';
|
||||
import * as AdditionalData from '@/workflow-execute-additional-data';
|
||||
|
||||
describe('DynamicNodeParametersController', () => {
|
||||
const service = mock<DynamicNodeParametersService>();
|
||||
const controller = new DynamicNodeParametersController(service);
|
||||
let service: jest.Mocked<DynamicNodeParametersService>;
|
||||
let controller: DynamicNodeParametersController;
|
||||
let mockUser: { id: string };
|
||||
let baseAdditionalData: IWorkflowExecuteAdditionalData;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
service = mock<DynamicNodeParametersService>();
|
||||
controller = new DynamicNodeParametersController(service);
|
||||
|
||||
mockUser = { id: 'user123' };
|
||||
baseAdditionalData = mock<IWorkflowExecuteAdditionalData>();
|
||||
|
||||
jest.spyOn(AdditionalData, 'getBase').mockResolvedValue(baseAdditionalData);
|
||||
});
|
||||
|
||||
describe('getOptions', () => {
|
||||
it('should take `loadOptions` as object', async () => {
|
||||
jest
|
||||
.spyOn(AdditionalData, 'getBase')
|
||||
.mockResolvedValue(mock<IWorkflowExecuteAdditionalData>());
|
||||
const basePayload: OptionsRequestDto = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
const req = mock<DynamicNodeParametersRequest.Options>();
|
||||
const loadOptions: ILoadOptions = {};
|
||||
req.body.loadOptions = loadOptions;
|
||||
it('should call getOptionsViaMethodName when methodName is provided', async () => {
|
||||
const payload: OptionsRequestDto = {
|
||||
...basePayload,
|
||||
methodName: 'testMethod',
|
||||
};
|
||||
const req = { user: mockUser } as AuthenticatedRequest;
|
||||
|
||||
await controller.getOptions(req);
|
||||
const expectedResult: INodePropertyOptions[] = [{ name: 'test', value: 'value' }];
|
||||
service.getOptionsViaMethodName.mockResolvedValue(expectedResult);
|
||||
|
||||
const zerothArg = service.getOptionsViaLoadOptions.mock.calls[0][0];
|
||||
const result = await controller.getOptions(req, mock(), payload);
|
||||
|
||||
expect(zerothArg).toEqual(loadOptions);
|
||||
expect(service.getOptionsViaMethodName).toHaveBeenCalledWith(
|
||||
'testMethod',
|
||||
'/test/path',
|
||||
baseAdditionalData,
|
||||
{ name: 'TestNode', version: 1 },
|
||||
{},
|
||||
undefined,
|
||||
);
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should call getOptionsViaLoadOptions when loadOptions is provided', async () => {
|
||||
const loadOptions: ILoadOptions = {
|
||||
routing: {
|
||||
operations: {},
|
||||
},
|
||||
};
|
||||
const payload: OptionsRequestDto = {
|
||||
...basePayload,
|
||||
loadOptions,
|
||||
};
|
||||
const req = { user: mockUser } as AuthenticatedRequest;
|
||||
|
||||
const expectedResult: INodePropertyOptions[] = [{ name: 'test', value: 'value' }];
|
||||
service.getOptionsViaLoadOptions.mockResolvedValue(expectedResult);
|
||||
|
||||
const result = await controller.getOptions(req, mock(), payload);
|
||||
|
||||
expect(service.getOptionsViaLoadOptions).toHaveBeenCalledWith(
|
||||
loadOptions,
|
||||
baseAdditionalData,
|
||||
{ name: 'TestNode', version: 1 },
|
||||
{},
|
||||
undefined,
|
||||
);
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should return empty array when no method or load options are provided', async () => {
|
||||
const req = { user: mockUser } as AuthenticatedRequest;
|
||||
|
||||
const result = await controller.getOptions(req, mock(), basePayload);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResourceLocatorResults', () => {
|
||||
const basePayload: ResourceLocatorRequestDto = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
methodName: 'testMethod',
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
it('should call getResourceLocatorResults with correct parameters', async () => {
|
||||
const payload: ResourceLocatorRequestDto = {
|
||||
...basePayload,
|
||||
filter: 'testFilter',
|
||||
paginationToken: 'testToken',
|
||||
};
|
||||
const req = { user: mockUser } as AuthenticatedRequest;
|
||||
|
||||
const expectedResult = { results: [{ name: 'test', value: 'value' }] };
|
||||
service.getResourceLocatorResults.mockResolvedValue(expectedResult);
|
||||
|
||||
const result = await controller.getResourceLocatorResults(req, mock(), payload);
|
||||
|
||||
expect(service.getResourceLocatorResults).toHaveBeenCalledWith(
|
||||
'testMethod',
|
||||
'/test/path',
|
||||
baseAdditionalData,
|
||||
{ name: 'TestNode', version: 1 },
|
||||
{},
|
||||
undefined,
|
||||
'testFilter',
|
||||
'testToken',
|
||||
);
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getResourceMappingFields', () => {
|
||||
const basePayload: ResourceMapperFieldsRequestDto = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
methodName: 'testMethod',
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
it('should call getResourceMappingFields with correct parameters', async () => {
|
||||
const req = { user: mockUser } as AuthenticatedRequest;
|
||||
|
||||
const expectedResult = { fields: [] };
|
||||
service.getResourceMappingFields.mockResolvedValue(expectedResult);
|
||||
|
||||
const result = await controller.getResourceMappingFields(req, mock(), basePayload);
|
||||
|
||||
expect(service.getResourceMappingFields).toHaveBeenCalledWith(
|
||||
'testMethod',
|
||||
'/test/path',
|
||||
baseAdditionalData,
|
||||
{ name: 'TestNode', version: 1 },
|
||||
{},
|
||||
undefined,
|
||||
);
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLocalResourceMappingFields', () => {
|
||||
const basePayload: ResourceMapperFieldsRequestDto = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
methodName: 'testMethod',
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
it('should call getLocalResourceMappingFields with correct parameters', async () => {
|
||||
const req = { user: mockUser } as AuthenticatedRequest;
|
||||
|
||||
const expectedResult = { fields: [] };
|
||||
service.getLocalResourceMappingFields.mockResolvedValue(expectedResult);
|
||||
|
||||
const result = await controller.getLocalResourceMappingFields(req, mock(), basePayload);
|
||||
|
||||
expect(service.getLocalResourceMappingFields).toHaveBeenCalledWith(
|
||||
'testMethod',
|
||||
'/test/path',
|
||||
baseAdditionalData,
|
||||
{ name: 'TestNode', version: 1 },
|
||||
);
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getActionResult', () => {
|
||||
const basePayload: ActionResultRequestDto = {
|
||||
path: '/test/path',
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
handler: 'testHandler',
|
||||
currentNodeParameters: {},
|
||||
};
|
||||
|
||||
it('should call getActionResult with correct parameters', async () => {
|
||||
const payload: ActionResultRequestDto = {
|
||||
...basePayload,
|
||||
payload: { test: 'value' },
|
||||
};
|
||||
const req = { user: mockUser } as AuthenticatedRequest;
|
||||
|
||||
const expectedResult: NodeParameterValueType = 'test result';
|
||||
service.getActionResult.mockResolvedValue(expectedResult);
|
||||
|
||||
const result = await controller.getActionResult(req, mock(), payload);
|
||||
|
||||
expect(service.getActionResult).toHaveBeenCalledWith(
|
||||
'testHandler',
|
||||
'/test/path',
|
||||
baseAdditionalData,
|
||||
{ name: 'TestNode', version: 1 },
|
||||
{},
|
||||
{ test: 'value' },
|
||||
undefined,
|
||||
);
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import {
|
||||
OptionsRequestDto,
|
||||
ResourceLocatorRequestDto,
|
||||
ResourceMapperFieldsRequestDto,
|
||||
ActionResultRequestDto,
|
||||
} from '@n8n/api-types';
|
||||
import type { INodePropertyOptions, NodeParameterValueType } from 'n8n-workflow';
|
||||
|
||||
import { Post, RestController } from '@/decorators';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { DynamicNodeParametersRequest } from '@/requests';
|
||||
import { Post, RestController, Body } from '@/decorators';
|
||||
import { AuthenticatedRequest } from '@/requests';
|
||||
import { DynamicNodeParametersService } from '@/services/dynamic-node-parameters.service';
|
||||
import { getBase } from '@/workflow-execute-additional-data';
|
||||
|
||||
|
@ -11,7 +16,11 @@ export class DynamicNodeParametersController {
|
|||
constructor(private readonly service: DynamicNodeParametersService) {}
|
||||
|
||||
@Post('/options')
|
||||
async getOptions(req: DynamicNodeParametersRequest.Options): Promise<INodePropertyOptions[]> {
|
||||
async getOptions(
|
||||
req: AuthenticatedRequest,
|
||||
_res: Response,
|
||||
@Body payload: OptionsRequestDto,
|
||||
): Promise<INodePropertyOptions[]> {
|
||||
const {
|
||||
credentials,
|
||||
currentNodeParameters,
|
||||
|
@ -19,7 +28,7 @@ export class DynamicNodeParametersController {
|
|||
path,
|
||||
methodName,
|
||||
loadOptions,
|
||||
} = req.body;
|
||||
} = payload;
|
||||
|
||||
const additionalData = await getBase(req.user.id, currentNodeParameters);
|
||||
|
||||
|
@ -48,7 +57,11 @@ export class DynamicNodeParametersController {
|
|||
}
|
||||
|
||||
@Post('/resource-locator-results')
|
||||
async getResourceLocatorResults(req: DynamicNodeParametersRequest.ResourceLocatorResults) {
|
||||
async getResourceLocatorResults(
|
||||
req: AuthenticatedRequest,
|
||||
_res: Response,
|
||||
@Body payload: ResourceLocatorRequestDto,
|
||||
) {
|
||||
const {
|
||||
path,
|
||||
methodName,
|
||||
|
@ -57,9 +70,7 @@ export class DynamicNodeParametersController {
|
|||
credentials,
|
||||
currentNodeParameters,
|
||||
nodeTypeAndVersion,
|
||||
} = req.body;
|
||||
|
||||
if (!methodName) throw new BadRequestError('Missing `methodName` in request body');
|
||||
} = payload;
|
||||
|
||||
const additionalData = await getBase(req.user.id, currentNodeParameters);
|
||||
|
||||
|
@ -76,10 +87,12 @@ export class DynamicNodeParametersController {
|
|||
}
|
||||
|
||||
@Post('/resource-mapper-fields')
|
||||
async getResourceMappingFields(req: DynamicNodeParametersRequest.ResourceMapperFields) {
|
||||
const { path, methodName, credentials, currentNodeParameters, nodeTypeAndVersion } = req.body;
|
||||
|
||||
if (!methodName) throw new BadRequestError('Missing `methodName` in request body');
|
||||
async getResourceMappingFields(
|
||||
req: AuthenticatedRequest,
|
||||
_res: Response,
|
||||
@Body payload: ResourceMapperFieldsRequestDto,
|
||||
) {
|
||||
const { path, methodName, credentials, currentNodeParameters, nodeTypeAndVersion } = payload;
|
||||
|
||||
const additionalData = await getBase(req.user.id, currentNodeParameters);
|
||||
|
||||
|
@ -94,10 +107,12 @@ export class DynamicNodeParametersController {
|
|||
}
|
||||
|
||||
@Post('/local-resource-mapper-fields')
|
||||
async getLocalResourceMappingFields(req: DynamicNodeParametersRequest.ResourceMapperFields) {
|
||||
const { path, methodName, currentNodeParameters, nodeTypeAndVersion } = req.body;
|
||||
|
||||
if (!methodName) throw new BadRequestError('Missing `methodName` in request body');
|
||||
async getLocalResourceMappingFields(
|
||||
req: AuthenticatedRequest,
|
||||
_res: Response,
|
||||
@Body payload: ResourceMapperFieldsRequestDto,
|
||||
) {
|
||||
const { path, methodName, currentNodeParameters, nodeTypeAndVersion } = payload;
|
||||
|
||||
const additionalData = await getBase(req.user.id, currentNodeParameters);
|
||||
|
||||
|
@ -111,25 +126,29 @@ export class DynamicNodeParametersController {
|
|||
|
||||
@Post('/action-result')
|
||||
async getActionResult(
|
||||
req: DynamicNodeParametersRequest.ActionResult,
|
||||
req: AuthenticatedRequest,
|
||||
_res: Response,
|
||||
@Body payload: ActionResultRequestDto,
|
||||
): Promise<NodeParameterValueType> {
|
||||
const { currentNodeParameters, nodeTypeAndVersion, path, credentials, handler, payload } =
|
||||
req.body;
|
||||
const {
|
||||
currentNodeParameters,
|
||||
nodeTypeAndVersion,
|
||||
path,
|
||||
credentials,
|
||||
handler,
|
||||
payload: actionPayload,
|
||||
} = payload;
|
||||
|
||||
const additionalData = await getBase(req.user.id, currentNodeParameters);
|
||||
|
||||
if (handler) {
|
||||
return await this.service.getActionResult(
|
||||
handler,
|
||||
path,
|
||||
additionalData,
|
||||
nodeTypeAndVersion,
|
||||
currentNodeParameters,
|
||||
payload,
|
||||
credentials,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
return await this.service.getActionResult(
|
||||
handler,
|
||||
path,
|
||||
additionalData,
|
||||
nodeTypeAndVersion,
|
||||
currentNodeParameters,
|
||||
actionPayload,
|
||||
credentials,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,7 @@ import type express from 'express';
|
|||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
IDataObject,
|
||||
ILoadOptions,
|
||||
INodeCredentialTestRequest,
|
||||
INodeCredentials,
|
||||
INodeParameters,
|
||||
INodeTypeNameVersion,
|
||||
IPersonalizationSurveyAnswersV4,
|
||||
IUser,
|
||||
} from 'n8n-workflow';
|
||||
|
@ -268,47 +264,6 @@ export declare namespace OAuthRequest {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// /dynamic-node-parameters
|
||||
// ----------------------------------
|
||||
export declare namespace DynamicNodeParametersRequest {
|
||||
type BaseRequest<RequestBody = {}> = AuthenticatedRequest<
|
||||
{},
|
||||
{},
|
||||
{
|
||||
path: string;
|
||||
nodeTypeAndVersion: INodeTypeNameVersion;
|
||||
currentNodeParameters: INodeParameters;
|
||||
methodName?: string;
|
||||
credentials?: INodeCredentials;
|
||||
} & RequestBody,
|
||||
{}
|
||||
>;
|
||||
|
||||
/** POST /dynamic-node-parameters/options */
|
||||
type Options = BaseRequest<{
|
||||
loadOptions?: ILoadOptions;
|
||||
}>;
|
||||
|
||||
/** POST /dynamic-node-parameters/resource-locator-results */
|
||||
type ResourceLocatorResults = BaseRequest<{
|
||||
methodName: string;
|
||||
filter?: string;
|
||||
paginationToken?: string;
|
||||
}>;
|
||||
|
||||
/** POST dynamic-node-parameters/resource-mapper-fields */
|
||||
type ResourceMapperFields = BaseRequest<{
|
||||
methodName: string;
|
||||
}>;
|
||||
|
||||
/** POST /dynamic-node-parameters/action-result */
|
||||
type ActionResult = BaseRequest<{
|
||||
handler: string;
|
||||
payload: IDataObject | string | undefined;
|
||||
}>;
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// /tags
|
||||
// ----------------------------------
|
||||
|
|
|
@ -3,16 +3,21 @@ import type {
|
|||
INodeListSearchResult,
|
||||
IWorkflowExecuteAdditionalData,
|
||||
ResourceMapperFields,
|
||||
NodeParameterValueType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { DynamicNodeParametersService } from '@/services/dynamic-node-parameters.service';
|
||||
import * as AdditionalData from '@/workflow-execute-additional-data';
|
||||
import { mockInstance } from '@test/mocking';
|
||||
|
||||
import { createOwner } from '../shared/db/users';
|
||||
import type { SuperAgentTest } from '../shared/types';
|
||||
import { setupTestServer } from '../shared/utils';
|
||||
|
||||
describe('DynamicNodeParametersController', () => {
|
||||
const additionalData = mock<IWorkflowExecuteAdditionalData>();
|
||||
const service = mockInstance(DynamicNodeParametersService);
|
||||
|
||||
const testServer = setupTestServer({ endpointGroups: ['dynamic-node-parameters'] });
|
||||
let ownerAgent: SuperAgentTest;
|
||||
|
||||
|
@ -21,62 +26,171 @@ describe('DynamicNodeParametersController', () => {
|
|||
ownerAgent = testServer.authAgentFor(owner);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.spyOn(AdditionalData, 'getBase').mockResolvedValue(additionalData);
|
||||
});
|
||||
|
||||
const commonRequestParams = {
|
||||
credentials: {},
|
||||
currentNodeParameters: {},
|
||||
nodeTypeAndVersion: {},
|
||||
nodeTypeAndVersion: { name: 'TestNode', version: 1 },
|
||||
path: 'path',
|
||||
methodName: 'methodName',
|
||||
};
|
||||
|
||||
describe('POST /dynamic-node-parameters/options', () => {
|
||||
jest.spyOn(AdditionalData, 'getBase').mockResolvedValue(mock<IWorkflowExecuteAdditionalData>());
|
||||
|
||||
it('should take params via body', async () => {
|
||||
jest
|
||||
.spyOn(DynamicNodeParametersService.prototype, 'getOptionsViaMethodName')
|
||||
.mockResolvedValue([]);
|
||||
service.getOptionsViaMethodName.mockResolvedValue([]);
|
||||
|
||||
await ownerAgent
|
||||
.post('/dynamic-node-parameters/options')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
loadOptions: {},
|
||||
methodName: 'testMethod',
|
||||
})
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('should take params with loadOptions', async () => {
|
||||
const expectedResult = [{ name: 'Test Option', value: 'test' }];
|
||||
service.getOptionsViaLoadOptions.mockResolvedValue(expectedResult);
|
||||
|
||||
const response = await ownerAgent
|
||||
.post('/dynamic-node-parameters/options')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
loadOptions: { type: 'test' },
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toEqual({ data: expectedResult });
|
||||
});
|
||||
|
||||
it('should return empty array when no method or loadOptions provided', async () => {
|
||||
const response = await ownerAgent
|
||||
.post('/dynamic-node-parameters/options')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toEqual({ data: [] });
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /dynamic-node-parameters/resource-locator-results', () => {
|
||||
it('should take params via body', async () => {
|
||||
jest
|
||||
.spyOn(DynamicNodeParametersService.prototype, 'getResourceLocatorResults')
|
||||
.mockResolvedValue(mock<INodeListSearchResult>());
|
||||
it('should return resource locator results', async () => {
|
||||
const expectedResult: INodeListSearchResult = { results: [] };
|
||||
service.getResourceLocatorResults.mockResolvedValue(expectedResult);
|
||||
|
||||
const response = await ownerAgent
|
||||
.post('/dynamic-node-parameters/resource-locator-results')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
methodName: 'testMethod',
|
||||
filter: 'testFilter',
|
||||
paginationToken: 'testToken',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toEqual({ data: expectedResult });
|
||||
});
|
||||
|
||||
it('should handle resource locator results without pagination', async () => {
|
||||
const mockResults = mock<INodeListSearchResult>();
|
||||
service.getResourceLocatorResults.mockResolvedValue(mockResults);
|
||||
|
||||
await ownerAgent
|
||||
.post('/dynamic-node-parameters/resource-locator-results')
|
||||
.send({
|
||||
methodName: 'testMethod',
|
||||
...commonRequestParams,
|
||||
filter: 'filter',
|
||||
paginationToken: 'paginationToken',
|
||||
})
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('should return a 400 if methodName is not defined', async () => {
|
||||
await ownerAgent
|
||||
.post('/dynamic-node-parameters/resource-locator-results')
|
||||
.send(commonRequestParams)
|
||||
.expect(400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /dynamic-node-parameters/resource-mapper-fields', () => {
|
||||
it('should take params via body', async () => {
|
||||
jest
|
||||
.spyOn(DynamicNodeParametersService.prototype, 'getResourceMappingFields')
|
||||
.mockResolvedValue(mock<ResourceMapperFields>());
|
||||
it('should return resource mapper fields', async () => {
|
||||
const expectedResult: ResourceMapperFields = { fields: [] };
|
||||
service.getResourceMappingFields.mockResolvedValue(expectedResult);
|
||||
|
||||
await ownerAgent
|
||||
const response = await ownerAgent
|
||||
.post('/dynamic-node-parameters/resource-mapper-fields')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
loadOptions: 'loadOptions',
|
||||
methodName: 'testMethod',
|
||||
loadOptions: 'testLoadOptions',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toEqual({ data: expectedResult });
|
||||
});
|
||||
|
||||
it('should return a 400 if methodName is not defined', async () => {
|
||||
await ownerAgent
|
||||
.post('/dynamic-node-parameters/resource-mapper-fields')
|
||||
.send(commonRequestParams)
|
||||
.expect(400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /dynamic-node-parameters/local-resource-mapper-fields', () => {
|
||||
it('should return local resource mapper fields', async () => {
|
||||
const expectedResult: ResourceMapperFields = { fields: [] };
|
||||
service.getLocalResourceMappingFields.mockResolvedValue(expectedResult);
|
||||
|
||||
const response = await ownerAgent
|
||||
.post('/dynamic-node-parameters/local-resource-mapper-fields')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
methodName: 'testMethod',
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toEqual({ data: expectedResult });
|
||||
});
|
||||
|
||||
it('should return a 400 if methodName is not defined', async () => {
|
||||
await ownerAgent
|
||||
.post('/dynamic-node-parameters/local-resource-mapper-fields')
|
||||
.send(commonRequestParams)
|
||||
.expect(400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /dynamic-node-parameters/action-result', () => {
|
||||
it('should return action result with handler', async () => {
|
||||
const expectedResult: NodeParameterValueType = { test: true };
|
||||
service.getActionResult.mockResolvedValue(expectedResult);
|
||||
|
||||
const response = await ownerAgent
|
||||
.post('/dynamic-node-parameters/action-result')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
handler: 'testHandler',
|
||||
payload: { someData: 'test' },
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).toEqual({ data: expectedResult });
|
||||
});
|
||||
|
||||
it('should return a 400 if handler is not defined', async () => {
|
||||
await ownerAgent
|
||||
.post('/dynamic-node-parameters/action-result')
|
||||
.send({
|
||||
...commonRequestParams,
|
||||
payload: { someData: 'test' },
|
||||
})
|
||||
.expect(400);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,9 +27,6 @@ import type {
|
|||
IWorkflowSettings as IWorkflowSettingsWorkflow,
|
||||
WorkflowExecuteMode,
|
||||
PublicInstalledPackage,
|
||||
INodeTypeNameVersion,
|
||||
ILoadOptions,
|
||||
INodeCredentials,
|
||||
INodeListSearchItems,
|
||||
NodeParameterValueType,
|
||||
IDisplayOptions,
|
||||
|
@ -1266,35 +1263,6 @@ export type NodeAuthenticationOption = {
|
|||
displayOptions?: IDisplayOptions;
|
||||
};
|
||||
|
||||
export declare namespace DynamicNodeParameters {
|
||||
interface BaseRequest {
|
||||
path: string;
|
||||
nodeTypeAndVersion: INodeTypeNameVersion;
|
||||
currentNodeParameters: INodeParameters;
|
||||
methodName?: string;
|
||||
credentials?: INodeCredentials;
|
||||
}
|
||||
|
||||
interface OptionsRequest extends BaseRequest {
|
||||
loadOptions?: ILoadOptions;
|
||||
}
|
||||
|
||||
interface ResourceLocatorResultsRequest extends BaseRequest {
|
||||
methodName: string;
|
||||
filter?: string;
|
||||
paginationToken?: string;
|
||||
}
|
||||
|
||||
interface ResourceMapperFieldsRequest extends BaseRequest {
|
||||
methodName: string;
|
||||
}
|
||||
|
||||
interface ActionResultRequest extends BaseRequest {
|
||||
handler: string;
|
||||
payload: IDataObject | string | undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export interface EnvironmentVariable {
|
||||
id: string;
|
||||
key: string;
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import type {
|
||||
ActionResultRequestDto,
|
||||
OptionsRequestDto,
|
||||
ResourceLocatorRequestDto,
|
||||
ResourceMapperFieldsRequestDto,
|
||||
} from '@n8n/api-types';
|
||||
import { makeRestApiRequest } from '@/utils/apiUtils';
|
||||
import type { DynamicNodeParameters, INodeTranslationHeaders, IRestApiContext } from '@/Interface';
|
||||
import type { INodeTranslationHeaders, IRestApiContext } from '@/Interface';
|
||||
import type {
|
||||
INodeListSearchResult,
|
||||
INodePropertyOptions,
|
||||
|
@ -30,14 +36,14 @@ export async function getNodesInformation(
|
|||
|
||||
export async function getNodeParameterOptions(
|
||||
context: IRestApiContext,
|
||||
sendData: DynamicNodeParameters.OptionsRequest,
|
||||
sendData: OptionsRequestDto,
|
||||
): Promise<INodePropertyOptions[]> {
|
||||
return await makeRestApiRequest(context, 'POST', '/dynamic-node-parameters/options', sendData);
|
||||
}
|
||||
|
||||
export async function getResourceLocatorResults(
|
||||
context: IRestApiContext,
|
||||
sendData: DynamicNodeParameters.ResourceLocatorResultsRequest,
|
||||
sendData: ResourceLocatorRequestDto,
|
||||
): Promise<INodeListSearchResult> {
|
||||
return await makeRestApiRequest(
|
||||
context,
|
||||
|
@ -49,7 +55,7 @@ export async function getResourceLocatorResults(
|
|||
|
||||
export async function getResourceMapperFields(
|
||||
context: IRestApiContext,
|
||||
sendData: DynamicNodeParameters.ResourceMapperFieldsRequest,
|
||||
sendData: ResourceMapperFieldsRequestDto,
|
||||
): Promise<ResourceMapperFields> {
|
||||
return await makeRestApiRequest(
|
||||
context,
|
||||
|
@ -61,7 +67,7 @@ export async function getResourceMapperFields(
|
|||
|
||||
export async function getLocalResourceMapperFields(
|
||||
context: IRestApiContext,
|
||||
sendData: DynamicNodeParameters.ResourceMapperFieldsRequest,
|
||||
sendData: ResourceMapperFieldsRequestDto,
|
||||
): Promise<ResourceMapperFields> {
|
||||
return await makeRestApiRequest(
|
||||
context,
|
||||
|
@ -73,7 +79,7 @@ export async function getLocalResourceMapperFields(
|
|||
|
||||
export async function getNodeParameterActionResult(
|
||||
context: IRestApiContext,
|
||||
sendData: DynamicNodeParameters.ActionResultRequest,
|
||||
sendData: ActionResultRequestDto,
|
||||
): Promise<NodeParameterValueType> {
|
||||
return await makeRestApiRequest(
|
||||
context,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { DynamicNodeParameters, IResourceLocatorResultExpanded } from '@/Interface';
|
||||
import type { ResourceLocatorRequestDto } from '@n8n/api-types';
|
||||
import type { IResourceLocatorResultExpanded } from '@/Interface';
|
||||
import DraggableTarget from '@/components/DraggableTarget.vue';
|
||||
import ExpressionParameterInput from '@/components/ExpressionParameterInput.vue';
|
||||
import ParameterIssues from '@/components/ParameterIssues.vue';
|
||||
|
@ -563,7 +564,7 @@ async function loadResources() {
|
|||
) as INodeParameters;
|
||||
const loadOptionsMethod = getPropertyArgument(currentMode.value, 'searchListMethod') as string;
|
||||
|
||||
const requestParams: DynamicNodeParameters.ResourceLocatorResultsRequest = {
|
||||
const requestParams: ResourceLocatorRequestDto = {
|
||||
nodeTypeAndVersion: {
|
||||
name: props.node.type,
|
||||
version: props.node.typeVersion,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { IUpdateInformation, DynamicNodeParameters } from '@/Interface';
|
||||
import type { ResourceMapperFieldsRequestDto } from '@n8n/api-types';
|
||||
import type { IUpdateInformation } from '@/Interface';
|
||||
import { resolveRequiredParameters } from '@/composables/useWorkflowHelpers';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import type {
|
||||
|
@ -294,7 +295,7 @@ const createRequestParams = (methodName: string) => {
|
|||
if (!props.node) {
|
||||
return;
|
||||
}
|
||||
const requestParams: DynamicNodeParameters.ResourceMapperFieldsRequest = {
|
||||
const requestParams: ResourceMapperFieldsRequestDto = {
|
||||
nodeTypeAndVersion: {
|
||||
name: props.node.type,
|
||||
version: props.node.typeVersion,
|
||||
|
@ -320,12 +321,12 @@ async function fetchFields(): Promise<ResourceMapperFields | null> {
|
|||
if (typeof resourceMapperMethod === 'string') {
|
||||
const requestParams = createRequestParams(
|
||||
resourceMapperMethod,
|
||||
) as DynamicNodeParameters.ResourceMapperFieldsRequest;
|
||||
) as ResourceMapperFieldsRequestDto;
|
||||
fetchedFields = await nodeTypesStore.getResourceMapperFields(requestParams);
|
||||
} else if (typeof localResourceMapperMethod === 'string') {
|
||||
const requestParams = createRequestParams(
|
||||
localResourceMapperMethod,
|
||||
) as DynamicNodeParameters.ResourceMapperFieldsRequest;
|
||||
) as ResourceMapperFieldsRequestDto;
|
||||
|
||||
fetchedFields = await nodeTypesStore.getLocalResourceMapperFields(requestParams);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import type {
|
||||
ActionResultRequestDto,
|
||||
OptionsRequestDto,
|
||||
ResourceLocatorRequestDto,
|
||||
ResourceMapperFieldsRequestDto,
|
||||
} from '@n8n/api-types';
|
||||
import * as nodeTypesApi from '@/api/nodeTypes';
|
||||
import { HTTP_REQUEST_NODE_TYPE, STORES, CREDENTIAL_ONLY_HTTP_NODE_VERSION } from '@/constants';
|
||||
import type { DynamicNodeParameters, NodeTypesByTypeNameAndVersion } from '@/Interface';
|
||||
import type { NodeTypesByTypeNameAndVersion } from '@/Interface';
|
||||
import { addHeaders, addNodeTranslation } from '@/plugins/i18n';
|
||||
import { omit } from '@/utils/typesUtils';
|
||||
import type {
|
||||
|
@ -282,19 +288,15 @@ export const useNodeTypesStore = defineStore(STORES.NODE_TYPES, () => {
|
|||
}
|
||||
};
|
||||
|
||||
const getNodeParameterOptions = async (sendData: DynamicNodeParameters.OptionsRequest) => {
|
||||
const getNodeParameterOptions = async (sendData: OptionsRequestDto) => {
|
||||
return await nodeTypesApi.getNodeParameterOptions(rootStore.restApiContext, sendData);
|
||||
};
|
||||
|
||||
const getResourceLocatorResults = async (
|
||||
sendData: DynamicNodeParameters.ResourceLocatorResultsRequest,
|
||||
) => {
|
||||
const getResourceLocatorResults = async (sendData: ResourceLocatorRequestDto) => {
|
||||
return await nodeTypesApi.getResourceLocatorResults(rootStore.restApiContext, sendData);
|
||||
};
|
||||
|
||||
const getResourceMapperFields = async (
|
||||
sendData: DynamicNodeParameters.ResourceMapperFieldsRequest,
|
||||
) => {
|
||||
const getResourceMapperFields = async (sendData: ResourceMapperFieldsRequestDto) => {
|
||||
try {
|
||||
return await nodeTypesApi.getResourceMapperFields(rootStore.restApiContext, sendData);
|
||||
} catch (error) {
|
||||
|
@ -302,9 +304,7 @@ export const useNodeTypesStore = defineStore(STORES.NODE_TYPES, () => {
|
|||
}
|
||||
};
|
||||
|
||||
const getLocalResourceMapperFields = async (
|
||||
sendData: DynamicNodeParameters.ResourceMapperFieldsRequest,
|
||||
) => {
|
||||
const getLocalResourceMapperFields = async (sendData: ResourceMapperFieldsRequestDto) => {
|
||||
try {
|
||||
return await nodeTypesApi.getLocalResourceMapperFields(rootStore.restApiContext, sendData);
|
||||
} catch (error) {
|
||||
|
@ -312,9 +312,7 @@ export const useNodeTypesStore = defineStore(STORES.NODE_TYPES, () => {
|
|||
}
|
||||
};
|
||||
|
||||
const getNodeParameterActionResult = async (
|
||||
sendData: DynamicNodeParameters.ActionResultRequest,
|
||||
) => {
|
||||
const getNodeParameterActionResult = async (sendData: ActionResultRequestDto) => {
|
||||
return await nodeTypesApi.getNodeParameterActionResult(rootStore.restApiContext, sendData);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue