n8n
Version:
n8n Workflow Automation Tool
186 lines • 8.7 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkflowImporter = void 0;
exports.collectPlannedWorkflowBindings = collectPlannedWorkflowBindings;
const db_1 = require("@n8n/db");
const di_1 = require("@n8n/di");
const workflow_creation_service_1 = require("../../../../workflows/workflow-creation.service");
const workflow_service_1 = require("../../../../workflows/workflow.service");
const workflow_references_1 = require("./references/workflow-references");
const workflow_conflict_policy_1 = require("./workflow-conflict-policy");
const workflow_id_policy_1 = require("./workflow-id-policy");
const workflow_import_match_service_1 = require("./workflow-import-match.service");
let WorkflowImporter = class WorkflowImporter {
constructor(workflowImportMatchService, workflowCreationService, workflowService) {
this.workflowImportMatchService = workflowImportMatchService;
this.workflowCreationService = workflowCreationService;
this.workflowService = workflowService;
}
async plan(context, prepared, options) {
const existingBySourceWorkflowId = await this.workflowImportMatchService.findBySourceWorkflowIds(context.projectId, prepared.map(({ sourceWorkflowId }) => sourceWorkflowId));
const items = [];
const conflicts = [];
const folderConflicts = [];
const sourceCreateIds = [];
for (const workflow of prepared) {
const existing = existingBySourceWorkflowId.get(workflow.sourceWorkflowId) ?? null;
const { action, blocked } = (0, workflow_conflict_policy_1.decideWorkflowConflictAction)(options.workflowConflictPolicy, existing);
const item = toPlanItem(workflow, existing, action, options.workflowIdPolicy);
items.push(item);
if (item.action === 'create' && options.workflowIdPolicy === 'source' && !blocked) {
sourceCreateIds.push(item.decidedId);
}
if (blocked && existing) {
conflicts.push({
sourceWorkflowId: workflow.sourceWorkflowId,
existingWorkflowId: existing.id,
name: existing.name,
});
}
const targetFolderId = workflow.parentFolderId ?? context.folderId;
if (targetFolderId && existing) {
const existingParentFolderId = existing.parentFolder?.id ?? null;
if (existingParentFolderId !== targetFolderId) {
folderConflicts.push({
sourceWorkflowId: workflow.sourceWorkflowId,
existingWorkflowId: existing.id,
existingParentFolderId,
targetFolderId,
name: existing.name,
});
}
}
}
const idConflicts = await this.collectIdConflicts(sourceCreateIds);
return { items, conflicts, idConflicts, folderConflicts };
}
async collectIdConflicts(candidateIds) {
const existing = await this.workflowImportMatchService.findOwningProjectsByWorkflowId(candidateIds);
return candidateIds.flatMap((id) => {
const location = existing.get(id);
if (!location)
return [];
return [
{
sourceWorkflowId: id,
existingWorkflowId: id,
existingProjectId: location.projectId,
isArchived: location.isArchived,
name: location.name,
},
];
});
}
async apply(context, plan, bindings) {
const workflowBindings = new Map([
...bindings.workflows,
...collectPlannedWorkflowBindings(plan.items),
]);
const resolvedBindings = { ...bindings, workflows: workflowBindings };
const outcomes = [];
for (const item of plan.items) {
outcomes.push(await this.applyItem(context, item, resolvedBindings));
}
return { outcomes, bindings: resolvedBindings };
}
async applyItem(context, item, bindings) {
if (item.action === 'skip') {
return {
status: 'skipped',
workflow: item.existing,
sourceWorkflowId: item.sourceWorkflowId,
};
}
return {
status: item.action === 'create' ? 'created' : 'updated',
workflow: await this.persistWorkflow(context, item, bindings),
sourceWorkflowId: item.sourceWorkflowId,
item,
};
}
async persistWorkflow(context, item, bindings) {
const tagIds = item.tagIds && [...new Set(item.tagIds)].filter((id) => !context.droppedTagIds.has(id));
if (item.action === 'create') {
const entity = prepareEntityForPersist(item.entity, bindings, item.decidedId);
return await this.workflowCreationService.createWorkflow(context.user, entity, {
projectId: context.projectId,
parentFolderId: item.parentFolderId ?? context.folderId ?? undefined,
publicApi: true,
source: 'import',
sourceWorkflowId: item.sourceWorkflowId,
...(tagIds !== undefined ? { tagIds } : {}),
});
}
const entity = prepareEntityForPersist(item.entity, bindings);
return await this.workflowService.update(context.user, entity, item.existing.id, {
publicApi: true,
source: 'import',
...(tagIds !== undefined ? { tagIds } : {}),
});
}
};
exports.WorkflowImporter = WorkflowImporter;
exports.WorkflowImporter = WorkflowImporter = __decorate([
(0, di_1.Service)(),
__metadata("design:paramtypes", [workflow_import_match_service_1.WorkflowImportMatchService, workflow_creation_service_1.WorkflowCreationService, workflow_service_1.WorkflowService])
], WorkflowImporter);
function planItemTargetId(item) {
return item.action === 'create' ? item.decidedId : item.existing.id;
}
function collectPlannedWorkflowBindings(items) {
return new Map(items.map((item) => [item.sourceWorkflowId, planItemTargetId(item)]));
}
function prepareEntityForPersist(source, bindings, decidedId) {
const entity = Object.assign(new db_1.WorkflowEntity(), source, {
nodes: structuredClone(source.nodes),
...(source.settings ? { settings: structuredClone(source.settings) } : {}),
...(decidedId !== undefined ? { id: decidedId } : {}),
});
applyCredentialBindingsInPlace(entity, bindings.credentials);
for (const reference of workflow_references_1.workflowReferences)
reference.apply(entity, bindings);
return entity;
}
function applyCredentialBindingsInPlace(entity, credentialBindings) {
for (const node of entity.nodes) {
for (const details of Object.values(node.credentials ?? {})) {
if (!details.id)
continue;
const targetId = credentialBindings.get(details.id);
if (targetId) {
details.id = targetId;
}
}
}
}
function toPlanItem(prepared, existing, action, idPolicy) {
if (existing === null) {
return {
action: 'create',
decidedId: (0, workflow_id_policy_1.decideWorkflowId)(idPolicy, prepared.sourceWorkflowId),
...prepared,
};
}
switch (action) {
case 'update':
return { action, ...prepared, existing };
case 'skip':
return { action, ...prepared, existing };
case 'create':
return {
action,
decidedId: (0, workflow_id_policy_1.decideWorkflowId)(idPolicy, prepared.sourceWorkflowId),
...prepared,
};
}
}
//# sourceMappingURL=workflow-importer.js.map