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:
Jaakko Husso
2025-05-06 17:48:24 +03:00
committed by GitHub
parent 32b72011e6
commit 3a13139f78
64 changed files with 1616 additions and 124 deletions

View File

@@ -84,6 +84,8 @@ export class WorkflowPage extends BasePage {
firstStepButton: () => cy.getByTestId('canvas-add-button'),
isWorkflowSaved: () => this.getters.saveButton().should('match', 'span'), // In Element UI, disabled button turn into spans 🤷‍♂️
isWorkflowActivated: () => this.getters.activatorSwitch().should('have.class', 'is-checked'),
isWorkflowDeactivated: () =>
this.getters.activatorSwitch().should('not.have.class', 'is-checked'),
expressionModalInput: () => cy.getByTestId('expression-modal-input').find('[role=textbox]'),
expressionModalOutput: () => cy.getByTestId('expression-modal-output'),
@@ -117,6 +119,8 @@ export class WorkflowPage extends BasePage {
workflowMenuItemImportFromFile: () => cy.getByTestId('workflow-menu-item-import-from-file'),
workflowMenuItemSettings: () => cy.getByTestId('workflow-menu-item-settings'),
workflowMenuItemDelete: () => cy.getByTestId('workflow-menu-item-delete'),
workflowMenuItemArchive: () => cy.getByTestId('workflow-menu-item-archive'),
workflowMenuItemUnarchive: () => cy.getByTestId('workflow-menu-item-unarchive'),
workflowMenuItemGitPush: () => cy.getByTestId('workflow-menu-item-push'),
// Workflow settings dialog elements
workflowSettingsModal: () => cy.getByTestId('workflow-settings-dialog'),
@@ -136,6 +140,7 @@ export class WorkflowPage extends BasePage {
workflowSettingsSaveButton: () =>
cy.getByTestId('workflow-settings-save-button').find('button'),
archivedTag: () => cy.getByTestId('workflow-archived-tag'),
shareButton: () => cy.getByTestId('workflow-share-button'),
duplicateWorkflowModal: () => cy.getByTestId('duplicate-modal'),
@@ -214,6 +219,7 @@ export class WorkflowPage extends BasePage {
}
return parseFloat(element.css('top'));
},
confirmModal: () => cy.get('div[role=dialog][aria-modal=true]'),
};
actions = {
@@ -551,5 +557,9 @@ export class WorkflowPage extends BasePage {
top: +$el[0].style.top.replace('px', ''),
}));
},
acceptConfirmModal: () => {
this.getters.confirmModal().should('be.visible');
cy.get('button.btn--confirm').should('be.visible').click();
},
};
}