mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
add workflow loader
This commit is contained in:
parent
5efdde1f6d
commit
e0c9e9eb0d
|
@ -24,6 +24,8 @@ import { Service } from 'typedi';
|
||||||
|
|
||||||
import { NodeTypes } from '@/node-types';
|
import { NodeTypes } from '@/node-types';
|
||||||
|
|
||||||
|
import { WorkflowLoaderService } from './workflow-loader.service';
|
||||||
|
|
||||||
type LocalResourceMappingMethod = (
|
type LocalResourceMappingMethod = (
|
||||||
this: ILocalLoadOptionsFunctions,
|
this: ILocalLoadOptionsFunctions,
|
||||||
) => Promise<ResourceMapperFields>;
|
) => Promise<ResourceMapperFields>;
|
||||||
|
@ -48,7 +50,10 @@ type NodeMethod =
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class DynamicNodeParametersService {
|
export class DynamicNodeParametersService {
|
||||||
constructor(private nodeTypes: NodeTypes) {}
|
constructor(
|
||||||
|
private nodeTypes: NodeTypes,
|
||||||
|
private workflowLoaderService: WorkflowLoaderService,
|
||||||
|
) {}
|
||||||
|
|
||||||
/** Returns the available options via a predefined method */
|
/** Returns the available options via a predefined method */
|
||||||
async getOptionsViaMethodName(
|
async getOptionsViaMethodName(
|
||||||
|
@ -193,8 +198,7 @@ export class DynamicNodeParametersService {
|
||||||
): Promise<ResourceMapperFields> {
|
): Promise<ResourceMapperFields> {
|
||||||
const nodeType = this.getNodeType(nodeTypeAndVersion);
|
const nodeType = this.getNodeType(nodeTypeAndVersion);
|
||||||
const method = this.getMethod('localResourceMapping', methodName, nodeType);
|
const method = this.getMethod('localResourceMapping', methodName, nodeType);
|
||||||
const workflow = this.getWorkflow(nodeTypeAndVersion, currentNodeParameters, credentials);
|
const thisArgs = this.getLocalLoadOptionsContext(path, additionalData);
|
||||||
const thisArgs = this.getLocalLoadOptionsContext(path, additionalData, workflow);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
return method.call(thisArgs);
|
return method.call(thisArgs);
|
||||||
}
|
}
|
||||||
|
@ -297,12 +301,7 @@ export class DynamicNodeParametersService {
|
||||||
return new LoadOptionsContext(workflow, node, additionalData, path);
|
return new LoadOptionsContext(workflow, node, additionalData, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLocalLoadOptionsContext(
|
private getLocalLoadOptionsContext(path: string, additionalData: IWorkflowExecuteAdditionalData) {
|
||||||
path: string,
|
return new LocalLoadOptionsContext(additionalData, path, this.workflowLoaderService);
|
||||||
additionalData: IWorkflowExecuteAdditionalData,
|
|
||||||
workflow: Workflow,
|
|
||||||
) {
|
|
||||||
const node = workflow.nodes['Temp-Node'];
|
|
||||||
return new LocalLoadOptionsContext(workflow, node, additionalData, path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
packages/cli/src/services/workflow-loader.service.ts
Normal file
19
packages/cli/src/services/workflow-loader.service.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { ApplicationError, type IWorkflowBase, type IWorkflowLoader } from 'n8n-workflow';
|
||||||
|
import { Service } from 'typedi';
|
||||||
|
|
||||||
|
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class WorkflowLoaderService implements IWorkflowLoader {
|
||||||
|
constructor(private readonly workflowRepository: WorkflowRepository) {}
|
||||||
|
|
||||||
|
async get(workflowId: string): Promise<IWorkflowBase> {
|
||||||
|
const workflow = await this.workflowRepository.findById(workflowId);
|
||||||
|
|
||||||
|
if (!workflow) {
|
||||||
|
throw new ApplicationError(`Failed to find workflow with ID "${workflowId}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return workflow;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,33 +2,21 @@ import { get } from 'lodash';
|
||||||
import { ApplicationError } from 'n8n-workflow';
|
import { ApplicationError } from 'n8n-workflow';
|
||||||
import type {
|
import type {
|
||||||
INodeParameterResourceLocator,
|
INodeParameterResourceLocator,
|
||||||
IGetNodeParameterOptions,
|
|
||||||
INode,
|
|
||||||
IWorkflowExecuteAdditionalData,
|
IWorkflowExecuteAdditionalData,
|
||||||
NodeParameterValueType,
|
NodeParameterValueType,
|
||||||
Workflow,
|
|
||||||
ILocalLoadOptionsFunctions,
|
ILocalLoadOptionsFunctions,
|
||||||
FieldValueOption,
|
FieldValueOption,
|
||||||
|
IWorkflowLoader,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import { extractValue } from '@/ExtractValue';
|
export class LocalLoadOptionsContext implements ILocalLoadOptionsFunctions {
|
||||||
|
|
||||||
import { NodeExecutionContext } from './node-execution-context';
|
|
||||||
|
|
||||||
export class LocalLoadOptionsContext
|
|
||||||
extends NodeExecutionContext
|
|
||||||
implements ILocalLoadOptionsFunctions
|
|
||||||
{
|
|
||||||
constructor(
|
constructor(
|
||||||
workflow: Workflow,
|
private additionalData: IWorkflowExecuteAdditionalData,
|
||||||
node: INode,
|
private path: string,
|
||||||
additionalData: IWorkflowExecuteAdditionalData,
|
private workflowLoader: IWorkflowLoader,
|
||||||
private readonly path: string,
|
) {}
|
||||||
) {
|
|
||||||
super(workflow, node, additionalData, 'internal');
|
|
||||||
}
|
|
||||||
|
|
||||||
getWorkflowInputValues(): FieldValueOption[] {
|
async getWorkflowInputValues(): Promise<FieldValueOption[]> {
|
||||||
const { value } = this.getCurrentNodeParameter('workflowId') as INodeParameterResourceLocator;
|
const { value } = this.getCurrentNodeParameter('workflowId') as INodeParameterResourceLocator;
|
||||||
|
|
||||||
const workflowId = value as string;
|
const workflowId = value as string;
|
||||||
|
@ -36,6 +24,10 @@ export class LocalLoadOptionsContext
|
||||||
throw new ApplicationError('No workflowId parameter defined on node!');
|
throw new ApplicationError('No workflowId parameter defined on node!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const workflow = await this.workflowLoader.get(workflowId);
|
||||||
|
|
||||||
|
workflow.nodes.find((node) => node.type === 'n8n-nodes-base.start');
|
||||||
|
|
||||||
// TODO: load the inputs from the workflow
|
// TODO: load the inputs from the workflow
|
||||||
const dummyFields = [
|
const dummyFields = [
|
||||||
{ name: 'field1', type: 'string' as const },
|
{ name: 'field1', type: 'string' as const },
|
||||||
|
@ -47,31 +39,14 @@ export class LocalLoadOptionsContext
|
||||||
return dummyFields;
|
return dummyFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentNodeParameter(
|
getCurrentNodeParameter(parameterPath: string): NodeParameterValueType | object | undefined {
|
||||||
parameterPath: string,
|
|
||||||
options?: IGetNodeParameterOptions,
|
|
||||||
): NodeParameterValueType | object | undefined {
|
|
||||||
const nodeParameters = this.additionalData.currentNodeParameters;
|
const nodeParameters = this.additionalData.currentNodeParameters;
|
||||||
|
|
||||||
if (parameterPath.startsWith('&')) {
|
if (parameterPath.startsWith('&')) {
|
||||||
parameterPath = `${this.path.split('.').slice(1, -1).join('.')}.${parameterPath.slice(1)}`;
|
parameterPath = `${this.path.split('.').slice(1, -1).join('.')}.${parameterPath.slice(1)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let returnData = get(nodeParameters, parameterPath);
|
const returnData = get(nodeParameters, parameterPath);
|
||||||
|
|
||||||
// This is outside the try/catch because it throws errors with proper messages
|
|
||||||
if (options?.extractValue) {
|
|
||||||
const nodeType = this.workflow.nodeTypes.getByNameAndVersion(
|
|
||||||
this.node.type,
|
|
||||||
this.node.typeVersion,
|
|
||||||
);
|
|
||||||
returnData = extractValue(
|
|
||||||
returnData,
|
|
||||||
parameterPath,
|
|
||||||
this.node,
|
|
||||||
nodeType,
|
|
||||||
) as NodeParameterValueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type {
|
||||||
export async function getWorkflowInputs(
|
export async function getWorkflowInputs(
|
||||||
this: ILocalLoadOptionsFunctions,
|
this: ILocalLoadOptionsFunctions,
|
||||||
): Promise<ResourceMapperFields> {
|
): Promise<ResourceMapperFields> {
|
||||||
const workflowInputFields = this.getWorkflowInputValues() as FieldValueOption[];
|
const workflowInputFields = (await this.getWorkflowInputValues()) as FieldValueOption[];
|
||||||
|
|
||||||
const fields: ResourceMapperField[] = workflowInputFields.map((currentWorkflowInput) => {
|
const fields: ResourceMapperField[] = workflowInputFields.map((currentWorkflowInput) => {
|
||||||
const field: ResourceMapperField = {
|
const field: ResourceMapperField = {
|
||||||
|
|
|
@ -1073,7 +1073,11 @@ export interface ILoadOptionsFunctions extends FunctionsBase {
|
||||||
export type FieldValueOption = { name: string; type: FieldType | 'any' };
|
export type FieldValueOption = { name: string; type: FieldType | 'any' };
|
||||||
|
|
||||||
export interface ILocalLoadOptionsFunctions {
|
export interface ILocalLoadOptionsFunctions {
|
||||||
getWorkflowInputValues(): FieldValueOption[];
|
getWorkflowInputValues(): Promise<FieldValueOption[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWorkflowLoader {
|
||||||
|
get(workflowId: string): Promise<IWorkflowBase>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPollFunctions
|
export interface IPollFunctions
|
||||||
|
|
Loading…
Reference in a new issue