mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +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:
@@ -257,23 +257,103 @@ describe('Workflow Actions', () => {
|
||||
}).as('loadWorkflows');
|
||||
});
|
||||
|
||||
it('should not be able to delete unsaved workflow', () => {
|
||||
it('should not be able to archive or delete unsaved workflow', () => {
|
||||
WorkflowPage.getters.workflowMenu().should('be.visible');
|
||||
WorkflowPage.getters.workflowMenu().click();
|
||||
WorkflowPage.getters.workflowMenuItemDelete().closest('li').should('have.class', 'is-disabled');
|
||||
WorkflowPage.getters.workflowMenuItemDelete().should('not.exist');
|
||||
WorkflowPage.getters
|
||||
.workflowMenuItemArchive()
|
||||
.closest('li')
|
||||
.should('have.class', 'is-disabled');
|
||||
});
|
||||
|
||||
it('should delete workflow', () => {
|
||||
it('should archive workflow and then delete it', () => {
|
||||
WorkflowPage.actions.saveWorkflowOnButtonClick();
|
||||
WorkflowPage.getters.archivedTag().should('not.exist');
|
||||
|
||||
// Archive the workflow
|
||||
WorkflowPage.getters.workflowMenu().should('be.visible');
|
||||
WorkflowPage.getters.workflowMenu().click();
|
||||
WorkflowPage.getters.workflowMenuItemArchive().click();
|
||||
WorkflowPage.actions.acceptConfirmModal();
|
||||
|
||||
successToast().should('exist');
|
||||
cy.url().should('include', WorkflowPages.url);
|
||||
|
||||
// Return back to the workflow
|
||||
cy.go('back');
|
||||
|
||||
WorkflowPage.getters.archivedTag().should('be.visible');
|
||||
WorkflowPage.getters.nodeCreatorPlusButton().should('not.exist');
|
||||
|
||||
// Delete the workflow
|
||||
WorkflowPage.getters.workflowMenu().should('be.visible');
|
||||
WorkflowPage.getters.workflowMenu().click();
|
||||
WorkflowPage.getters.workflowMenuItemDelete().click();
|
||||
cy.get('div[role=dialog][aria-modal=true]').should('be.visible');
|
||||
cy.get('button.btn--confirm').should('be.visible').click();
|
||||
WorkflowPage.actions.acceptConfirmModal();
|
||||
successToast().should('exist');
|
||||
cy.url().should('include', WorkflowPages.url);
|
||||
});
|
||||
|
||||
it('should archive workflow and then unarchive it', () => {
|
||||
WorkflowPage.actions.saveWorkflowOnButtonClick();
|
||||
WorkflowPage.getters.archivedTag().should('not.exist');
|
||||
|
||||
// Archive the workflow
|
||||
WorkflowPage.getters.workflowMenu().should('be.visible');
|
||||
WorkflowPage.getters.workflowMenu().click();
|
||||
WorkflowPage.getters.workflowMenuItemArchive().click();
|
||||
WorkflowPage.actions.acceptConfirmModal();
|
||||
successToast().should('exist');
|
||||
cy.url().should('include', WorkflowPages.url);
|
||||
|
||||
// Return back to the workflow
|
||||
cy.go('back');
|
||||
|
||||
WorkflowPage.getters.archivedTag().should('be.visible');
|
||||
WorkflowPage.getters.nodeCreatorPlusButton().should('not.exist');
|
||||
|
||||
// Unarchive the workflow
|
||||
WorkflowPage.getters.workflowMenu().should('be.visible');
|
||||
WorkflowPage.getters.workflowMenu().click();
|
||||
WorkflowPage.getters.workflowMenuItemUnarchive().click();
|
||||
successToast().should('exist');
|
||||
WorkflowPage.getters.archivedTag().should('not.exist');
|
||||
WorkflowPage.getters.nodeCreatorPlusButton().should('be.visible');
|
||||
});
|
||||
|
||||
it('should deactivate active workflow on archive', () => {
|
||||
WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
|
||||
WorkflowPage.actions.saveWorkflowOnButtonClick();
|
||||
WorkflowPage.actions.activateWorkflow();
|
||||
WorkflowPage.getters.isWorkflowActivated();
|
||||
|
||||
// Archive the workflow
|
||||
WorkflowPage.getters.workflowMenu().click();
|
||||
WorkflowPage.getters.workflowMenuItemArchive().click();
|
||||
WorkflowPage.actions.acceptConfirmModal();
|
||||
successToast().should('exist');
|
||||
cy.url().should('include', WorkflowPages.url);
|
||||
|
||||
// Return back to the workflow
|
||||
cy.go('back');
|
||||
|
||||
WorkflowPage.getters.archivedTag().should('be.visible');
|
||||
WorkflowPage.getters.isWorkflowDeactivated();
|
||||
WorkflowPage.getters.activatorSwitch().find('input').first().should('be.disabled');
|
||||
|
||||
// Unarchive the workflow
|
||||
WorkflowPage.getters.workflowMenu().should('be.visible');
|
||||
WorkflowPage.getters.workflowMenu().click();
|
||||
WorkflowPage.getters.workflowMenuItemUnarchive().click();
|
||||
successToast().should('exist');
|
||||
WorkflowPage.getters.archivedTag().should('not.exist');
|
||||
|
||||
// Activate the workflow again
|
||||
WorkflowPage.actions.activateWorkflow();
|
||||
WorkflowPage.getters.isWorkflowActivated();
|
||||
});
|
||||
|
||||
describe('duplicate workflow', () => {
|
||||
function duplicateWorkflow() {
|
||||
WorkflowPage.getters.workflowMenu().should('be.visible');
|
||||
|
||||
Reference in New Issue
Block a user