mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 04:34:06 -08:00
fix(editor): Add 'Stop execution' button to execution preview (#4632)
* ✨ Adding `Stop execution` button to execution preview * ✨ Added execution timer for running executions * 💄 Adjusting spinner size and text color * 🔥 Removing excessive popup error message when opening failed executions preview * 🐛 Handling execution stopping when workflow is not saving manual executions
This commit is contained in:
parent
0ade24dfaf
commit
be7672a177
|
@ -18,7 +18,8 @@
|
|||
<n8n-spinner v-if="executionUIDetails.name === 'running'" size="small" :class="[$style.spinner, 'mr-4xs']"/>
|
||||
<n8n-text :class="$style.statusLabel" size="small">{{ executionUIDetails.label }}</n8n-text>
|
||||
<n8n-text v-if="executionUIDetails.name === 'running'" :color="isActive? 'text-dark' : 'text-base'" size="small">
|
||||
{{ $locale.baseText('executionDetails.runningTimeRunning', { interpolate: { time: executionUIDetails.runningTime } }) }}
|
||||
{{ $locale.baseText('executionDetails.runningTimeRunning') }}
|
||||
<execution-time :start-time="execution.startedAt"/>
|
||||
</n8n-text>
|
||||
<n8n-text v-else-if="executionUIDetails.name !== 'waiting' && executionUIDetails.name !== 'unknown'" :color="isActive? 'text-dark' : 'text-base'" size="small">
|
||||
{{ $locale.baseText('executionDetails.runningTimeFinished', { interpolate: { time: executionUIDetails.runningTime } }) }}
|
||||
|
@ -56,6 +57,7 @@ import { executionHelpers, IExecutionUIData } from '../mixins/executionsHelpers'
|
|||
import { VIEWS } from '../../constants';
|
||||
import { showMessage } from '../mixins/showMessage';
|
||||
import { restApi } from '../mixins/restApi';
|
||||
import ExecutionTime from '@/components/ExecutionTime.vue';
|
||||
|
||||
export default mixins(
|
||||
executionHelpers,
|
||||
|
@ -63,6 +65,9 @@ export default mixins(
|
|||
restApi,
|
||||
).extend({
|
||||
name: 'execution-card',
|
||||
components: {
|
||||
ExecutionTime,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
VIEWS,
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
<template>
|
||||
<div v-if="executionUIDetails && executionUIDetails.name === 'running'" :class="$style.runningInfo">
|
||||
<div :class="$style.spinner">
|
||||
<font-awesome-icon icon="spinner" spin />
|
||||
<n8n-spinner type="ring" />
|
||||
</div>
|
||||
<n8n-text :class="$style.runningMessage">
|
||||
<n8n-text :class="$style.runningMessage" color="text-light">
|
||||
{{ $locale.baseText('executionDetails.runningMessage') }}
|
||||
</n8n-text>
|
||||
<n8n-button class="mt-l" type="tertiary" size="medium" @click="handleStopClick">
|
||||
{{ $locale.baseText('executionsList.stopExecution') }}
|
||||
</n8n-button>
|
||||
</div>
|
||||
<div v-else :class="$style.previewContainer">
|
||||
<div :class="{[$style.executionDetails]: true, [$style.sidebarCollapsed]: sidebarCollapsed }" v-if="activeExecution">
|
||||
|
@ -111,6 +114,9 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
|
|||
handleRetryClick(command: string): void {
|
||||
this.$emit('retryExecution', { execution: this.activeExecution, command });
|
||||
},
|
||||
handleStopClick(): void {
|
||||
this.$emit('stopExecution');
|
||||
},
|
||||
onRetryButtonBlur(event: FocusEvent): void {
|
||||
// Hide dropdown when clicking outside of current document
|
||||
const retryDropdown = this.$refs.retryDropdown as Vue & { hide: () => void } | undefined;
|
||||
|
@ -146,6 +152,14 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
|
|||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
div div {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.running, .spinner { color: var(--color-warning); }
|
||||
.waiting { color: var(--color-secondary); }
|
||||
.success { color: var(--color-success); }
|
||||
|
@ -158,11 +172,6 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
|
|||
margin-top: var(--spacing-4xl);
|
||||
}
|
||||
|
||||
.spinner {
|
||||
font-size: var(--font-size-2xl);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.runningMessage {
|
||||
width: 200px;
|
||||
margin-top: var(--spacing-l);
|
||||
|
|
|
@ -12,7 +12,12 @@
|
|||
@refresh="loadAutoRefresh"
|
||||
/>
|
||||
<div :class="$style.content" v-if="!hidePreview">
|
||||
<router-view name="executionPreview" @deleteCurrentExecution="onDeleteCurrentExecution" @retryExecution="onRetryExecution"/>
|
||||
<router-view
|
||||
name="executionPreview"
|
||||
@deleteCurrentExecution="onDeleteCurrentExecution"
|
||||
@retryExecution="onRetryExecution"
|
||||
@stopExecution="onStopExecution"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="executions.length === 0 && filterApplied" :class="$style.noResultsContainer">
|
||||
<n8n-text color="text-base" size="medium" align="center">
|
||||
|
@ -240,6 +245,29 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
|
|||
type: 'success',
|
||||
});
|
||||
},
|
||||
async onStopExecution(): Promise<void> {
|
||||
const activeExecutionId = this.$route.params.executionId;
|
||||
|
||||
try {
|
||||
await this.restApi().stopCurrentExecution(activeExecutionId);
|
||||
|
||||
this.$showMessage({
|
||||
title: this.$locale.baseText('executionsList.showMessage.stopExecution.title'),
|
||||
message: this.$locale.baseText(
|
||||
'executionsList.showMessage.stopExecution.message',
|
||||
{ interpolate: { activeExecutionId } },
|
||||
),
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
this.loadAutoRefresh();
|
||||
} catch (error) {
|
||||
this.$showError(
|
||||
error,
|
||||
this.$locale.baseText('executionsList.showError.stopExecution.title'),
|
||||
);
|
||||
}
|
||||
},
|
||||
onFilterUpdated(newFilter: { finished: boolean, status: string }): void {
|
||||
this.filter = newFilter;
|
||||
this.setExecutions();
|
||||
|
@ -304,9 +332,12 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
|
|||
const activeNotInTheList = existingExecutions.find(ex => ex.id === this.activeExecution.id) === undefined;
|
||||
if (activeNotInTheList && this.executions.length > 0) {
|
||||
this.$router.push({
|
||||
name: VIEWS.EXECUTION_PREVIEW,
|
||||
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
|
||||
}).catch(()=>{});;
|
||||
name: VIEWS.EXECUTION_PREVIEW,
|
||||
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
|
||||
}).catch(()=>{});
|
||||
} else if (this.executions.length === 0) {
|
||||
this.$router.push({ name: VIEWS.EXECUTION_HOME }).catch(()=>{});
|
||||
this.workflowsStore.activeWorkflowExecution = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -398,7 +398,7 @@
|
|||
"executionDetails.readOnly.youreViewingTheLogOf": "You're viewing the log of a previous execution. You cannot<br />\n\t\tmake changes since this execution already occurred. Make changes<br />\n\t\tto this workflow by clicking on its name on the left.",
|
||||
"executionDetails.retry": "Retry of execution",
|
||||
"executionDetails.runningTimeFinished": "in {time}",
|
||||
"executionDetails.runningTimeRunning": "for {time}",
|
||||
"executionDetails.runningTimeRunning": "for",
|
||||
"executionDetails.runningMessage": "Execution is running. It will show here once finished.",
|
||||
"executionDetails.workflow": "workflow",
|
||||
"executionsLandingPage.emptyState.noTrigger.heading": "Set up the first step. Then execute your workflow",
|
||||
|
|
|
@ -725,21 +725,11 @@ export default mixins(
|
|||
}
|
||||
}
|
||||
|
||||
if (!nodeErrorFound) {
|
||||
const resultError = data.data.resultData.error;
|
||||
const errorMessage = this.$getExecutionError(data.data);
|
||||
const shouldTrack = resultError && 'node' in resultError && resultError.node!.type.startsWith('n8n-nodes-base');
|
||||
this.$showMessage({
|
||||
title: 'Failed execution',
|
||||
message: errorMessage,
|
||||
type: 'error',
|
||||
}, shouldTrack);
|
||||
if (data.data.resultData.error.stack) {
|
||||
// Display some more information for now in console to make debugging easier
|
||||
// TODO: Improve this in the future by displaying in UI
|
||||
console.error(`Execution ${executionId} error:`); // eslint-disable-line no-console
|
||||
console.error(data.data.resultData.error.stack); // eslint-disable-line no-console
|
||||
}
|
||||
if (!nodeErrorFound && data.data.resultData.error.stack) {
|
||||
// Display some more information for now in console to make debugging easier
|
||||
// TODO: Improve this in the future by displaying in UI
|
||||
console.error(`Execution ${executionId} error:`); // eslint-disable-line no-console
|
||||
console.error(data.data.resultData.error.stack); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
if ((data as IExecutionsSummary).waitTill) {
|
||||
|
|
Loading…
Reference in a new issue