From c0c36b6bb2719c60ab82f68651dbb5e7dc9cc981 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 3 Mar 2023 10:29:59 +0100 Subject: [PATCH 01/23] fix(editor): Fix execution list item selection --- .../src/components/ExecutionsList.vue | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index b890db34ce9d5..b8b9fb950d4b1 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -40,12 +40,7 @@ - + {{ $locale.baseText('executionsList.name') }} {{ $locale.baseText('executionsList.startedAt') }} @@ -229,7 +224,7 @@
{{ $locale.baseText('executionsList.loadedAll') }}
-
+
{{ $locale.baseText('executionsList.selected', { interpolate: { numSelected } }) }} @@ -261,10 +256,9 @@ import { IExecutionsCurrentSummaryExtended, IExecutionDeleteFilter, IExecutionsListResponse, - IExecutionsSummary, IWorkflowShortResponse, } from '@/Interface'; -import type { ExecutionStatus, IDataObject } from 'n8n-workflow'; +import type { IExecutionsSummary, ExecutionStatus, IDataObject } from 'n8n-workflow'; import { range as _range } from 'lodash-es'; import mixins from 'vue-typed-mixins'; import { mapStores } from 'pinia'; @@ -353,7 +347,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, return this.workflowsStore.activeExecutions; }, combinedExecutions(): IExecutionsSummary[] { - const returnData: IExecutionsSummary[] = []; + const returnData = []; if (['ALL', 'running'].includes(this.filter.status)) { returnData.push(...this.activeExecutions); @@ -363,23 +357,9 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, } return returnData; }, - combinedExecutionsCount(): number { - return 0 + this.activeExecutions.length + this.finishedExecutionsCount; - }, numSelected(): number { - if (this.checkAll) { - return this.finishedExecutionsCount; - } - return Object.keys(this.selectedItems).length; }, - isIndeterminate(): boolean { - if (this.checkAll) { - return false; - } - - return this.numSelected > 0; - }, workflowFilterCurrent(): IDataObject { const filter: IDataObject = {}; if (this.filter.workflowId !== 'ALL') { @@ -435,8 +415,13 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, } }, handleCheckAllChange() { + this.checkAll = !this.checkAll; if (!this.checkAll) { Vue.set(this, 'selectedItems', {}); + } else { + this.combinedExecutions.forEach((execution: IExecutionsSummary) => { + Vue.set(this.selectedItems, execution.id, true); + }); } }, handleCheckboxChanged(executionId: string) { @@ -445,6 +430,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, } else { Vue.set(this.selectedItems, executionId, true); } + this.checkAll = Object.keys(this.selectedItems).length === this.combinedExecutions.length; }, async handleDeleteSelected() { const deleteExecutions = await this.confirmMessage( From 811dd6ab98d3791976fd88e7024ca8e0f39e9380 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 3 Mar 2023 10:40:48 +0100 Subject: [PATCH 02/23] fix(editor): Delete only selected executions --- packages/editor-ui/src/components/ExecutionsList.vue | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index b8b9fb950d4b1..424dfc1cc7605 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -450,11 +450,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.isDataLoading = true; const sendData: IExecutionDeleteFilter = {}; - if (this.checkAll) { - sendData.deleteBefore = this.finishedExecutions[0].startedAt as Date; - } else { - sendData.ids = Object.keys(this.selectedItems); - } + sendData.ids = Object.keys(this.selectedItems); sendData.filters = this.workflowFilterPast; From 6db282c6b799350f89fae5e2e792b12f9e5bacb5 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 3 Mar 2023 10:42:06 +0100 Subject: [PATCH 03/23] fix(editor): Fix clear selection --- packages/editor-ui/src/components/ExecutionsList.vue | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 424dfc1cc7605..6db3e4fe90ca8 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -236,7 +236,7 @@
@@ -516,10 +516,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.refreshData(); }, - handleClearSelection() { - this.checkAll = false; - this.handleCheckAllChange(); - }, handleFilterChanged() { this.refreshData(); }, From c74e16c4e1d82668287ed3ba8f50d386451557a0 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 3 Mar 2023 10:44:49 +0100 Subject: [PATCH 04/23] fix(editor): Fix clear selection --- packages/editor-ui/src/components/ExecutionsList.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 6db3e4fe90ca8..d7bb742f453fe 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -236,7 +236,7 @@ @@ -516,6 +516,10 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.refreshData(); }, + handleClearSelection() { + this.checkAll = true; + this.handleCheckAllChange(); + }, handleFilterChanged() { this.refreshData(); }, From b0927933e24cfa8f390f7faf85b488413829be6c Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 3 Mar 2023 10:46:47 +0100 Subject: [PATCH 05/23] fix(editor): Fix clear selection --- packages/editor-ui/src/components/ExecutionsList.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index d7bb742f453fe..a17256693954c 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -517,8 +517,8 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.refreshData(); }, handleClearSelection() { - this.checkAll = true; - this.handleCheckAllChange(); + this.checkAll = false; + Vue.set(this, 'selectedItems', {}); }, handleFilterChanged() { this.refreshData(); From 6780c63b0fadd43a20191cf4d8c634bbeca12e0b Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Tue, 7 Mar 2023 17:09:57 +0100 Subject: [PATCH 06/23] feat(editor): Add select all existing executions checkbox --- .../src/components/ExecutionsList.vue | 86 +++++++++++++++---- .../src/plugins/i18n/locales/en.json | 3 +- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index a17256693954c..5b0d0431eae3b 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -36,11 +36,28 @@
+ + @@ -61,7 +78,7 @@ {}, + }; + }, + }); + Object.defineProperty(vue.prototype, '$telemetry', { + get() { + return { + track: () => {}, + }; + }, + }); +} + +const renderComponent = () => + render(ExecutionsList, renderOptions, (vue) => { + vue.use(TelemetryPlugin); + vue.use(PiniaVuePlugin); + vue.use((vue) => I18nPlugin(vue)); + }); + +describe('ExecutionsList.vue', () => { + it('renders list', async () => { + const { getAllByTestId } = renderComponent(); + await new Promise((resolve) => setTimeout(resolve)); + expect(getAllByTestId('execution-data-row').length).toBe(executionsData.results.length); + }); +}); From fc9dcb939906c74f8e42bfa065464fff934e0e4c Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Thu, 9 Mar 2023 13:29:12 +0100 Subject: [PATCH 09/23] fix(editor): Fix selection --- .../src/components/ExecutionsList.vue | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 1357717802f1b..5b53d268bcddd 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -37,7 +37,7 @@ @@ -453,9 +453,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.allExistingSelected = false; Vue.set(this, 'selectedItems', {}); } else { - this.combinedExecutions.forEach((execution: IExecutionsSummary) => { - Vue.set(this.selectedItems, execution.id, true); - }); + this.selectAllVisibleExecutions(); } }, handleCheckboxChanged(executionId: string) { @@ -692,6 +690,8 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, Vue.set(this, 'finishedExecutions', alreadyPresentExecutionsFiltered); this.workflowsStore.addToCurrentExecutions(alreadyPresentExecutionsFiltered); + + this.adjustSelectionAfterMoreItemsLoaded(); }, async loadFinishedExecutions(): Promise { if (this.filter.status === 'running') { @@ -750,6 +750,8 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.isDataLoading = false; this.workflowsStore.addToCurrentExecutions(data.results); + + this.adjustSelectionAfterMoreItemsLoaded(); }, async loadWorkflows() { try { @@ -960,6 +962,17 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, isRunning(execution: IExecutionsSummary): boolean { return this.getStatus(execution) === 'running'; }, + selectAllVisibleExecutions() { + this.combinedExecutions.forEach((execution: IExecutionsSummary) => { + Vue.set(this.selectedItems, execution.id, true); + }); + }, + adjustSelectionAfterMoreItemsLoaded() { + if (this.allExistingSelected) { + this.allVisibleSelected = true; + this.selectAllVisibleExecutions(); + } + }, }, }, ); From 920863c752aa6a42acad01eb1eb5fa6bf6975454 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Thu, 9 Mar 2023 15:38:31 +0100 Subject: [PATCH 10/23] test(editor): update execution selection test --- .../src/components/ExecutionsList.vue | 13 +- .../__tests__/ExecutionsList.test.ts | 177 ++++++++++++++++-- 2 files changed, 175 insertions(+), 15 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 5b53d268bcddd..19dc60eedf583 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -47,6 +47,7 @@ " :value="allExistingSelected" @change="handleCheckAllExistingChange" + data-testid="select-all-executions-checkbox" />
- + {{ $locale.baseText('executionsList.name') }} {{ $locale.baseText('executionsList.startedAt') }} @@ -226,7 +243,12 @@
- {{ $locale.baseText('executionsList.selected', { interpolate: { numSelected } }) }} + {{ + $locale.baseText('executionsList.selected', { + adjustToNumber: numSelected, + interpolate: { numSelected }, + }) + }} this.loadAutoRefresh(), 4 * 1000); // refresh data every 4 secs } }, - handleCheckAllChange() { - this.checkAll = !this.checkAll; - if (!this.checkAll) { + handleCheckAllExistingChange() { + this.allExistingSelected = !this.allExistingSelected; + this.allVisibleSelected = !this.allExistingSelected; + this.handleCheckAllVisibleChange(); + }, + handleCheckAllVisibleChange() { + this.allVisibleSelected = !this.allVisibleSelected; + if (!this.allVisibleSelected) { + this.allExistingSelected = false; Vue.set(this, 'selectedItems', {}); } else { - this.combinedExecutions.forEach((execution: IExecutionsSummary) => { - Vue.set(this.selectedItems, execution.id, true); - }); + this.selectCombinedExecutions(); } }, handleCheckboxChanged(executionId: string) { @@ -430,7 +461,10 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, } else { Vue.set(this.selectedItems, executionId, true); } - this.checkAll = Object.keys(this.selectedItems).length === this.combinedExecutions.length; + this.allVisibleSelected = + Object.keys(this.selectedItems).length === this.combinedExecutions.length; + this.allExistingSelected = + Object.keys(this.selectedItems).length === this.finishedExecutionsCount; }, async handleDeleteSelected() { const deleteExecutions = await this.confirmMessage( @@ -450,7 +484,11 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.isDataLoading = true; const sendData: IExecutionDeleteFilter = {}; - sendData.ids = Object.keys(this.selectedItems); + if (this.allExistingSelected) { + sendData.deleteBefore = this.finishedExecutions[0].startedAt as Date; + } else { + sendData.ids = Object.keys(this.selectedItems); + } sendData.filters = this.workflowFilterPast; @@ -512,12 +550,13 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, }); Vue.set(this, 'selectedItems', {}); - this.checkAll = false; + this.allVisibleSelected = false; this.refreshData(); }, handleClearSelection() { - this.checkAll = false; + this.allVisibleSelected = false; + this.allExistingSelected = false; Vue.set(this, 'selectedItems', {}); }, handleFilterChanged() { @@ -705,6 +744,10 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.finishedExecutionsCount = data.count; this.finishedExecutionsCountEstimated = data.estimated; + if (this.allVisibleSelected) { + this.selectCombinedExecutions(); + } + this.isDataLoading = false; this.workflowsStore.addToCurrentExecutions(data.results); @@ -918,6 +961,11 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, isRunning(execution: IExecutionsSummary): boolean { return this.getStatus(execution) === 'running'; }, + selectCombinedExecutions() { + this.combinedExecutions.forEach((execution: IExecutionsSummary) => { + Vue.set(this.selectedItems, execution.id, true); + }); + }, }, }, ); @@ -951,7 +999,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, z-index: 2; left: 50%; transform: translateX(-50%); - bottom: var(--spacing-xl); + bottom: var(--spacing-3xl); background: var(--color-background-dark); border-radius: var(--border-radius-base); color: var(--color-text-xlight); @@ -1123,7 +1171,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, } .loadMore { - margin: var(--spacing-l) 0; + margin: var(--spacing-m) 0; width: 100%; text-align: center; } @@ -1141,4 +1189,10 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, .retryAction + .deleteAction { border-top: 1px solid var(--color-foreground-light); } + +.selectAll { + display: inline-block; + margin: 0 0 var(--spacing-s) var(--spacing-s); + color: var(--color-danger); +} diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index 166cf93e4dec3..770c094182778 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -471,7 +471,8 @@ "executionsList.succeeded": "Succeeded", "executionsList.selectStatus": "Select Status", "executionsList.selectWorkflow": "Select Workflow", - "executionsList.selected": "{numSelected} execution selected:", + "executionsList.selected": "{numSelected} execution selected: | {numSelected} executions selected:", + "executionsList.selectAll": "Select {executionNum} finished execution | Select all {executionNum} finished executions", "executionsList.test": "Test execution", "executionsList.showError.handleDeleteSelected.title": "Problem deleting executions", "executionsList.showError.loadMore.title": "Problem loading executions", From 97009038ba13ca5883d565e861a27eb2805653af Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Tue, 7 Mar 2023 21:45:42 +0100 Subject: [PATCH 07/23] fix(editor): Do not mark later loaded executions selected --- .../editor-ui/src/components/ExecutionsList.vue | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 5b0d0431eae3b..1b8095d519295 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -78,7 +78,7 @@
@@ -452,7 +452,9 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.allExistingSelected = false; Vue.set(this, 'selectedItems', {}); } else { - this.selectCombinedExecutions(); + this.combinedExecutions.forEach((execution: IExecutionsSummary) => { + Vue.set(this.selectedItems, execution.id, true); + }); } }, handleCheckboxChanged(executionId: string) { @@ -744,10 +746,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.finishedExecutionsCount = data.count; this.finishedExecutionsCountEstimated = data.estimated; - if (this.allVisibleSelected) { - this.selectCombinedExecutions(); - } - this.isDataLoading = false; this.workflowsStore.addToCurrentExecutions(data.results); @@ -961,11 +959,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, isRunning(execution: IExecutionsSummary): boolean { return this.getStatus(execution) === 'running'; }, - selectCombinedExecutions() { - this.combinedExecutions.forEach((execution: IExecutionsSummary) => { - Vue.set(this.selectedItems, execution.id, true); - }); - }, }, }, ); From cfe478580a0ffcebfcd4848edd7ab8a40a6e1c3f Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Thu, 9 Mar 2023 06:36:09 +0100 Subject: [PATCH 08/23] test(editor): Add execution list unit test --- .../src/components/ExecutionsList.vue | 1 + .../__tests__/ExecutionsList.test.ts | 444 ++++++++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 1b8095d519295..1357717802f1b 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -71,6 +71,7 @@
@@ -57,6 +58,7 @@ :value="allVisibleSelected" @change="handleCheckAllVisibleChange" label="" + data-testid="select-visible-executions-checkbox" /> @@ -71,7 +73,6 @@
{{ $locale.baseText('executionsList.name') }}
@@ -238,11 +240,16 @@ :label="$locale.baseText('executionsList.loadMore')" @click="loadMore()" :loading="isDataLoading" + data-testid="load-more-button" />
{{ $locale.baseText('executionsList.loadedAll') }}
-
+
{{ $locale.baseText('executionsList.selected', { @@ -255,11 +262,13 @@ :label="$locale.baseText('generic.delete')" type="tertiary" @click="handleDeleteSelected" + data-testid="delete-selected-button" />
diff --git a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts index 2804f0f6e0643..ee73f1ea565c7 100644 --- a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts +++ b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts @@ -1,7 +1,8 @@ +import { vi, describe, it, expect, afterEach } from 'vitest'; import Vue from 'vue'; import { PiniaVuePlugin } from 'pinia'; import { createTestingPinia } from '@pinia/testing'; -import { render, cleanup } from '@testing-library/vue'; +import { render, cleanup, fireEvent } from '@testing-library/vue'; import { STORES } from '@/constants'; import ExecutionsList from '@/components/ExecutionsList.vue'; import { externalHooks } from '@/mixins/externalHooks'; @@ -375,19 +376,145 @@ const executionsData = { estimated: false, }; +const executionsData2 = { + data: { + count: 239, + results: [ + { + id: '28791', + finished: false, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-14T10:58:51.615Z', + stoppedAt: '2023-02-14T10:58:52.853Z', + workflowId: '1037', + workflowName: 'Manual wait set', + status: 'failed', + nodeExecutionStatus: {}, + }, + { + id: '28790', + finished: false, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-14T10:58:48.134Z', + stoppedAt: '2023-02-14T10:58:48.740Z', + workflowId: '1037', + workflowName: 'Manual wait set', + status: 'failed', + nodeExecutionStatus: {}, + }, + { + id: '28789', + finished: false, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-14T10:46:57.863Z', + stoppedAt: '2023-02-14T10:46:58.786Z', + workflowId: '1037', + workflowName: 'Manual wait set', + status: 'failed', + nodeExecutionStatus: {}, + }, + { + id: '28788', + finished: true, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-14T10:46:28.168Z', + stoppedAt: '2023-02-14T10:46:30.193Z', + workflowId: '1037', + workflowName: 'Manual wait set', + status: 'success', + nodeExecutionStatus: {}, + }, + { + id: '28787', + finished: false, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-14T10:46:00.194Z', + stoppedAt: '2023-02-14T10:46:01.016Z', + workflowId: '1037', + workflowName: 'Manual wait set', + status: 'failed', + nodeExecutionStatus: {}, + }, + { + id: '28786', + finished: false, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-14T10:45:48.263Z', + stoppedAt: '2023-02-14T10:45:49.129Z', + workflowId: '1037', + workflowName: 'Manual wait set', + status: 'failed', + nodeExecutionStatus: {}, + }, + { + id: '28785', + finished: false, + mode: 'own', + waitTill: null, + startedAt: '2023-02-14T10:45:35.390Z', + stoppedAt: '2023-02-14T10:45:35.391Z', + workflowId: '1037', + workflowName: 'Manual wait set', + status: 'failed', + nodeExecutionStatus: {}, + }, + { + id: '28782', + finished: true, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-14T09:55:03.561Z', + stoppedAt: '2023-02-14T09:55:05.591Z', + workflowId: '1037', + workflowName: 'Manual long running', + status: 'success', + nodeExecutionStatus: {}, + }, + { + id: '28781', + finished: true, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-10T11:18:56.590Z', + stoppedAt: '2023-02-10T11:18:59.181Z', + workflowId: '1037', + workflowName: 'Manual long running', + status: 'success', + nodeExecutionStatus: {}, + }, + { + id: '28780', + finished: true, + mode: 'manual', + waitTill: null, + startedAt: '2023-02-10T11:17:25.837Z', + stoppedAt: '2023-02-10T11:17:28.428Z', + workflowId: '1037', + workflowName: 'Manual long running', + status: 'success', + nodeExecutionStatus: {}, + }, + ], + estimated: false, + }, +}; + const mockRestApiMixin = Vue.extend({ methods: { restApi() { return { - getWorkflows() { - return Promise.resolve(workflowsData); - }, - getCurrentExecutions() { - return Promise.resolve([]); - }, - getPastExecutions() { - return Promise.resolve(executionsData); - }, + getWorkflows: vi.fn().mockResolvedValue(workflowsData), + getCurrentExecutions: vi.fn().mockResolvedValue([]), + getPastExecutions: vi + .fn() + .mockResolvedValueOnce(executionsData) + .mockResolvedValueOnce(executionsData2), }; }, }, @@ -436,9 +563,33 @@ const renderComponent = () => }); describe('ExecutionsList.vue', () => { - it('renders list', async () => { - const { getAllByTestId } = renderComponent(); + afterEach(cleanup); + + it('should handle visible executions selection properly', async () => { + const { getAllByTestId, getByTestId } = renderComponent(); + // wait for all previous promises to make sure the component is fully rendered await new Promise((resolve) => setTimeout(resolve)); - expect(getAllByTestId('execution-data-row').length).toBe(executionsData.results.length); + + const itemCheckboxes = getAllByTestId('select-execution-checkbox'); + expect(itemCheckboxes.length).toBe(executionsData.results.length); + + await fireEvent.click(getByTestId('select-visible-executions-checkbox')); + + expect(itemCheckboxes.filter((el) => el.contains(el.querySelector(':checked'))).length).toBe( + executionsData.results.length, + ); + expect(getByTestId('selected-executions-info').textContent).toContain( + executionsData.results.length, + ); + + const firstCheckbox = itemCheckboxes[0]; + await fireEvent.click(firstCheckbox); + + expect(itemCheckboxes.filter((el) => el.contains(el.querySelector(':checked'))).length).toBe( + executionsData.results.length - 1, + ); + expect(getByTestId('selected-executions-info').textContent).toContain( + executionsData.results.length - 1, + ); }); }); From 50c1051b08c654f4f781409bdcbb02f20bad4334 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 10 Mar 2023 13:15:17 +0100 Subject: [PATCH 11/23] fix(editor): Handle UI state when there is no execution --- .../editor-ui/src/components/ExecutionsList.vue | 17 ++++++++++++----- .../editor-ui/src/plugins/i18n/locales/en.json | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 9cc9cf9100bd2..8df11b6ea5743 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -228,9 +228,16 @@
+
+ {{ $locale.baseText('executionsList.empty') }} +
finishedExecutions.length || finishedExecutionsCountEstimated " > @@ -243,7 +250,9 @@ data-testid="load-more-button" />
-
{{ $locale.baseText('executionsList.loadedAll') }}
+
+ {{ $locale.baseText('executionsList.loadedAll') }} +
Date: Fri, 10 Mar 2023 13:15:44 +0100 Subject: [PATCH 12/23] fix(editor): Remove unnecessary logic --- .../src/components/ExecutionsList.vue | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 8df11b6ea5743..8f7706bf0e985 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -513,45 +513,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, try { await this.restApi().deleteExecutions(sendData); - let removedCurrentlyLoadedExecution = false; - let removedActiveExecution = false; - const currentWorkflow: string = this.workflowsStore.workflowId; - const activeExecution: IExecutionsSummary | null = - this.workflowsStore.activeWorkflowExecution; - // Also update current workflow executions view if needed - for (const selectedId of Object.keys(this.selectedItems)) { - const execution: IExecutionsSummary | undefined = - this.workflowsStore.getExecutionDataById(selectedId); - if (execution && execution.workflowId === currentWorkflow) { - this.workflowsStore.deleteExecution(execution); - removedCurrentlyLoadedExecution = true; - } - if ( - execution !== undefined && - activeExecution !== null && - execution.id === activeExecution.id - ) { - removedActiveExecution = true; - } - } - // Also update route if needed - if (removedCurrentlyLoadedExecution) { - const currentWorkflowExecutions: IExecutionsSummary[] = - this.workflowsStore.currentWorkflowExecutions; - if (currentWorkflowExecutions.length === 0) { - this.workflowsStore.activeWorkflowExecution = null; - - this.$router.push({ name: VIEWS.EXECUTION_HOME, params: { name: currentWorkflow } }); - } else if (removedActiveExecution) { - this.workflowsStore.activeWorkflowExecution = currentWorkflowExecutions[0]; - this.$router - .push({ - name: VIEWS.EXECUTION_PREVIEW, - params: { name: currentWorkflow, executionId: currentWorkflowExecutions[0].id }, - }) - .catch(() => {}); - } - } } catch (error) { this.isDataLoading = false; this.$showError( From 225bc8c0c254031a97830005ad4ecb4676efac21 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 10 Mar 2023 16:05:33 +0100 Subject: [PATCH 13/23] test(editor): Add more execution list unit tests and fake data generation --- packages/editor-ui/package.json | 1 + .../__tests__/ExecutionsList.test.ts | 579 +++--------------- pnpm-lock.yaml | 7 + 3 files changed, 84 insertions(+), 503 deletions(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index f127854f92c2f..9b54bfc8ddc1b 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -101,6 +101,7 @@ "@vitejs/plugin-legacy": "^3.0.1", "@vitejs/plugin-vue2": "^2.2.0", "c8": "^7.12.0", + "@faker-js/faker": "7.6.0", "jshint": "^2.9.7", "sass": "^1.55.0", "sass-loader": "^10.1.1", diff --git a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts index ee73f1ea565c7..6626fd3a860ba 100644 --- a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts +++ b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts @@ -3,6 +3,7 @@ import Vue from 'vue'; import { PiniaVuePlugin } from 'pinia'; import { createTestingPinia } from '@pinia/testing'; import { render, cleanup, fireEvent } from '@testing-library/vue'; +import { faker } from '@faker-js/faker'; import { STORES } from '@/constants'; import ExecutionsList from '@/components/ExecutionsList.vue'; import { externalHooks } from '@/mixins/externalHooks'; @@ -10,500 +11,39 @@ import { genericHelpers } from '@/mixins/genericHelpers'; import { executionHelpers } from '@/mixins/executionsHelpers'; import { showMessage } from '@/mixins/showMessage'; import { i18nInstance, I18nPlugin } from '@/plugins/i18n'; +import type { IWorkflowShortResponse } from '@/Interface'; +import type { IExecutionsSummary } from 'n8n-workflow'; -const workflowsData = [ - { - createdAt: '2023-03-01T05:52:34.106Z', - updatedAt: '2023-03-01T05:53:00.000Z', - id: '1039', - name: 'Set workflow', - active: false, - tags: [{ id: '2', name: 'finance' }], - }, - { - createdAt: '2023-02-08T13:33:51.023Z', - updatedAt: '2023-02-27T09:14:35.000Z', - id: '1037', - name: 'Manual wait set', - active: false, - tags: [{ id: '4', name: 'development' }], - }, - { - createdAt: '2023-02-14T10:35:41.769Z', - updatedAt: '2023-02-14T10:36:07.000Z', - id: '1038', - name: 'Webhook wait set', - active: false, - tags: [], - }, - { - createdAt: '2023-01-11T05:01:19.530Z', - updatedAt: '2023-02-08T13:33:28.000Z', - id: '1025', - name: 'Long running', - active: true, - tags: [], - }, - { - createdAt: '2023-02-07T11:45:22.388Z', - updatedAt: '2023-02-08T08:21:09.000Z', - id: '1036', - name: 'Items count test', - active: false, - tags: [], - }, - { - createdAt: '2023-02-06T13:17:11.555Z', - updatedAt: '2023-02-06T13:17:11.555Z', - id: '1035', - name: 'Items length test', - active: false, - tags: [], - }, - { - createdAt: '2022-11-18T13:58:54.602Z', - updatedAt: '2023-02-03T14:46:51.000Z', - id: '1017', - name: 'Waiter', - active: true, - tags: [], - }, - { - createdAt: '2022-12-22T09:24:56.454Z', - updatedAt: '2023-02-03T14:46:51.000Z', - id: '1019', - name: 'HTTP test', - active: true, - tags: [], - }, - { - createdAt: '2023-01-10T13:58:10.243Z', - updatedAt: '2023-02-03T14:46:51.000Z', - id: '1024', - name: 'Infinite waiter', - active: true, - tags: [], - }, - { - createdAt: '2023-01-11T16:24:38.349Z', - updatedAt: '2023-02-03T14:46:51.000Z', - id: '1026', - name: 'Pinned data', - active: true, - tags: [], - }, - { - createdAt: '2023-01-25T10:01:38.870Z', - updatedAt: '2023-02-03T14:46:51.000Z', - id: '1027', - name: 'A webhook', - active: true, - tags: [], - }, - { - createdAt: '2023-02-01T13:53:35.170Z', - updatedAt: '2023-02-01T13:53:35.170Z', - id: '1034', - name: 'My workflow 10', - active: false, - tags: [], - }, - { - createdAt: '2023-02-01T13:52:27.937Z', - updatedAt: '2023-02-01T13:52:27.937Z', - id: '1033', - name: 'My workflow 9', - active: false, - tags: [], - }, - { - createdAt: '2023-02-01T13:51:56.977Z', - updatedAt: '2023-02-01T13:51:56.977Z', - id: '1032', - name: 'My workflow 8', - active: false, - tags: [], - }, - { - createdAt: '2023-02-01T13:51:44.565Z', - updatedAt: '2023-02-01T13:51:44.565Z', - id: '1031', - name: 'My workflow 7', - active: false, - tags: [], - }, - { - createdAt: '2023-01-31T12:52:15.797Z', - updatedAt: '2023-01-31T12:52:15.797Z', - id: '1030', - name: 'My workflow 6', - active: false, - tags: [], - }, - { - createdAt: '2023-01-31T12:10:11.850Z', - updatedAt: '2023-01-31T12:10:11.850Z', - id: '1029', - name: 'My workflow 5', - active: false, - tags: [], - }, - { - createdAt: '2022-11-01T10:27:37.477Z', - updatedAt: '2023-01-16T17:07:11.000Z', - id: '1015', - name: 'Execution testing', - active: false, - tags: [], - }, - { - createdAt: '2023-01-10T10:36:02.480Z', - updatedAt: '2023-01-10T10:36:02.480Z', - id: '1021', - name: 'Empty', - active: false, - tags: [], - }, - { - createdAt: '2022-09-13T08:27:55.565Z', - updatedAt: '2023-01-09T15:48:52.000Z', - id: '3', - name: 'Null values in table and json', - active: false, - tags: [], - }, - { - createdAt: '2022-09-12T13:46:20.452Z', - updatedAt: '2023-01-09T14:54:16.000Z', - id: '2', - name: 'Improve visibility of Trigger NDV listening state', - active: false, - tags: [], - }, - { - createdAt: '2022-09-13T18:47:34.347Z', - updatedAt: '2023-01-05T17:18:34.000Z', - id: '4', - name: 'Mapping test', - active: false, - tags: [], - }, - { - createdAt: '2022-12-22T09:24:56.448Z', - updatedAt: '2022-12-22T09:24:56.448Z', - id: '1018', - name: 'My workflow 4', - active: false, - tags: [], - }, - { - createdAt: '2022-11-18T13:58:54.596Z', - updatedAt: '2022-11-18T13:58:54.596Z', - id: '1016', - name: 'My workflow 3', - active: false, - tags: [], - }, - { - createdAt: '2022-10-27T09:54:34.808Z', - updatedAt: '2022-10-27T09:54:34.808Z', - id: '1014', - name: 'Large data', - active: false, - tags: [], - }, - { - createdAt: '2022-10-26T18:58:22.675Z', - updatedAt: '2022-10-26T18:58:22.675Z', - id: '1013', - name: 'My workflow', - active: false, - tags: [], - }, - { - createdAt: '2022-10-20T21:50:27.089Z', - updatedAt: '2022-10-24T14:03:39.482Z', - id: '5', - name: 'Readonly nodes', - active: false, - tags: [], - }, - { - createdAt: '2022-02-22T09:37:42.963Z', - updatedAt: '2022-10-10T11:13:47.133Z', - id: '1012', - name: 'Transporeon - orders - step 3 - process single', - active: false, - tags: [ - { id: '9', name: 'nested' }, - { id: '10', name: 'transporeon' }, - ], - }, - { - createdAt: '2022-09-08T20:25:49.637Z', - updatedAt: '2022-09-14T12:13:52.930Z', - id: '1', - name: 'Input error test', - active: false, - tags: [], - }, -]; +const workflowDataFactory = (): IWorkflowShortResponse => ({ + createdAt: faker.date.past().toDateString(), + updatedAt: faker.date.past().toDateString(), + id: faker.datatype.uuid(), + name: faker.datatype.string(), + active: faker.datatype.boolean(), + tags: [], +}); -const executionsData = { - count: 239, - results: [ - { - id: '28803', - finished: true, - mode: 'manual', - waitTill: null, - startedAt: '2023-03-01T05:53:02.273Z', - stoppedAt: '2023-03-01T05:53:02.283Z', - workflowId: '1039', - workflowName: 'Set workflow', - status: 'success', - nodeExecutionStatus: {}, - }, - { - id: '28800', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:59:31.871Z', - stoppedAt: '2023-02-14T10:59:32.162Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28799', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:59:21.886Z', - stoppedAt: '2023-02-14T10:59:22.521Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28798', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:59:18.240Z', - stoppedAt: '2023-02-14T10:59:19.247Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28797', - finished: true, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:59:13.053Z', - stoppedAt: '2023-02-14T10:59:15.084Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'success', - nodeExecutionStatus: {}, - }, - { - id: '28796', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:59:08.348Z', - stoppedAt: '2023-02-14T10:59:09.527Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28795', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:59:06.001Z', - stoppedAt: '2023-02-14T10:59:06.542Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28794', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:59:04.309Z', - stoppedAt: '2023-02-14T10:59:04.447Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28793', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:58:59.666Z', - stoppedAt: '2023-02-14T10:59:00.695Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28792', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:58:55.243Z', - stoppedAt: '2023-02-14T10:58:57.086Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - ], +const executionDataFactory = (): IExecutionsSummary => ({ + id: faker.datatype.uuid(), + finished: faker.datatype.boolean(), + mode: faker.helpers.arrayElement(['manual', 'trigger']), + startedAt: faker.date.past(), + stoppedAt: faker.date.past(), + workflowId: faker.datatype.number().toString(), + workflowName: faker.datatype.string(), + status: faker.helpers.arrayElement(['failed', 'success']), + nodeExecutionStatus: {}, +}); + +const workflowsData = Array.from({ length: 10 }, workflowDataFactory); + +const executionsData = Array.from({ length: 2 }, () => ({ + count: 20, + results: Array.from({ length: 10 }, executionDataFactory), estimated: false, -}; +})); -const executionsData2 = { - data: { - count: 239, - results: [ - { - id: '28791', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:58:51.615Z', - stoppedAt: '2023-02-14T10:58:52.853Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28790', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:58:48.134Z', - stoppedAt: '2023-02-14T10:58:48.740Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28789', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:46:57.863Z', - stoppedAt: '2023-02-14T10:46:58.786Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28788', - finished: true, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:46:28.168Z', - stoppedAt: '2023-02-14T10:46:30.193Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'success', - nodeExecutionStatus: {}, - }, - { - id: '28787', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:46:00.194Z', - stoppedAt: '2023-02-14T10:46:01.016Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28786', - finished: false, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T10:45:48.263Z', - stoppedAt: '2023-02-14T10:45:49.129Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28785', - finished: false, - mode: 'own', - waitTill: null, - startedAt: '2023-02-14T10:45:35.390Z', - stoppedAt: '2023-02-14T10:45:35.391Z', - workflowId: '1037', - workflowName: 'Manual wait set', - status: 'failed', - nodeExecutionStatus: {}, - }, - { - id: '28782', - finished: true, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-14T09:55:03.561Z', - stoppedAt: '2023-02-14T09:55:05.591Z', - workflowId: '1037', - workflowName: 'Manual long running', - status: 'success', - nodeExecutionStatus: {}, - }, - { - id: '28781', - finished: true, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-10T11:18:56.590Z', - stoppedAt: '2023-02-10T11:18:59.181Z', - workflowId: '1037', - workflowName: 'Manual long running', - status: 'success', - nodeExecutionStatus: {}, - }, - { - id: '28780', - finished: true, - mode: 'manual', - waitTill: null, - startedAt: '2023-02-10T11:17:25.837Z', - stoppedAt: '2023-02-10T11:17:28.428Z', - workflowId: '1037', - workflowName: 'Manual long running', - status: 'success', - nodeExecutionStatus: {}, - }, - ], - estimated: false, - }, -}; +let getPastExecutionsSpy = vi.fn().mockResolvedValue({ count: 0, results: [], estimated: false }); const mockRestApiMixin = Vue.extend({ methods: { @@ -511,10 +51,7 @@ const mockRestApiMixin = Vue.extend({ return { getWorkflows: vi.fn().mockResolvedValue(workflowsData), getCurrentExecutions: vi.fn().mockResolvedValue([]), - getPastExecutions: vi - .fn() - .mockResolvedValueOnce(executionsData) - .mockResolvedValueOnce(executionsData2), + getPastExecutions: getPastExecutionsSpy, }; }, }, @@ -565,31 +102,67 @@ const renderComponent = () => describe('ExecutionsList.vue', () => { afterEach(cleanup); - it('should handle visible executions selection properly', async () => { - const { getAllByTestId, getByTestId } = renderComponent(); + it('should render empty list', async () => { + const { queryAllByTestId, queryByTestId, getByTestId } = renderComponent(); // wait for all previous promises to make sure the component is fully rendered await new Promise((resolve) => setTimeout(resolve)); + expect(queryAllByTestId('select-execution-checkbox').length).toBe(0); + expect(queryByTestId('load-more-button')).not.toBeInTheDocument(); + expect(getByTestId('execution-list-empty')).toBeInTheDocument(); + }); + + it('should handle visible executions selection', async () => { + getPastExecutionsSpy = vi.fn().mockResolvedValue(executionsData[0]); + + const { getAllByTestId, getByTestId, queryByTestId } = renderComponent(); + // wait for all previous promises to make sure the component is fully rendered + await new Promise((resolve) => setTimeout(resolve)); + + const executionsData1Length = executionsData[0].results.length; const itemCheckboxes = getAllByTestId('select-execution-checkbox'); - expect(itemCheckboxes.length).toBe(executionsData.results.length); + expect(itemCheckboxes.length).toBe(executionsData1Length); + + expect(getByTestId('load-more-button')).toBeInTheDocument(); + expect(queryByTestId('execution-list-empty')).not.toBeInTheDocument(); await fireEvent.click(getByTestId('select-visible-executions-checkbox')); expect(itemCheckboxes.filter((el) => el.contains(el.querySelector(':checked'))).length).toBe( - executionsData.results.length, - ); - expect(getByTestId('selected-executions-info').textContent).toContain( - executionsData.results.length, + executionsData1Length, ); + expect(getByTestId('selected-executions-info').textContent).toContain(executionsData1Length); const firstCheckbox = itemCheckboxes[0]; await fireEvent.click(firstCheckbox); expect(itemCheckboxes.filter((el) => el.contains(el.querySelector(':checked'))).length).toBe( - executionsData.results.length - 1, + executionsData1Length - 1, ); expect(getByTestId('selected-executions-info').textContent).toContain( - executionsData.results.length - 1, + executionsData1Length - 1, ); }); + + it('should handle load more', async () => { + getPastExecutionsSpy = vi + .fn() + .mockResolvedValueOnce(executionsData[0]) + .mockResolvedValueOnce(executionsData[1]); + + const { getAllByTestId, getByTestId } = renderComponent(); + // wait for all previous promises to make sure the component is fully rendered + await new Promise((resolve) => setTimeout(resolve)); + + let executionsDataLength = executionsData[0].results.length; + let itemCheckboxes = getAllByTestId('select-execution-checkbox'); + expect(itemCheckboxes.length).toBe(executionsDataLength); + + await fireEvent.click(getByTestId('load-more-button')); + await new Promise((resolve) => setTimeout(resolve)); + + executionsDataLength += executionsData[1].results.length; + itemCheckboxes = getAllByTestId('select-execution-checkbox'); + expect(itemCheckboxes.length).toBe(executionsDataLength); + }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1a8ad959f0664..f33c7505eea4d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -558,6 +558,7 @@ importers: '@codemirror/lint': ^6.0.0 '@codemirror/state': ^6.1.4 '@codemirror/view': ^6.5.1 + '@faker-js/faker': 7.6.0 '@fontsource/open-sans': ^4.5.0 '@fortawesome/fontawesome-svg-core': ^1.2.35 '@fortawesome/free-regular-svg-icons': ^6.1.1 @@ -688,6 +689,7 @@ importers: vue2-touch-events: 3.2.2 xss: 1.0.14 devDependencies: + '@faker-js/faker': 7.6.0 '@pinia/testing': 0.0.14_pinia@2.0.23+vue@2.7.14 '@testing-library/jest-dom': 5.16.5 '@testing-library/vue': 5.8.3_rhqkolmkwunxzlyyxxsuwaiuri @@ -3077,6 +3079,11 @@ packages: - supports-color dev: true + /@faker-js/faker/7.6.0: + resolution: {integrity: sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==} + engines: {node: '>=14.0.0', npm: '>=6.0.0'} + dev: true + /@fal-works/esbuild-plugin-global-externals/2.1.2: resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} dev: true From 80ee5ea3b6430769a527e166c66e0fa217bb8652 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Fri, 10 Mar 2023 22:38:07 +0100 Subject: [PATCH 14/23] test(editor): Add more execution list unit tests --- packages/editor-ui/package.json | 3 +- .../src/components/ExecutionsList.vue | 6 +- .../__tests__/ExecutionsList.test.ts | 112 +++++++++--------- pnpm-lock.yaml | 11 ++ 4 files changed, 74 insertions(+), 58 deletions(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 9b54bfc8ddc1b..defd71d71bb22 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -84,8 +84,10 @@ "xss": "^1.0.10" }, "devDependencies": { + "@faker-js/faker": "7.6.0", "@pinia/testing": "^0.0.14", "@testing-library/jest-dom": "^5.16.5", + "@testing-library/user-event": "14.4.3", "@testing-library/vue": "^5.8.3", "@types/dateformat": "^3.0.0", "@types/express": "^4.17.6", @@ -101,7 +103,6 @@ "@vitejs/plugin-legacy": "^3.0.1", "@vitejs/plugin-vue2": "^2.2.0", "c8": "^7.12.0", - "@faker-js/faker": "7.6.0", "jshint": "^2.9.7", "sass": "^1.55.0", "sass-loader": "^10.1.1", diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 8f7706bf0e985..f151aa77463af 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -31,7 +31,11 @@ > - + {{ $locale.baseText('executionsList.autoRefresh') }}
diff --git a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts index 6626fd3a860ba..e81d9d78495f9 100644 --- a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts +++ b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts @@ -1,8 +1,9 @@ -import { vi, describe, it, expect, afterEach } from 'vitest'; +import { vi, describe, it, expect } from 'vitest'; import Vue from 'vue'; import { PiniaVuePlugin } from 'pinia'; import { createTestingPinia } from '@pinia/testing'; -import { render, cleanup, fireEvent } from '@testing-library/vue'; +import { render } from '@testing-library/vue'; +import userEvent from '@testing-library/user-event'; import { faker } from '@faker-js/faker'; import { STORES } from '@/constants'; import ExecutionsList from '@/components/ExecutionsList.vue'; @@ -14,6 +15,8 @@ import { i18nInstance, I18nPlugin } from '@/plugins/i18n'; import type { IWorkflowShortResponse } from '@/Interface'; import type { IExecutionsSummary } from 'n8n-workflow'; +const waitAllPromises = () => new Promise((resolve) => setTimeout(resolve)); + const workflowDataFactory = (): IWorkflowShortResponse => ({ createdAt: faker.date.past().toDateString(), updatedAt: faker.date.past().toDateString(), @@ -92,77 +95,74 @@ export function TelemetryPlugin(vue: typeof Vue): void { }); } -const renderComponent = () => - render(ExecutionsList, renderOptions, (vue) => { +const renderComponent = async () => { + const renderResult = render(ExecutionsList, renderOptions, (vue) => { vue.use(TelemetryPlugin); vue.use(PiniaVuePlugin); vue.use((vue) => I18nPlugin(vue)); }); + await waitAllPromises(); + return renderResult; +}; describe('ExecutionsList.vue', () => { - afterEach(cleanup); - it('should render empty list', async () => { - const { queryAllByTestId, queryByTestId, getByTestId } = renderComponent(); - // wait for all previous promises to make sure the component is fully rendered - await new Promise((resolve) => setTimeout(resolve)); + const { queryAllByTestId, queryByTestId, getByTestId } = await renderComponent(); + await userEvent.click(getByTestId('execution-auto-refresh-checkbox')); expect(queryAllByTestId('select-execution-checkbox').length).toBe(0); expect(queryByTestId('load-more-button')).not.toBeInTheDocument(); + expect(queryByTestId('select-all-executions-checkbox')).not.toBeInTheDocument(); expect(getByTestId('execution-list-empty')).toBeInTheDocument(); }); - it('should handle visible executions selection', async () => { - getPastExecutionsSpy = vi.fn().mockResolvedValue(executionsData[0]); - - const { getAllByTestId, getByTestId, queryByTestId } = renderComponent(); - // wait for all previous promises to make sure the component is fully rendered - await new Promise((resolve) => setTimeout(resolve)); - - const executionsData1Length = executionsData[0].results.length; - const itemCheckboxes = getAllByTestId('select-execution-checkbox'); - expect(itemCheckboxes.length).toBe(executionsData1Length); - - expect(getByTestId('load-more-button')).toBeInTheDocument(); - expect(queryByTestId('execution-list-empty')).not.toBeInTheDocument(); - - await fireEvent.click(getByTestId('select-visible-executions-checkbox')); - - expect(itemCheckboxes.filter((el) => el.contains(el.querySelector(':checked'))).length).toBe( - executionsData1Length, - ); - expect(getByTestId('selected-executions-info').textContent).toContain(executionsData1Length); - - const firstCheckbox = itemCheckboxes[0]; - await fireEvent.click(firstCheckbox); - - expect(itemCheckboxes.filter((el) => el.contains(el.querySelector(':checked'))).length).toBe( - executionsData1Length - 1, - ); - expect(getByTestId('selected-executions-info').textContent).toContain( - executionsData1Length - 1, - ); - }); - - it('should handle load more', async () => { + it('should handle selection flow when loading more items', async () => { getPastExecutionsSpy = vi .fn() .mockResolvedValueOnce(executionsData[0]) .mockResolvedValueOnce(executionsData[1]); - const { getAllByTestId, getByTestId } = renderComponent(); - // wait for all previous promises to make sure the component is fully rendered - await new Promise((resolve) => setTimeout(resolve)); - - let executionsDataLength = executionsData[0].results.length; - let itemCheckboxes = getAllByTestId('select-execution-checkbox'); - expect(itemCheckboxes.length).toBe(executionsDataLength); - - await fireEvent.click(getByTestId('load-more-button')); - await new Promise((resolve) => setTimeout(resolve)); - - executionsDataLength += executionsData[1].results.length; - itemCheckboxes = getAllByTestId('select-execution-checkbox'); - expect(itemCheckboxes.length).toBe(executionsDataLength); + const { getByTestId, getAllByTestId, queryByTestId } = await renderComponent(); + await userEvent.click(getByTestId('execution-auto-refresh-checkbox')); + + await userEvent.click(getByTestId('select-visible-executions-checkbox')); + + expect(getPastExecutionsSpy).toHaveBeenCalledTimes(1); + expect( + getAllByTestId('select-execution-checkbox').filter((el) => + el.contains(el.querySelector(':checked')), + ).length, + ).toBe(10); + expect(getByTestId('select-all-executions-checkbox')).toBeInTheDocument(); + expect(getByTestId('selected-executions-info').textContent).toContain(10); + + await userEvent.click(getByTestId('load-more-button')); + + expect(getAllByTestId('select-execution-checkbox').length).toBe(20); + expect( + getAllByTestId('select-execution-checkbox').filter((el) => + el.contains(el.querySelector(':checked')), + ).length, + ).toBe(10); + + await userEvent.click(getByTestId('select-all-executions-checkbox')); + expect(getAllByTestId('select-execution-checkbox').length).toBe(20); + expect( + getAllByTestId('select-execution-checkbox').filter((el) => + el.contains(el.querySelector(':checked')), + ).length, + ).toBe(20); + expect(getByTestId('selected-executions-info').textContent).toContain(20); + + await userEvent.click(getAllByTestId('select-execution-checkbox')[2]); + expect(getAllByTestId('select-execution-checkbox').length).toBe(20); + expect( + getAllByTestId('select-execution-checkbox').filter((el) => + el.contains(el.querySelector(':checked')), + ).length, + ).toBe(19); + expect(getByTestId('selected-executions-info').textContent).toContain(19); + expect(getByTestId('select-visible-executions-checkbox')).toBeInTheDocument(); + expect(queryByTestId('select-all-executions-checkbox')).not.toBeInTheDocument(); }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f33c7505eea4d..26be0f49ab633 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -571,6 +571,7 @@ importers: '@jsplumb/util': ^5.13.2 '@pinia/testing': ^0.0.14 '@testing-library/jest-dom': ^5.16.5 + '@testing-library/user-event': 14.4.3 '@testing-library/vue': ^5.8.3 '@types/dateformat': ^3.0.0 '@types/express': ^4.17.6 @@ -692,6 +693,7 @@ importers: '@faker-js/faker': 7.6.0 '@pinia/testing': 0.0.14_pinia@2.0.23+vue@2.7.14 '@testing-library/jest-dom': 5.16.5 + '@testing-library/user-event': 14.4.3_7izb363m7fjrh7ob6q4a2yqaqe '@testing-library/vue': 5.8.3_rhqkolmkwunxzlyyxxsuwaiuri '@types/dateformat': 3.0.1 '@types/express': 4.17.14 @@ -5294,6 +5296,15 @@ packages: redent: 3.0.0 dev: true + /@testing-library/user-event/14.4.3_7izb363m7fjrh7ob6q4a2yqaqe: + resolution: {integrity: sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + dependencies: + '@testing-library/dom': 7.31.2 + dev: true + /@testing-library/vue/5.8.3_rhqkolmkwunxzlyyxxsuwaiuri: resolution: {integrity: sha512-M6+QqP1xuFHixKOeXF9pCLbtiyJZRKfJRP+unBf6Ljm7aS1V2CSS95oTetFoblaj0W1+AC9XJgwmUDtlLoaakQ==} engines: {node: '>10.18'} From 6238a4374a6e1ef6c18aa206e9f251c3ea7a6b1d Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Mon, 13 Mar 2023 06:50:09 +0100 Subject: [PATCH 15/23] test(editor): Simplifying test setup --- .../src/components/__tests__/ExecutionsList.test.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts index e81d9d78495f9..aaba8382aa902 100644 --- a/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts +++ b/packages/editor-ui/src/components/__tests__/ExecutionsList.test.ts @@ -11,7 +11,7 @@ import { externalHooks } from '@/mixins/externalHooks'; import { genericHelpers } from '@/mixins/genericHelpers'; import { executionHelpers } from '@/mixins/executionsHelpers'; import { showMessage } from '@/mixins/showMessage'; -import { i18nInstance, I18nPlugin } from '@/plugins/i18n'; +import { i18nInstance } from '@/plugins/i18n'; import type { IWorkflowShortResponse } from '@/Interface'; import type { IExecutionsSummary } from 'n8n-workflow'; @@ -78,7 +78,7 @@ const renderOptions = { mixins: [externalHooks, genericHelpers, executionHelpers, showMessage, mockRestApiMixin], }; -export function TelemetryPlugin(vue: typeof Vue): void { +function TelemetryPlugin(vue: typeof Vue): void { Object.defineProperty(vue, '$telemetry', { get() { return { @@ -96,15 +96,14 @@ export function TelemetryPlugin(vue: typeof Vue): void { } const renderComponent = async () => { - const renderResult = render(ExecutionsList, renderOptions, (vue) => { - vue.use(TelemetryPlugin); - vue.use(PiniaVuePlugin); - vue.use((vue) => I18nPlugin(vue)); - }); + const renderResult = render(ExecutionsList, renderOptions); await waitAllPromises(); return renderResult; }; +Vue.use(TelemetryPlugin); +Vue.use(PiniaVuePlugin); + describe('ExecutionsList.vue', () => { it('should render empty list', async () => { const { queryAllByTestId, queryByTestId, getByTestId } = await renderComponent(); From 4605be15433c003c879532422ca4bcf3cecbdb98 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Mon, 13 Mar 2023 10:24:33 +0100 Subject: [PATCH 16/23] chore: update pnpm lock after resolving merge conflocts --- pnpm-lock.yaml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index def31059e0dcd..8d61fb501dfcd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -571,6 +571,7 @@ importers: '@jsplumb/util': ^5.13.2 '@pinia/testing': ^0.0.14 '@testing-library/jest-dom': ^5.16.5 + '@testing-library/user-event': 14.4.3 '@testing-library/vue': ^5.8.3 '@types/dateformat': ^3.0.0 '@types/express': ^4.17.6 @@ -693,6 +694,7 @@ importers: '@faker-js/faker': 7.6.0 '@pinia/testing': 0.0.14_pinia@2.0.23+vue@2.7.14 '@testing-library/jest-dom': 5.16.5 + '@testing-library/user-event': 14.4.3_7izb363m7fjrh7ob6q4a2yqaqe '@testing-library/vue': 5.8.3_rhqkolmkwunxzlyyxxsuwaiuri '@types/dateformat': 3.0.1 '@types/express': 4.17.14 @@ -5300,6 +5302,15 @@ packages: redent: 3.0.0 dev: true + /@testing-library/user-event/14.4.3_7izb363m7fjrh7ob6q4a2yqaqe: + resolution: {integrity: sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + dependencies: + '@testing-library/dom': 7.31.2 + dev: true + /@testing-library/vue/5.8.3_rhqkolmkwunxzlyyxxsuwaiuri: resolution: {integrity: sha512-M6+QqP1xuFHixKOeXF9pCLbtiyJZRKfJRP+unBf6Ljm7aS1V2CSS95oTetFoblaj0W1+AC9XJgwmUDtlLoaakQ==} engines: {node: '>10.18'} @@ -6558,7 +6569,7 @@ packages: vite: ^3.0.0 || ^4.0.0 vue: ^2.7.0-0 dependencies: - vite: 4.0.4_sass@1.55.0+terser@5.16.1 + vite: 4.0.4_sass@1.58.0 vue: 2.7.14 dev: true From 0ce56df70e230842bed45e3728d61f0b37ab00bf Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Mon, 13 Mar 2023 10:43:36 +0100 Subject: [PATCH 17/23] chore: fix package version --- packages/editor-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 4e24057564017..a2a1019b80d78 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -87,7 +87,7 @@ "@faker-js/faker": "^7.6.0", "@pinia/testing": "^0.0.14", "@testing-library/jest-dom": "^5.16.5", - "@testing-library/user-event": "14.4.3", + "@testing-library/user-event": "^14.4.3", "@testing-library/vue": "^5.8.3", "@types/dateformat": "^3.0.0", "@types/express": "^4.17.6", From 669cabecd5db7599380c17abdf3b85a6f99dace8 Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Tue, 14 Mar 2023 10:32:22 +0100 Subject: [PATCH 18/23] fix: Improved executions deletion to prevent crashing and fixed removal of failed executions --- packages/cli/src/executions/executions.service.ts | 8 +++++++- pnpm-lock.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/executions/executions.service.ts b/packages/cli/src/executions/executions.service.ts index a4f9d05dcd4e4..5da24129f80bb 100644 --- a/packages/cli/src/executions/executions.service.ts +++ b/packages/cli/src/executions/executions.service.ts @@ -541,6 +541,9 @@ export class ExecutionsService { // delete executions by date, if user may access the underlying workflows where.startedAt = LessThanOrEqual(deleteBefore); Object.assign(where, requestFilters); + if (where.status) { + where.status = In(requestFiltersRaw!.status as string[]); + } } else if (ids) { // delete executions by IDs, if user may access the underlying workflows where.id = In(ids); @@ -568,6 +571,9 @@ export class ExecutionsService { idsToDelete.map(async (id) => binaryDataManager.deleteBinaryDataByExecutionId(id)), ); - await Db.collections.Execution.delete(idsToDelete); + do { + const batch = idsToDelete.splice(0, 500); + await Db.collections.Execution.delete(batch); + } while (idsToDelete.length > 0); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8d61fb501dfcd..7f5735f486d38 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -571,7 +571,7 @@ importers: '@jsplumb/util': ^5.13.2 '@pinia/testing': ^0.0.14 '@testing-library/jest-dom': ^5.16.5 - '@testing-library/user-event': 14.4.3 + '@testing-library/user-event': ^14.4.3 '@testing-library/vue': ^5.8.3 '@types/dateformat': ^3.0.0 '@types/express': ^4.17.6 From f0605ba396e5b1e20fa8e09d108b72c6807549b9 Mon Sep 17 00:00:00 2001 From: Omar Ajoue Date: Tue, 14 Mar 2023 12:28:24 +0100 Subject: [PATCH 19/23] fix: Add comment to clarify why change was needed --- packages/cli/src/executions/executions.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/executions/executions.service.ts b/packages/cli/src/executions/executions.service.ts index 5da24129f80bb..54f1c7925df2e 100644 --- a/packages/cli/src/executions/executions.service.ts +++ b/packages/cli/src/executions/executions.service.ts @@ -572,6 +572,7 @@ export class ExecutionsService { ); do { + // Delete in batches to avoid "SQLITE_ERROR: Expression tree is too large (maximum depth 1000)" error const batch = idsToDelete.splice(0, 500); await Db.collections.Execution.delete(batch); } while (idsToDelete.length > 0); From 984bd8eedcff8f93f75ff56369ca8376e936bb41 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Tue, 14 Mar 2023 15:08:41 +0200 Subject: [PATCH 20/23] fix: fix executions list bug when selecting all and changing filter --- packages/editor-ui/src/components/ExecutionsList.vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index f151aa77463af..36e58b4088681 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -61,6 +61,7 @@ @@ -689,6 +690,12 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.finishedExecutionsCount = data.count; this.finishedExecutionsCountEstimated = data.estimated; + if (this.finishedExecutions.length === 0) { + this.allVisibleSelected = false; + this.allExistingSelected = false; + this.selectedItems = {}; + } + this.workflowsStore.addToCurrentExecutions(data.results); }, async loadMore() { From 85941582fc9508b793920dbf86359dcce89cb17b Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Tue, 14 Mar 2023 15:27:38 +0200 Subject: [PATCH 21/23] fix: fix execution lists running execution showing up on different workflow id --- .../src/components/ExecutionsList.vue | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 36e58b4088681..d02fe575eae08 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -397,12 +397,17 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, const returnData = []; if (['ALL', 'running'].includes(this.filter.status)) { - returnData.push(...this.activeExecutions); + returnData.push(...(this.activeExecutions as IExecutionsSummary[])); } + if (['ALL', 'error', 'success', 'waiting'].includes(this.filter.status)) { returnData.push(...this.finishedExecutions); } - return returnData; + + return returnData.filter( + (execution) => + this.filter.workflowId === 'ALL' || execution.workflowId === this.filter.workflowId, + ); }, numSelected(): number { if (this.allExistingSelected) { @@ -537,12 +542,12 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.handleClearSelection(); this.refreshData(); }, - handleClearSelection() { + handleClearSelection(): void { this.allVisibleSelected = false; this.allExistingSelected = false; Vue.set(this, 'selectedItems', {}); }, - handleFilterChanged() { + handleFilterChanged(): void { this.refreshData(); }, handleActionItemClick(commandData: { command: string; execution: IExecutionsSummary }) { @@ -690,13 +695,11 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, this.finishedExecutionsCount = data.count; this.finishedExecutionsCountEstimated = data.estimated; + this.workflowsStore.addToCurrentExecutions(data.results); + if (this.finishedExecutions.length === 0) { - this.allVisibleSelected = false; - this.allExistingSelected = false; - this.selectedItems = {}; + this.handleClearSelection(); } - - this.workflowsStore.addToCurrentExecutions(data.results); }, async loadMore() { if (this.filter.status === 'running') { From a99ac01ea10f57e283a7c9a721cf0689cb045a6e Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Thu, 16 Mar 2023 11:57:44 +0100 Subject: [PATCH 22/23] fix(editor): Deleting an execution while all are selected --- packages/editor-ui/src/components/ExecutionsList.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index d02fe575eae08..07d80e1c2e3b6 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -41,7 +41,7 @@ @@ -936,6 +936,11 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, try { await this.restApi().deleteExecutions({ ids: [execution.id] }); await this.refreshData(); + + if (this.allVisibleSelected && !this.allExistingSelected) { + this.handleClearSelection(); + this.selectAllVisibleExecutions(); + } } catch (error) { this.$showError( error, From 6bedc7fc6731c3c940b3927bbfe24b2ee6332f1c Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Thu, 16 Mar 2023 12:04:37 +0100 Subject: [PATCH 23/23] fix(editor): Deleting an execution while all are selected --- packages/editor-ui/src/components/ExecutionsList.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index 07d80e1c2e3b6..e7b6a548bf325 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -937,8 +937,8 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, await this.restApi().deleteExecutions({ ids: [execution.id] }); await this.refreshData(); - if (this.allVisibleSelected && !this.allExistingSelected) { - this.handleClearSelection(); + if (this.allVisibleSelected) { + Vue.set(this, 'selectedItems', {}); this.selectAllVisibleExecutions(); } } catch (error) {