fix(editor): Remove 'crashed' status from filter (#5524)

* fix(editor): remove 'crashed' status from filter

* fix(editor): remove 'crashed' and 'new' status from filter

* fix(editor): add 'status' to response

* fix(editor): create request filter for workflow level execution filtering

* fix(editor): update filters

* fix(editor): simplify condition

* fix(editor): update filters

* fix(editor): optimizing data loading flow

* fix(editor): always load past executions
This commit is contained in:
Csaba Tuncsik
2023-02-23 11:13:21 +01:00
committed by GitHub
parent 4998ab2350
commit 7c517cb530
9 changed files with 82 additions and 106 deletions

View File

@@ -133,9 +133,9 @@ export interface IExternalHooks {
export interface IRestApi {
getActiveWorkflows(): Promise<string[]>;
getActivationError(id: string): Promise<IActivationError | undefined>;
getCurrentExecutions(filter: object): Promise<IExecutionsCurrentSummaryExtended[]>;
getCurrentExecutions(filter: IDataObject): Promise<IExecutionsCurrentSummaryExtended[]>;
getPastExecutions(
filter: object,
filter: IDataObject,
limit: number,
lastId?: string,
firstId?: string,

View File

@@ -335,14 +335,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
id: 'error',
name: this.$locale.baseText('executionsList.error'),
},
{
id: 'crashed',
name: this.$locale.baseText('executionsList.error'),
},
{
id: 'new',
name: this.$locale.baseText('executionsList.new'),
},
{
id: 'running',
name: this.$locale.baseText('executionsList.running'),
@@ -363,10 +355,10 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
combinedExecutions(): IExecutionsSummary[] {
const returnData: IExecutionsSummary[] = [];
if (['ALL', 'running', 'new'].includes(this.filter.status)) {
if (['ALL', 'running'].includes(this.filter.status)) {
returnData.push(...this.activeExecutions);
}
if (['ALL', 'error', 'crashed', 'success', 'waiting'].includes(this.filter.status)) {
if (['ALL', 'error', 'success', 'waiting'].includes(this.filter.status)) {
returnData.push(...this.finishedExecutions);
}
return returnData;
@@ -404,14 +396,8 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
case 'waiting':
queryFilter.status = ['waiting'];
break;
case 'crashed':
queryFilter.status = ['crashed'];
break;
case 'new':
queryFilter.status = ['new'];
break;
case 'error':
queryFilter.status = ['failed', 'crashed', 'error'];
queryFilter.status = ['failed', 'crashed'];
break;
case 'success':
queryFilter.status = ['success'];
@@ -813,8 +799,9 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
this.isDataLoading = false;
},
getStatus(execution: IExecutionsSummary): ExecutionStatus {
if (execution.status) return execution.status;
else {
if (execution.status) {
return execution.status;
} else {
// this should not happen but just in case
let status: ExecutionStatus = 'unknown';
if (execution.waitTill) {
@@ -843,7 +830,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
} else if (status === 'crashed') {
text = this.$locale.baseText('executionsList.error');
} else if (status === 'new') {
text = this.$locale.baseText('executionsList.new');
text = this.$locale.baseText('executionsList.running');
} else if (status === 'running') {
text = this.$locale.baseText('executionsList.running');
} else if (status === 'success') {
@@ -865,7 +852,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
} else if (status === 'crashed') {
path = 'executionsList.statusText';
} else if (status === 'new') {
path = 'executionsList.statusNew';
path = 'executionsList.statusRunning';
} else if (status === 'running') {
path = 'executionsList.statusRunning';
} else if (status === 'success') {
@@ -1018,14 +1005,11 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
font-size: var(--font-size-s);
font-weight: var(--font-weight-bold);
.crashed &,
.failed & {
color: var(--color-danger);
}
.crashed & {
color: var(--color-danger);
}
.waiting & {
color: var(--color-secondary);
}
@@ -1034,6 +1018,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
font-weight: var(--font-weight-normal);
}
.new &,
.running & {
color: var(--color-warning);
}
@@ -1131,18 +1116,16 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
background: var(--color-primary-tint-3);
}
&.crashed td:first-child::before,
&.failed td:first-child::before {
background: var(--color-danger);
}
&.crashed td:first-child::before {
background: var(--color-danger);
}
&.success td:first-child::before {
background: var(--color-success);
}
&.new td:first-child::before,
&.running td:first-child::before {
background: var(--color-warning);
}

View File

@@ -191,8 +191,7 @@ export default mixins(executionHelpers, showMessage, restApi).extend({
}
}
&.error,
&.crashed {
&.error {
&,
& .executionLink {
border-left: var(--spacing-4xs) var(--border-style-base) hsl(var(--color-danger-h), 94%, 80%);

View File

@@ -26,20 +26,15 @@ import ExecutionsSidebar from '@/components/ExecutionsView/ExecutionsSidebar.vue
import {
MAIN_HEADER_TABS,
MODAL_CANCEL,
MODAL_CLOSE,
MODAL_CONFIRMED,
PLACEHOLDER_EMPTY_WORKFLOW_ID,
VIEWS,
WEBHOOK_NODE_TYPE,
} from '@/constants';
import { IExecutionsListResponse, INodeUi, ITag, IWorkflowDb } from '@/Interface';
import {
IExecutionsListResponse,
ExecutionStatus,
IExecutionsSummary,
INodeUi,
ITag,
IWorkflowDb,
} from '@/Interface';
import {
IConnection,
IConnections,
IDataObject,
@@ -71,7 +66,7 @@ export default mixins(
debounceHelper,
workflowHelpers,
).extend({
name: 'executions-view',
name: 'executions-list',
components: {
ExecutionsSidebar,
},
@@ -87,9 +82,7 @@ export default mixins(
hidePreview(): boolean {
const activeNotPresent =
this.filterApplied &&
(this.executions as IExecutionsSummary[]).find(
(ex) => ex.id === this.activeExecution.id,
) === undefined;
!(this.executions as IExecutionsSummary[]).find((ex) => ex.id === this.activeExecution?.id);
return this.loading || !this.executions.length || activeNotPresent;
},
filterApplied(): boolean {
@@ -107,6 +100,31 @@ export default mixins(
totalFinishedExecutionsCount(): number {
return this.workflowsStore.getTotalFinishedExecutionsCount;
},
requestFilter(): IDataObject {
const rFilter: IDataObject = { workflowId: this.currentWorkflow };
if (this.filter.status === 'waiting') {
rFilter.waitTill = true;
} else if (this.filter.status !== '') {
rFilter.finished = this.filter.status === 'success';
}
switch (this.filter.status as ExecutionStatus) {
case 'waiting':
rFilter.status = ['waiting'];
break;
case 'error':
rFilter.status = ['failed', 'crashed'];
break;
case 'success':
rFilter.status = ['success'];
break;
case 'running':
rFilter.status = ['running'];
break;
}
return rFilter;
},
},
watch: {
$route(to: Route, from: Route) {
@@ -179,7 +197,7 @@ export default mixins(
await this.openWorkflow(this.$route.params.name);
this.uiStore.nodeViewInitialized = false;
if (this.workflowsStore.currentWorkflowExecutions.length === 0) {
this.setExecutions();
await this.setExecutions();
}
if (this.activeExecution) {
this.$router
@@ -193,7 +211,7 @@ export default mixins(
},
async onLoadMore(): Promise<void> {
if (!this.loadingMore) {
this.callDebounced('loadMore', { debounceTime: 1000 });
await this.callDebounced('loadMore', { debounceTime: 1000 });
}
},
async loadMore(limit = 20): Promise<void> {
@@ -211,15 +229,9 @@ export default mixins(
lastId = lastItem.id;
}
const requestFilter: IDataObject = { workflowId: this.currentWorkflow };
if (this.filter.status === 'waiting') {
requestFilter.waitTill = true;
} else if (this.filter.status !== '') {
requestFilter.finished = this.filter.status === 'success';
}
let data: IExecutionsListResponse;
try {
data = await this.restApi().getPastExecutions(requestFilter, limit, lastId);
data = await this.restApi().getPastExecutions(this.requestFilter, limit, lastId);
} catch (error) {
this.loadingMore = false;
this.$showError(error, this.$locale.baseText('executionsList.showError.loadMore.title'));
@@ -344,7 +356,7 @@ export default mixins(
if (existingStillRunning && currentFinished) {
existingExecutions[executionIndex] = currentItem;
if (currentItem.id === this.activeExecution.id) {
if (currentItem.id === this.activeExecution?.id) {
updatedActiveExecution = currentItem;
}
}
@@ -371,7 +383,7 @@ export default mixins(
if (updatedActiveExecution !== null) {
this.workflowsStore.activeWorkflowExecution = updatedActiveExecution;
} else {
const activeInList = existingExecutions.some((ex) => ex.id === this.activeExecution.id);
const activeInList = existingExecutions.some((ex) => ex.id === this.activeExecution?.id);
if (!activeInList && this.executions.length > 0) {
this.$router
.push({
@@ -390,7 +402,7 @@ export default mixins(
return [];
}
try {
return await this.workflowsStore.loadCurrentWorkflowExecutions(this.filter);
return await this.workflowsStore.loadCurrentWorkflowExecutions(this.requestFilter);
} catch (error) {
if (error.errorCode === NO_NETWORK_ERROR_CODE) {
this.$showMessage(
@@ -452,7 +464,10 @@ export default mixins(
}
// stop if the execution wasn't found in the first 1000 lookups
if (attemptCount >= 10) return;
if (attemptCount >= 10) {
this.workflowsStore.activeWorkflowExecution = null;
return;
}
// Fetch next batch of executions
await this.loadMore(100);
@@ -619,8 +634,7 @@ export default mixins(
}
},
async loadActiveWorkflows(): Promise<void> {
const activeWorkflows = await this.restApi().getActiveWorkflows();
this.workflowsStore.activeWorkflows = activeWorkflows;
this.workflowsStore.activeWorkflows = await this.restApi().getActiveWorkflows();
},
async onRetryExecution(payload: { execution: IExecutionsSummary; command: string }) {
const loadWorkflow = payload.command === 'current-workflow';

View File

@@ -115,8 +115,7 @@
<script lang="ts">
import ExecutionCard from '@/components/ExecutionsView/ExecutionCard.vue';
import ExecutionsInfoAccordion from '@/components/ExecutionsView/ExecutionsInfoAccordion.vue';
import { VIEWS } from '../../constants';
import { range as _range } from 'lodash';
import { VIEWS } from '@/constants';
import { IExecutionsSummary } from '@/Interface';
import { Route } from 'vue-router';
import Vue from 'vue';
@@ -162,8 +161,6 @@ export default Vue.extend({
},
executionStatuses(): Array<{ id: string; name: string }> {
return [
{ id: 'crashed', name: this.$locale.baseText('executionsList.error') },
{ id: 'new', name: this.$locale.baseText('executionsList.new') },
{ id: 'error', name: this.$locale.baseText('executionsList.error') },
{ id: 'running', name: this.$locale.baseText('executionsList.running') },
{ id: 'success', name: this.$locale.baseText('executionsList.success') },

View File

@@ -43,13 +43,19 @@ export const executionHelpers = mixins(genericHelpers).extend({
if (execution.status === 'waiting' || execution.waitTill) {
status.name = 'waiting';
status.label = this.$locale.baseText('executionsList.waiting');
} else if (execution.status === 'running' || execution.stoppedAt === undefined) {
} else if (
execution.status === 'running' ||
execution.status === 'new' ||
execution.stoppedAt === undefined
) {
status.name = 'running';
status.label = this.$locale.baseText('executionsList.running');
status.runningTime = this.displayTimer(
new Date().getTime() - new Date(execution.startedAt).getTime(),
true,
);
if (execution.startedAt) {
status.runningTime = this.displayTimer(
new Date().getTime() - new Date(execution.startedAt).getTime(),
true,
);
}
} else if (execution.status === 'success' || execution.finished) {
status.name = 'success';
status.label = this.$locale.baseText('executionsList.succeeded');
@@ -59,21 +65,9 @@ export const executionHelpers = mixins(genericHelpers).extend({
true,
);
}
} else if (execution.status === 'crashed') {
status.name = 'crashed';
status.label = this.$locale.baseText('executionsList.error');
if (execution.stoppedAt) {
status.runningTime = this.displayTimer(
new Date(execution.stoppedAt).getTime() - new Date(execution.startedAt).getTime(),
true,
);
}
} else if (execution.status === 'new') {
status.name = 'new';
status.label = this.$locale.baseText('executionsList.new');
} else if (
execution.status === 'error' ||
execution.status === 'failed' ||
execution.status === 'crashed' ||
execution.stoppedAt !== null
) {
status.name = 'error';

View File

@@ -77,7 +77,9 @@ export const restApi = Vue.extend({
getActivationError: (id: string): Promise<IActivationError | undefined> => {
return self.restApi().makeRestApiRequest('GET', `/active/error/${id}`);
},
getCurrentExecutions: (filter: object): Promise<IExecutionsCurrentSummaryExtended[]> => {
getCurrentExecutions: (
filter: IDataObject,
): Promise<IExecutionsCurrentSummaryExtended[]> => {
let sendData = {};
if (filter) {
sendData = {
@@ -179,7 +181,7 @@ export const restApi = Vue.extend({
// Returns all saved executions
// TODO: For sure needs some kind of default filter like last day, with max 10 results, ...
getPastExecutions: (
filter: object,
filter: IDataObject,
limit: number,
lastId?: string,
firstId?: string,

View File

@@ -442,8 +442,6 @@
"executionsList.confirmMessage.headline": "Delete Executions?",
"executionsList.confirmMessage.message": "Are you sure that you want to delete the {numSelected} selected execution(s)?",
"executionsList.clearSelection": "Clear selection",
"executionsList.crashed": "Crashed",
"executionsList.new": "New",
"executionsList.error": "Failed",
"executionsList.filters": "Filters",
"executionsList.loadMore": "Load More",
@@ -482,8 +480,6 @@
"executionsList.id": "Execution ID",
"executionsList.status": "Status",
"executionsList.statusText": "{status} in {time}",
"executionsList.statusCrashed": "{status}",
"executionsList.statusNew": "{status}",
"executionsList.statusRunning": "{status} for {time}",
"executionsList.statusWaiting": "{status} until {time}",
"executionsList.statusUnknown": "Could not complete",

View File

@@ -938,33 +938,24 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
Vue.set(this, 'activeExecutions', newActiveExecutions);
},
async loadCurrentWorkflowExecutions(filter: {
finished: boolean;
status: string;
}): Promise<IExecutionsSummary[]> {
async loadCurrentWorkflowExecutions(requestFilter: IDataObject): Promise<IExecutionsSummary[]> {
let activeExecutions = [];
let finishedExecutions = [];
const requestFilter: IDataObject = { workflowId: this.workflowId };
if (!this.workflowId) {
if (!requestFilter.workflowId) {
return [];
}
try {
const rootStore = useRootStore();
if (filter.status === '' || !filter.finished) {
activeExecutions = await getCurrentExecutions(rootStore.getRestApiContext, requestFilter);
}
if (filter.status === '' || filter.finished) {
if (filter.status === 'waiting') {
requestFilter.waitTill = true;
} else if (filter.status !== '') {
requestFilter.finished = filter.status === 'success';
}
finishedExecutions = await getFinishedExecutions(
rootStore.getRestApiContext,
requestFilter,
);
if (!requestFilter.status || !requestFilter.finished) {
activeExecutions = await getCurrentExecutions(rootStore.getRestApiContext, {
workflowId: requestFilter.workflowId,
});
}
finishedExecutions = await getFinishedExecutions(
rootStore.getRestApiContext,
requestFilter,
);
this.finishedExecutionsCount = finishedExecutions.count;
return [...activeExecutions, ...(finishedExecutions.results || [])];
} catch (error) {