fix: Show correct message on retry (#14321)

This commit is contained in:
Michael Kret
2025-04-02 17:20:21 +03:00
committed by GitHub
parent df9ea095fc
commit 501963f568
7 changed files with 120 additions and 27 deletions

View File

@@ -236,7 +236,7 @@ export class ExecutionService {
throw new UnexpectedError('The retry did not start for an unknown reason.'); throw new UnexpectedError('The retry did not start for an unknown reason.');
} }
return !!executionData.finished; return executionData.status;
} }
async delete(req: ExecutionRequest.Delete, sharedWorkflowIds: string[]) { async delete(req: ExecutionRequest.Delete, sharedWorkflowIds: string[]) {

View File

@@ -14,6 +14,7 @@ import { getResourcePermissions } from '@/permissions';
import { useExecutionsStore } from '@/stores/executions.store'; import { useExecutionsStore } from '@/stores/executions.store';
import { useSettingsStore } from '@/stores/settings.store'; import { useSettingsStore } from '@/stores/settings.store';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import { executionRetryMessage } from '@/utils/executionUtils';
import { N8nButton, N8nCheckbox, N8nTableBase } from '@n8n/design-system'; import { N8nButton, N8nCheckbox, N8nTableBase } from '@n8n/design-system';
import { useIntersectionObserver } from '@vueuse/core'; import { useIntersectionObserver } from '@vueuse/core';
import { ElSkeletonItem } from 'element-plus'; import { ElSkeletonItem } from 'element-plus';
@@ -243,18 +244,11 @@ async function retryOriginalExecution(execution: ExecutionSummary) {
async function retryExecution(execution: ExecutionSummary, loadWorkflow?: boolean) { async function retryExecution(execution: ExecutionSummary, loadWorkflow?: boolean) {
try { try {
const retrySuccessful = await executionsStore.retryExecution(execution.id, loadWorkflow); const retryStatus = await executionsStore.retryExecution(execution.id, loadWorkflow);
const retryMessage = executionRetryMessage(retryStatus);
if (retrySuccessful) { if (retryMessage) {
toast.showMessage({ toast.showMessage(retryMessage);
title: i18n.baseText('executionsList.showMessage.retrySuccessfulTrue.title'),
type: 'success',
});
} else {
toast.showMessage({
title: i18n.baseText('executionsList.showMessage.retrySuccessfulFalse.title'),
type: 'error',
});
} }
} catch (error) { } catch (error) {
toast.showError(error, i18n.baseText('executionsList.showError.retryExecution.title')); toast.showError(error, i18n.baseText('executionsList.showError.retryExecution.title'));

View File

@@ -784,8 +784,12 @@
"executionsList.showError.retryExecution.title": "Problem with retry", "executionsList.showError.retryExecution.title": "Problem with retry",
"executionsList.showError.stopExecution.title": "Problem stopping execution", "executionsList.showError.stopExecution.title": "Problem stopping execution",
"executionsList.showMessage.handleDeleteSelected.title": "Execution deleted", "executionsList.showMessage.handleDeleteSelected.title": "Execution deleted",
"executionsList.showMessage.retrySuccessfulFalse.title": "Retry unsuccessful", "executionsList.showMessage.retryError.title": "Retry unsuccessful",
"executionsList.showMessage.retrySuccessfulTrue.title": "Retry successful", "executionsList.showMessage.retrySuccess.title": "Retry successful",
"executionsList.showMessage.retryWaiting.title": "Retry waiting",
"executionsList.showMessage.retryCrashed.title": "Retry crashed",
"executionsList.showMessage.retryCanceled.title": "Retry canceled",
"executionsList.showMessage.retryRunning.title": "Retry running",
"executionsList.showMessage.stopExecution.message": "Execution ID {activeExecutionId}", "executionsList.showMessage.stopExecution.message": "Execution ID {activeExecutionId}",
"executionsList.showMessage.stopExecution.title": "Execution stopped", "executionsList.showMessage.stopExecution.title": "Execution stopped",
"executionsList.startedAt": "Started", "executionsList.startedAt": "Started",

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import type { IDataObject, ExecutionSummary, AnnotationVote } from 'n8n-workflow'; import type { IDataObject, ExecutionSummary, AnnotationVote, ExecutionStatus } from 'n8n-workflow';
import type { import type {
ExecutionFilterType, ExecutionFilterType,
ExecutionsQueryFilter, ExecutionsQueryFilter,
@@ -240,7 +240,7 @@ export const useExecutionsStore = defineStore('executions', () => {
); );
} }
async function retryExecution(id: string, loadWorkflow?: boolean): Promise<boolean> { async function retryExecution(id: string, loadWorkflow?: boolean): Promise<ExecutionStatus> {
return await makeRestApiRequest( return await makeRestApiRequest(
rootStore.restApiContext, rootStore.restApiContext,
'POST', 'POST',

View File

@@ -210,3 +210,54 @@ export function hasTrimmedItem(taskData: ITaskData[]) {
export function hasTrimmedData(runData: IRunData) { export function hasTrimmedData(runData: IRunData) {
return Object.keys(runData).some((nodeName) => hasTrimmedItem(runData[nodeName])); return Object.keys(runData).some((nodeName) => hasTrimmedItem(runData[nodeName]));
} }
export function executionRetryMessage(executionStatus: ExecutionStatus):
| {
title: string;
type: 'error' | 'info' | 'success';
}
| undefined {
if (executionStatus === 'success') {
return {
title: i18n.baseText('executionsList.showMessage.retrySuccess.title'),
type: 'success',
};
}
if (executionStatus === 'waiting') {
return {
title: i18n.baseText('executionsList.showMessage.retryWaiting.title'),
type: 'info',
};
}
if (executionStatus === 'running') {
return {
title: i18n.baseText('executionsList.showMessage.retryRunning.title'),
type: 'info',
};
}
if (executionStatus === 'crashed') {
return {
title: i18n.baseText('executionsList.showMessage.retryCrashed.title'),
type: 'error',
};
}
if (executionStatus === 'canceled') {
return {
title: i18n.baseText('executionsList.showMessage.retryCanceled.title'),
type: 'error',
};
}
if (executionStatus === 'error') {
return {
title: i18n.baseText('executionsList.showMessage.retryError.title'),
type: 'error',
};
}
return undefined;
}

View File

@@ -6,6 +6,7 @@ import {
stringifyExpressionResult, stringifyExpressionResult,
unwrapExpression, unwrapExpression,
} from './expressions'; } from './expressions';
import { executionRetryMessage } from './executionUtils';
describe('Utils: Expressions', () => { describe('Utils: Expressions', () => {
describe('stringifyExpressionResult()', () => { describe('stringifyExpressionResult()', () => {
@@ -108,4 +109,52 @@ describe('Utils: Expressions', () => {
expect(shouldConvertToExpression('test {{ value }}', true)).toBe(false); expect(shouldConvertToExpression('test {{ value }}', true)).toBe(false);
}); });
}); });
describe('executionRetryMessage', () => {
it('returns success message for success status', () => {
expect(executionRetryMessage('success')).toEqual({
title: 'Retry successful',
type: 'success',
});
});
it('returns info message for waiting status', () => {
expect(executionRetryMessage('waiting')).toEqual({
title: 'Retry waiting',
type: 'info',
});
});
it('returns info message for running status', () => {
expect(executionRetryMessage('running')).toEqual({
title: 'Retry running',
type: 'info',
});
});
it('returns error message for crashed status', () => {
expect(executionRetryMessage('crashed')).toEqual({
title: 'Retry crashed',
type: 'error',
});
});
it('returns error message for canceled status', () => {
expect(executionRetryMessage('canceled')).toEqual({
title: 'Retry canceled',
type: 'error',
});
});
it('returns error message for error status', () => {
expect(executionRetryMessage('error')).toEqual({
title: 'Retry unsuccessful',
type: 'error',
});
});
it('returns undefined for an unknown status', () => {
expect(executionRetryMessage('unknown')).toBeUndefined();
});
});
}); });

View File

@@ -14,6 +14,7 @@ import type { ExecutionSummary } from 'n8n-workflow';
import { useDebounce } from '@/composables/useDebounce'; import { useDebounce } from '@/composables/useDebounce';
import { useTelemetry } from '@/composables/useTelemetry'; import { useTelemetry } from '@/composables/useTelemetry';
import { useCanvasOperations } from '@/composables/useCanvasOperations'; import { useCanvasOperations } from '@/composables/useCanvasOperations';
import { executionRetryMessage } from '@/utils/executionUtils';
const executionsStore = useExecutionsStore(); const executionsStore = useExecutionsStore();
const workflowsStore = useWorkflowsStore(); const workflowsStore = useWorkflowsStore();
@@ -277,18 +278,12 @@ async function onExecutionRetry(payload: { id: string; loadWorkflow: boolean })
async function retryExecution(payload: { id: string; loadWorkflow: boolean }) { async function retryExecution(payload: { id: string; loadWorkflow: boolean }) {
try { try {
const retrySuccessful = await executionsStore.retryExecution(payload.id, payload.loadWorkflow); const retryStatus = await executionsStore.retryExecution(payload.id, payload.loadWorkflow);
if (retrySuccessful) { const retryMessage = executionRetryMessage(retryStatus);
toast.showMessage({
title: i18n.baseText('executionsList.showMessage.retrySuccessfulTrue.title'), if (retryMessage) {
type: 'success', toast.showMessage(retryMessage);
});
} else {
toast.showMessage({
title: i18n.baseText('executionsList.showMessage.retrySuccessfulFalse.title'),
type: 'error',
});
} }
} catch (error) { } catch (error) {
toast.showError(error, i18n.baseText('executionsList.showError.retryExecution.title')); toast.showError(error, i18n.baseText('executionsList.showError.retryExecution.title'));