n8n/packages/editor-ui/src/composables/useExecutionHelpers.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

132 lines
3.7 KiB
TypeScript
Raw Permalink Normal View History

import type { ExecutionSummary, RelatedExecution } from 'n8n-workflow';
import { convertToDisplayDate } from '@/utils/formatters/dateFormatter';
import { useI18n } from '@/composables/useI18n';
import { useRouter } from 'vue-router';
import { VIEWS } from '@/constants';
import { useTelemetry } from './useTelemetry';
import type { IRunDataDisplayMode } from '@/Interface';
export interface IExecutionUIData {
name: string;
label: string;
createdAt: string;
startTime: string;
runningTime: string;
showTimestamp: boolean;
tags: Array<{ id: string; name: string }>;
}
export function useExecutionHelpers() {
const i18n = useI18n();
const router = useRouter();
const telemetry = useTelemetry();
function getUIDetails(execution: ExecutionSummary): IExecutionUIData {
const status = {
name: 'unknown',
createdAt: execution.createdAt?.toString() ?? '',
startTime: formatDate(execution.startedAt),
label: 'Status unknown',
runningTime: '',
showTimestamp: true,
tags: execution.annotation?.tags ?? [],
};
if (execution.status === 'new') {
status.name = 'new';
status.label = i18n.baseText('executionsList.new');
status.showTimestamp = false;
} else if (execution.status === 'waiting') {
status.name = 'waiting';
status.label = i18n.baseText('executionsList.waiting');
status.showTimestamp = false;
} else if (execution.status === 'canceled') {
status.label = i18n.baseText('executionsList.canceled');
} else if (execution.status === 'running') {
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.retrySuccessId;
}
function openExecutionInNewTab(executionId: string, workflowId: string): void {
const route = router.resolve({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: workflowId, executionId },
});
window.open(route.href, '_blank');
}
function resolveRelatedExecutionUrl(metadata: {
parentExecution?: RelatedExecution;
subExecution?: RelatedExecution;
}): string {
const info = metadata.parentExecution || metadata.subExecution;
if (!info) {
return '';
}
const { workflowId, executionId } = info;
return router.resolve({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: workflowId, executionId },
}).fullPath;
}
function trackOpeningRelatedExecution(
metadata: { parentExecution?: RelatedExecution; subExecution?: RelatedExecution },
view: IRunDataDisplayMode,
) {
const info = metadata.parentExecution || metadata.subExecution;
if (!info) {
return;
}
telemetry.track(
metadata.parentExecution
? 'User clicked parent execution button'
: 'User clicked inspect sub-workflow',
{
view,
},
);
}
return {
getUIDetails,
formatDate,
isExecutionRetriable,
openExecutionInNewTab,
trackOpeningRelatedExecution,
resolveRelatedExecutionUrl,
};
}