fix(editor): Execution page bug fixes (#5122)

* fix(editor): Global exec list adding tooltips

* fix(editor): Global exec list fix indefinite waiting status display

* fix(editor): Global exec list fix indefinite waiting status display

* fix(editor): Global exec list remove ellipsis menu from running execs
This commit is contained in:
Csaba Tuncsik 2023-01-13 12:42:34 +01:00 committed by GitHub
parent 14454243e7
commit 665eaef925
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 50 deletions

View file

@ -60,6 +60,7 @@
<th></th> <th></th>
<th></th> <th></th>
<th></th> <th></th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -86,10 +87,13 @@
</td> </td>
<td> <td>
<div :class="$style.statusColumn"> <div :class="$style.statusColumn">
<span v-if="execution.stoppedAt === undefined" :class="$style.spinner"> <span v-if="isRunning(execution)" :class="$style.spinner">
<font-awesome-icon icon="spinner" spin /> <font-awesome-icon icon="spinner" spin />
</span> </span>
<i18n :path="getStatusTextTranslationPath(execution)"> <i18n
v-if="!isWaitTillIndefinite(execution)"
:path="getStatusTextTranslationPath(execution)"
>
<template #status> <template #status>
<span :class="$style.status">{{ getStatusText(execution) }}</span> <span :class="$style.status">{{ getStatusText(execution) }}</span>
</template> </template>
@ -109,6 +113,12 @@
<execution-time v-else :start-time="execution.startedAt" /> <execution-time v-else :start-time="execution.startedAt" />
</template> </template>
</i18n> </i18n>
<n8n-tooltip v-else placement="top">
<template #content>
<span>{{ getStatusTooltipText(execution) }}</span>
</template>
<span :class="$style.status">{{ getStatusText(execution) }}</span>
</n8n-tooltip>
</div> </div>
</td> </td>
<td> <td>
@ -129,18 +139,15 @@
</span> </span>
</td> </td>
<td> <td>
<font-awesome-icon v-if="execution.mode === 'manual'" icon="flask" /> <n8n-tooltip v-if="execution.mode === 'manual'" placement="top">
<template #content>
<span>{{ $locale.baseText('executionsList.test') }}</span>
</template>
<font-awesome-icon icon="flask" />
</n8n-tooltip>
</td> </td>
<td> <td>
<div :class="$style.actionsContainer"> <div :class="$style.buttonCell">
<n8n-button
v-if="execution.stoppedAt === undefined || execution.waitTill"
size="small"
outline
:label="$locale.baseText('executionsList.stop')"
@click.stop="stopExecution(execution.id)"
:loading="stoppingExecutions.includes(execution.id)"
/>
<n8n-button <n8n-button
v-if="execution.stoppedAt !== undefined && execution.id" v-if="execution.stoppedAt !== undefined && execution.id"
size="small" size="small"
@ -151,7 +158,23 @@
</div> </div>
</td> </td>
<td> <td>
<el-dropdown trigger="click" @command="handleActionItemClick"> <div :class="$style.buttonCell">
<n8n-button
v-if="execution.stoppedAt === undefined || execution.waitTill"
size="small"
outline
:label="$locale.baseText('executionsList.stop')"
@click.stop="stopExecution(execution.id)"
:loading="stoppingExecutions.includes(execution.id)"
/>
</div>
</td>
<td>
<el-dropdown
v-if="!isRunning(execution)"
trigger="click"
@command="handleActionItemClick"
>
<span class="retry-button"> <span class="retry-button">
<n8n-icon-button <n8n-icon-button
text text
@ -235,7 +258,7 @@ import Vue from 'vue';
import ExecutionTime from '@/components/ExecutionTime.vue'; import ExecutionTime from '@/components/ExecutionTime.vue';
import WorkflowActivator from '@/components/WorkflowActivator.vue'; import WorkflowActivator from '@/components/WorkflowActivator.vue';
import { externalHooks } from '@/mixins/externalHooks'; import { externalHooks } from '@/mixins/externalHooks';
import { VIEWS } from '@/constants'; import { VIEWS, WAIT_TIME_UNLIMITED } from '@/constants';
import { restApi } from '@/mixins/restApi'; import { restApi } from '@/mixins/restApi';
import { genericHelpers } from '@/mixins/genericHelpers'; import { genericHelpers } from '@/mixins/genericHelpers';
import { executionHelpers } from '@/mixins/executionsHelpers'; import { executionHelpers } from '@/mixins/executionsHelpers';
@ -254,6 +277,8 @@ import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui'; import { useUIStore } from '@/stores/ui';
import { useWorkflowsStore } from '@/stores/workflows'; import { useWorkflowsStore } from '@/stores/workflows';
type ExecutionStatus = 'failed' | 'success' | 'waiting' | 'running' | 'unknown';
export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, showMessage).extend( export default mixins(externalHooks, genericHelpers, executionHelpers, restApi, showMessage).extend(
{ {
name: 'ExecutionsList', name: 'ExecutionsList',
@ -528,22 +553,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
this.deleteExecution(commandData.execution); this.deleteExecution(commandData.execution);
} }
}, },
getRowClass(execution: IExecutionsSummary): string {
const classes: string[] = [this.$style.execRow];
if (execution.waitTill) {
classes.push(this.$style.waiting);
} else if (execution.stoppedAt === undefined) {
classes.push(this.$style.running);
} else if (execution.finished) {
classes.push(this.$style.success);
} else if (execution.stoppedAt !== null) {
classes.push(this.$style.failed);
} else {
classes.push(this.$style.unknown);
}
return classes.join(' ');
},
getWorkflowName(workflowId: string): string | undefined { getWorkflowName(workflowId: string): string | undefined {
const workflow = this.workflows.find((data) => data.id === workflowId); const workflow = this.workflows.find((data) => data.id === workflowId);
if (workflow === undefined) { if (workflow === undefined) {
@ -784,16 +793,35 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
this.isDataLoading = false; this.isDataLoading = false;
}, },
getStatus(execution: IExecutionsSummary): ExecutionStatus {
let status: ExecutionStatus = 'unknown';
if (execution.waitTill) {
status = 'waiting';
} else if (execution.stoppedAt === undefined) {
status = 'running';
} else if (execution.finished) {
status = 'success';
} else if (execution.stoppedAt !== null) {
status = 'failed';
} else {
status = 'unknown';
}
return status;
},
getRowClass(execution: IExecutionsSummary): string {
return [this.$style.execRow, this.$style[this.getStatus(execution)]].join(' ');
},
getStatusText(entry: IExecutionsSummary): string { getStatusText(entry: IExecutionsSummary): string {
const status = this.getStatus(entry);
let text = ''; let text = '';
if (entry.waitTill) { if (status === 'waiting') {
text = this.$locale.baseText('executionsList.waiting'); text = this.$locale.baseText('executionsList.waiting');
} else if (entry.stoppedAt === undefined) { } else if (status === 'running') {
text = this.$locale.baseText('executionsList.running'); text = this.$locale.baseText('executionsList.running');
} else if (entry.finished) { } else if (status === 'success') {
text = this.$locale.baseText('executionsList.succeeded'); text = this.$locale.baseText('executionsList.succeeded');
} else if (entry.stoppedAt !== null) { } else if (status === 'failed') {
text = this.$locale.baseText('executionsList.error'); text = this.$locale.baseText('executionsList.error');
} else { } else {
text = this.$locale.baseText('executionsList.unknown'); text = this.$locale.baseText('executionsList.unknown');
@ -802,15 +830,16 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
return text; return text;
}, },
getStatusTextTranslationPath(entry: IExecutionsSummary): string { getStatusTextTranslationPath(entry: IExecutionsSummary): string {
const status = this.getStatus(entry);
let path = ''; let path = '';
if (entry.waitTill) { if (status === 'waiting') {
path = 'executionsList.statusWaiting'; path = 'executionsList.statusWaiting';
} else if (entry.stoppedAt === undefined) { } else if (status === 'running') {
path = 'executionsList.statusRunning'; path = 'executionsList.statusRunning';
} else if (entry.finished) { } else if (status === 'success') {
path = 'executionsList.statusText'; path = 'executionsList.statusText';
} else if (entry.stoppedAt !== null) { } else if (status === 'failed') {
path = 'executionsList.statusText'; path = 'executionsList.statusText';
} else { } else {
path = 'executionsList.statusUnknown'; path = 'executionsList.statusUnknown';
@ -818,6 +847,18 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
return path; return path;
}, },
getStatusTooltipText(entry: IExecutionsSummary): string {
const status = this.getStatus(entry);
let text = '';
if (status === 'waiting' && this.isWaitTillIndefinite(entry)) {
text = this.$locale.baseText(
'executionsList.statusTooltipText.theWorkflowIsWaitingIndefinitely',
);
}
return text;
},
async stopExecution(activeExecutionId: string) { async stopExecution(activeExecutionId: string) {
try { try {
// Add it to the list of currently stopping executions that we // Add it to the list of currently stopping executions that we
@ -868,6 +909,15 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
} }
this.isDataLoading = true; this.isDataLoading = true;
}, },
isWaitTillIndefinite(execution: IExecutionsSummary): boolean {
if (!execution.waitTill) {
return false;
}
return new Date(execution.waitTill).toISOString() === WAIT_TIME_UNLIMITED;
},
isRunning(execution: IExecutionsSummary): boolean {
return this.getStatus(execution) === 'running';
},
}, },
}, },
); );
@ -936,6 +986,10 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
color: var(--color-danger); color: var(--color-danger);
} }
.waiting & {
color: var(--color-secondary);
}
.success & { .success & {
font-weight: var(--font-weight-normal); font-weight: var(--font-weight-normal);
} }
@ -949,7 +1003,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
} }
} }
.actionsContainer { .buttonCell {
overflow: hidden; overflow: hidden;
button { button {
@ -960,10 +1014,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, restApi,
.execRow:hover & { .execRow:hover & {
transform: translateX(0); transform: translateX(0);
} }
&:not(:first-child) {
margin-left: 5px;
}
} }
} }

