feat(editor): Refactor and unify executions views (no-changelog) (#8538)

This commit is contained in:
Alex Grozav
2024-04-19 07:50:18 +02:00
committed by GitHub
parent eab01876ab
commit a3eea3ac5e
65 changed files with 3601 additions and 2960 deletions

View File

@@ -0,0 +1,50 @@
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
import type { ExecutionSummary } from 'n8n-workflow';
import { i18n } from '@/plugins/i18n';
import { convertToDisplayDate } from '@/utils/formatters/dateFormatter';
describe('useExecutionHelpers()', () => {
describe('getUIDetails()', () => {
it.each([
['waiting', 'waiting', i18n.baseText('executionsList.waiting')],
['canceled', 'unknown', i18n.baseText('executionsList.canceled')],
['running', 'running', i18n.baseText('executionsList.running')],
['new', 'running', i18n.baseText('executionsList.running')],
['success', 'success', i18n.baseText('executionsList.succeeded')],
['error', 'error', i18n.baseText('executionsList.error')],
['crashed', 'error', i18n.baseText('executionsList.error')],
[undefined, 'unknown', 'Status unknown'],
])(
'should return %s status name %s and label %s based on execution status',
async (status, expectedName, expectedLabel) => {
const date = new Date();
const execution = {
id: '1',
startedAt: date,
stoppedAt: date,
status,
};
const { getUIDetails } = useExecutionHelpers();
const uiDetails = getUIDetails(execution as ExecutionSummary);
expect(uiDetails.name).toEqual(expectedName);
expect(uiDetails.label).toEqual(expectedLabel);
expect(uiDetails.runningTime).toEqual('0s');
},
);
});
describe('formatDate()', () => {
it('should return formatted date', async () => {
const { formatDate } = useExecutionHelpers();
const fullDate = new Date();
const { date, time } = convertToDisplayDate(fullDate);
expect(formatDate(fullDate)).toEqual(
i18n.baseText('executionsList.started', {
interpolate: { time, date },
}),
);
});
});
});

View File

@@ -0,0 +1,70 @@
import type { ExecutionSummary } from 'n8n-workflow';
import { convertToDisplayDate } from '@/utils/formatters/dateFormatter';
import { useI18n } from '@/composables/useI18n';
export interface IExecutionUIData {
name: string;
label: string;
startTime: string;
runningTime: string;
}
export function useExecutionHelpers() {
const i18n = useI18n();
function getUIDetails(execution: ExecutionSummary): IExecutionUIData {
const status = {
name: 'unknown',
startTime: formatDate(execution.startedAt),
label: 'Status unknown',
runningTime: '',
};
if (execution.status === 'waiting') {
status.name = 'waiting';
status.label = i18n.baseText('executionsList.waiting');
} else if (execution.status === 'canceled') {
status.label = i18n.baseText('executionsList.canceled');
} else if (execution.status === 'running' || execution.status === 'new') {
status.name = 'running';
status.label = i18n.baseText('executionsList.running');
} else if (execution.status === 'success') {
status.name = 'success';
status.label = i18n.baseText('executionsList.succeeded');
} else if (execution.status === 'error' || execution.status === 'crashed') {
status.name = 'error';
status.label = i18n.baseText('executionsList.error');
}
if (!execution.status) execution.status = 'unknown';
if (execution.startedAt && execution.stoppedAt) {
const stoppedAt = execution.stoppedAt ? new Date(execution.stoppedAt).getTime() : Date.now();
status.runningTime = i18n.displayTimer(
stoppedAt - new Date(execution.startedAt).getTime(),
true,
);
}
return status;
}
function formatDate(fullDate: Date | string | number) {
const { date, time } = convertToDisplayDate(fullDate);
return i18n.baseText('executionsList.started', { interpolate: { time, date } });
}
function isExecutionRetriable(execution: ExecutionSummary): boolean {
return (
['crashed', 'error'].includes(execution.status ?? '') &&
!execution.retryOf &&
!execution.retrySuccessId
);
}
return {
getUIDetails,
formatDate,
isExecutionRetriable,
};
}

View File

@@ -37,6 +37,7 @@ import type { useRouter } from 'vue-router';
import { isEmpty } from '@/utils/typesUtils';
import { useI18n } from '@/composables/useI18n';
import { get } from 'lodash-es';
import { useExecutionsStore } from '@/stores/executions.store';
export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof useRouter> }) {
const nodeHelpers = useNodeHelpers();
@@ -48,6 +49,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
const rootStore = useRootStore();
const uiStore = useUIStore();
const workflowsStore = useWorkflowsStore();
const executionsStore = useExecutionsStore();
// Starts to execute a workflow on server
async function runWorkflowApi(runData: IStartRunData): Promise<IExecutionPushResponse> {
@@ -384,10 +386,10 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
}
try {
await workflowsStore.stopCurrentExecution(executionId);
await executionsStore.stopCurrentExecution(executionId);
} catch (error) {
// Execution stop might fail when the execution has already finished. Let's treat this here.
const execution = await this.workflowsStore.getExecution(executionId);
const execution = await workflowsStore.getExecution(executionId);
if (execution === undefined) {
// execution finished but was not saved (e.g. due to low connectivity)