fix(editor): Don't render now when startedAt is null (#15283)

This commit is contained in:
Danny Martini
2025-05-14 10:31:52 +02:00
committed by GitHub
parent 0cddc9576f
commit 44ecad5883
12 changed files with 150 additions and 13 deletions

View File

@@ -157,4 +157,48 @@ describe('GlobalExecutionsListItem', () => {
expect(globalExecutionsListItemQueuedTooltipRenderSpy).toHaveBeenCalled();
});
afterEach(() => {
vitest.useRealTimers();
});
it('uses `createdAt` to calculate running time if `startedAt` is undefined', async () => {
const createdAt = new Date('2024-09-27T12:00:00Z');
const now = new Date('2024-09-27T12:30:00Z');
vitest.useFakeTimers({ now });
const { getByTestId } = renderComponent({
props: {
execution: { status: 'running', id: 123, workflowName: 'Test Workflow', createdAt },
workflowPermissions: {},
concurrencyCap: 5,
},
});
const executionTimeElement = getByTestId('execution-time');
expect(executionTimeElement).toBeVisible();
expect(executionTimeElement.textContent).toBe('-1727438401s');
});
it('uses `createdAt` to calculate running time if `startedAt` is undefined and `stoppedAt` is defined', async () => {
const createdAt = new Date('2024-09-27T12:00:00Z');
const now = new Date('2024-09-27T12:30:00Z');
vitest.useFakeTimers({ now });
const { getByTestId } = renderComponent({
props: {
execution: {
status: 'running',
id: 123,
workflowName: 'Test Workflow',
createdAt,
stoppedAt: now,
},
workflowPermissions: {},
concurrencyCap: 5,
},
});
const executionTimeElement = getByTestId('execution-time');
expect(executionTimeElement).toBeVisible();
expect(executionTimeElement.textContent).toBe('30:00m');
});
});

View File

@@ -130,7 +130,7 @@ const formattedStoppedAtDate = computed(() => {
return props.execution.stoppedAt
? locale.displayTimer(
new Date(props.execution.stoppedAt).getTime() -
new Date(props.execution.startedAt).getTime(),
new Date(props.execution.startedAt ?? props.execution.createdAt).getTime(),
true,
)
: '';
@@ -233,11 +233,11 @@ async function handleActionItemClick(commandData: Command) {
<td>
{{ formattedStartedAtDate }}
</td>
<td>
<td data-test-id="execution-time">
<template v-if="formattedStoppedAtDate">
{{ formattedStoppedAtDate }}
</template>
<ExecutionsTime v-else :start-time="execution.startedAt" />
<ExecutionsTime v-else :start-time="execution.startedAt ?? execution.createdAt" />
</td>
<td>
<span v-if="execution.id">{{ execution.id }}</span>

View File

@@ -172,4 +172,29 @@ describe('WorkflowExecutionsCard', () => {
expect(executionTimeElement).toBeVisible();
expect(executionTimeElement.textContent).toBe('27 Sep - Starting soon');
});
afterEach(() => {
vitest.useRealTimers();
});
test('uses `createdAt` to calculate running time if `startedAt` is undefined', () => {
const createdAt = new Date('2024-09-27T12:00:00Z');
const now = new Date('2024-09-27T12:30:00Z');
vitest.useFakeTimers({ now });
const props = {
execution: {
id: '1',
mode: 'webhook',
status: 'running',
createdAt: createdAt.toISOString(),
},
workflowPermissions: { execute: true },
};
const { getByTestId } = renderComponent({ props });
const executionTimeElement = getByTestId('execution-time-in-status');
expect(executionTimeElement).toBeVisible();
expect(executionTimeElement.textContent).toBe('for -1727438401s');
});
});

View File

@@ -108,9 +108,11 @@ function onRetryMenuItemSelect(action: string): void {
v-if="executionUIDetails.name === 'running'"
:color="isActive ? 'text-dark' : 'text-base'"
size="small"
data-test-id="execution-time-in-status"
>
{{ locale.baseText('executionDetails.runningTimeRunning') }}
<ExecutionsTime :start-time="execution.startedAt" />
<!-- Just here to make typescript happy, since `startedAt` will always be defined for running executions -->
<ExecutionsTime :start-time="execution.startedAt ?? execution.createdAt" />
</N8nText>
<N8nText
v-if="executionUIDetails.name === 'new' && execution.createdAt"