View file

@ -64,12 +64,16 @@
activatorIcon="redo" activatorIcon="redo"
@select="onRetryMenuItemSelect" @select="onRetryMenuItemSelect"
/> />
<font-awesome-icon <n8n-tooltip v-if="execution.mode === 'manual'" placement="top">
v-if="execution.mode === 'manual'" <template #content>
:class="[$style.icon, $style.manual]" <span>{{ $locale.baseText('executionsList.test') }}</span>
:title="$locale.baseText('executionsList.manual')" </template>
icon="flask" <font-awesome-icon
/> v-if="execution.mode === 'manual'"
:class="[$style.icon, $style.manual]"
icon="flask"
/>
</n8n-tooltip>
</div> </div>
</router-link> </router-link>
</div> </div>

View file

@ -454,7 +454,7 @@
"executionsList.selectStatus": "Select Status", "executionsList.selectStatus": "Select Status",
"executionsList.selectWorkflow": "Select Workflow", "executionsList.selectWorkflow": "Select Workflow",
"executionsList.selected": "{numSelected} execution selected:", "executionsList.selected": "{numSelected} execution selected:",
"executionsList.manual": "Manual execution", "executionsList.test": "Test execution",
"executionsList.showError.handleDeleteSelected.title": "Problem deleting executions", "executionsList.showError.handleDeleteSelected.title": "Problem deleting executions",
"executionsList.showError.loadMore.title": "Problem loading executions", "executionsList.showError.loadMore.title": "Problem loading executions",
"executionsList.showError.loadWorkflows.title": "Problem loading workflows", "executionsList.showError.loadWorkflows.title": "Problem loading workflows",
@ -484,6 +484,7 @@
"executionsList.workflowExecutions": "Workflow Executions", "executionsList.workflowExecutions": "Workflow Executions",
"executionsList.view": "View", "executionsList.view": "View",
"executionsList.stop": "Stop", "executionsList.stop": "Stop",
"executionsList.statusTooltipText.theWorkflowIsWaitingIndefinitely": "The workflow is waiting indefinitely for an incoming webhook call.",
"executionSidebar.executionName": "Execution {id}", "executionSidebar.executionName": "Execution {id}",
"executionSidebar.searchPlaceholder": "Search executions...", "executionSidebar.searchPlaceholder": "Search executions...",
"executionView.onPaste.title": "Cannot paste here", "executionView.onPaste.title": "Cannot paste here",