mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-10 06:34:05 -08:00
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:
parent
14454243e7
commit
665eaef925
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue