mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 10:31:15 +00:00
feat(core): Change workflow deletions to soft deletes (#14894)
Adds soft‑deletion support for workflows through a new boolean column `isArchived`. When a workflow is archived we now set `isArchived` flag to true and the workflows stays in the database and is omitted from the default workflow listing query. Archived workflows can be viewed in read-only mode, but they cannot be activated. Archived workflows are still available by ID and can be invoked as sub-executions, so existing Execute Workflow nodes continue to work. Execution engine doesn't care about isArchived flag. Users can restore workflows via Unarchive action at the UI.
This commit is contained in:
@@ -310,7 +310,14 @@ export class SourceControlImportService {
|
||||
continue;
|
||||
}
|
||||
const existingWorkflow = existingWorkflows.find((e) => e.id === importedWorkflow.id);
|
||||
importedWorkflow.active = existingWorkflow?.active ?? false;
|
||||
|
||||
// Workflow's active status is not saved in the remote workflow files, and the field is missing despite
|
||||
// IWorkflowToImport having it typed as boolean. Imported workflows are always inactive if they are new,
|
||||
// and existing workflows use the existing workflow's active status unless they have been archived on the remote.
|
||||
// In that case, we deactivate the existing workflow on pull and turn it archived.
|
||||
importedWorkflow.active = existingWorkflow
|
||||
? existingWorkflow.active && !importedWorkflow.isArchived
|
||||
: false;
|
||||
|
||||
const parentFolderId = importedWorkflow.parentFolderId ?? '';
|
||||
|
||||
@@ -353,14 +360,17 @@ export class SourceControlImportService {
|
||||
// remove active pre-import workflow
|
||||
this.logger.debug(`Deactivating workflow id ${existingWorkflow.id}`);
|
||||
await workflowManager.remove(existingWorkflow.id);
|
||||
// try activating the imported workflow
|
||||
this.logger.debug(`Reactivating workflow id ${existingWorkflow.id}`);
|
||||
await workflowManager.add(existingWorkflow.id, 'activate');
|
||||
// update the versionId of the workflow to match the imported workflow
|
||||
|
||||
if (importedWorkflow.active) {
|
||||
// try activating the imported workflow
|
||||
this.logger.debug(`Reactivating workflow id ${existingWorkflow.id}`);
|
||||
await workflowManager.add(existingWorkflow.id, 'activate');
|
||||
}
|
||||
} catch (e) {
|
||||
const error = ensureError(e);
|
||||
this.logger.error(`Failed to activate workflow ${existingWorkflow.id}`, { error });
|
||||
} finally {
|
||||
// update the versionId of the workflow to match the imported workflow
|
||||
await this.workflowRepository.update(
|
||||
{ id: existingWorkflow.id },
|
||||
{ versionId: importedWorkflow.versionId },
|
||||
@@ -639,7 +649,7 @@ export class SourceControlImportService {
|
||||
|
||||
async deleteWorkflowsNotInWorkfolder(user: User, candidates: SourceControlledFile[]) {
|
||||
for (const candidate of candidates) {
|
||||
await this.workflowService.delete(user, candidate.id);
|
||||
await this.workflowService.delete(user, candidate.id, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user