Skip to content

Commit 744e2da

Browse files
authored
fix(editor): Support 'View Execution' links with multiple branches (#14345)
1 parent 9c8a5f9 commit 744e2da

File tree

3 files changed

+89
-76
lines changed

3 files changed

+89
-76
lines changed

packages/frontend/editor-ui/src/components/RunData.vue

Lines changed: 16 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ import {
8686
} from '@n8n/design-system';
8787
import { storeToRefs } from 'pinia';
8888
import { useRoute } from 'vue-router';
89-
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
9089
import { useUIStore } from '@/stores/ui.store';
9190
import { useSchemaPreviewStore } from '@/stores/schemaPreview.store';
9291
import { asyncComputed } from '@vueuse/core';
9392
import { usePostHog } from '@/stores/posthog.store';
93+
import ViewSubExecution from './ViewSubExecution.vue';
9494
9595
const LazyRunDataTable = defineAsyncComponent(
9696
async () => await import('@/components/RunDataTable.vue'),
@@ -200,7 +200,6 @@ const nodeHelpers = useNodeHelpers();
200200
const externalHooks = useExternalHooks();
201201
const telemetry = useTelemetry();
202202
const i18n = useI18n();
203-
const { trackOpeningRelatedExecution, resolveRelatedExecutionUrl } = useExecutionHelpers();
204203
205204
const node = toRef(props, 'node');
206205
@@ -558,12 +557,6 @@ const activeTaskMetadata = computed((): ITaskMetadata | null => {
558557
return workflowRunData.value?.[node.value.name]?.[props.runIndex]?.metadata ?? null;
559558
});
560559
561-
const hasRelatedExecution = computed(() => {
562-
return Boolean(
563-
activeTaskMetadata.value?.subExecution ?? activeTaskMetadata.value?.parentExecution,
564-
);
565-
});
566-
567560
const hasInputOverwrite = computed((): boolean => {
568561
if (!node.value) {
569562
return false;
@@ -1313,26 +1306,6 @@ function onSearchClear() {
13131306
document.dispatchEvent(new KeyboardEvent('keyup', { key: '/' }));
13141307
}
13151308
1316-
function getExecutionLinkLabel(task: ITaskMetadata): string | undefined {
1317-
if (task.parentExecution) {
1318-
return i18n.baseText('runData.openParentExecution', {
1319-
interpolate: { id: task.parentExecution.executionId },
1320-
});
1321-
}
1322-
1323-
if (task.subExecution) {
1324-
if (activeTaskMetadata.value?.subExecutionsCount === 1) {
1325-
return i18n.baseText('runData.openSubExecutionSingle');
1326-
} else {
1327-
return i18n.baseText('runData.openSubExecutionWithId', {
1328-
interpolate: { id: task.subExecution.executionId },
1329-
});
1330-
}
1331-
}
1332-
1333-
return;
1334-
}
1335-
13361309
defineExpose({ enterEditMode });
13371310
</script>
13381311

@@ -1504,20 +1477,11 @@ defineExpose({ enterEditMode });
15041477

15051478
<slot name="run-info"></slot>
15061479
</div>
1507-
1508-
<a
1509-
v-if="
1510-
activeTaskMetadata && hasRelatedExecution && !(paneType === 'input' && hasInputOverwrite)
1511-
"
1512-
:class="$style.relatedExecutionInfo"
1513-
data-test-id="related-execution-link"
1514-
:href="resolveRelatedExecutionUrl(activeTaskMetadata)"
1515-
target="_blank"
1516-
@click.stop="trackOpeningRelatedExecution(activeTaskMetadata, displayMode)"
1517-
>
1518-
<N8nIcon icon="external-link-alt" size="xsmall" />
1519-
{{ getExecutionLinkLabel(activeTaskMetadata) }}
1520-
</a>
1480+
<ViewSubExecution
1481+
v-if="activeTaskMetadata && !(paneType === 'input' && hasInputOverwrite)"
1482+
:task-metadata="activeTaskMetadata"
1483+
:display-mode="displayMode"
1484+
/>
15211485
</div>
15221486

15231487
<slot v-if="!displaysMultipleNodes" name="before-data" />
@@ -1544,6 +1508,11 @@ defineExpose({ enterEditMode });
15441508
data-test-id="branches"
15451509
>
15461510
<slot v-if="inputSelectLocation === 'outputs'" name="input-select"></slot>
1511+
<ViewSubExecution
1512+
v-if="activeTaskMetadata && !(paneType === 'input' && hasInputOverwrite)"
1513+
:task-metadata="activeTaskMetadata"
1514+
:display-mode="displayMode"
1515+
/>
15471516

15481517
<div :class="$style.tabs">
15491518
<N8nTabs
@@ -1594,20 +1563,11 @@ defineExpose({ enterEditMode });
15941563
}}
15951564
</span>
15961565
</N8nText>
1597-
1598-
<a
1599-
v-if="
1600-
activeTaskMetadata && hasRelatedExecution && !(paneType === 'input' && hasInputOverwrite)
1601-
"
1602-
:class="$style.relatedExecutionInfo"
1603-
data-test-id="related-execution-link"
1604-
:href="resolveRelatedExecutionUrl(activeTaskMetadata)"
1605-
target="_blank"
1606-
@click.stop="trackOpeningRelatedExecution(activeTaskMetadata, displayMode)"
1607-
>
1608-
<N8nIcon icon="external-link-alt" size="xsmall" />
1609-
{{ getExecutionLinkLabel(activeTaskMetadata) }}
1610-
</a>
1566+
<ViewSubExecution
1567+
v-if="activeTaskMetadata && !(paneType === 'input' && hasInputOverwrite)"
1568+
:task-metadata="activeTaskMetadata"
1569+
:display-mode="displayMode"
1570+
/>
16111571
</div>
16121572

16131573
<div ref="dataContainerRef" :class="$style.dataContainer" data-test-id="ndv-data-container">
@@ -2304,15 +2264,6 @@ defineExpose({ enterEditMode });
23042264
.schema {
23052265
padding: 0 var(--spacing-s);
23062266
}
2307-
2308-
.relatedExecutionInfo {
2309-
font-size: var(--font-size-s);
2310-
margin-left: var(--spacing-3xs);
2311-
2312-
svg {
2313-
padding-bottom: 2px;
2314-
}
2315-
}
23162267
</style>
23172268

23182269
<style lang="scss" scoped>

packages/frontend/editor-ui/src/components/RunDataAi/RunDataAiContent.vue

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import type { INodeTypeDescription, NodeConnectionType, NodeError } from 'n8n-wo
66
import { computed } from 'vue';
77
import NodeIcon from '@/components/NodeIcon.vue';
88
import AiRunContentBlock from './AiRunContentBlock.vue';
9-
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
109
import { useI18n } from '@/composables/useI18n';
1110
import { formatTokenUsageCount, getConsumedTokens } from '@/components/RunDataAi/utils';
1211
import ConsumedTokensDetails from '@/components/ConsumedTokensDetails.vue';
12+
import ViewSubExecution from '../ViewSubExecution.vue';
1313
1414
interface RunMeta {
1515
startTimeMs: number;
@@ -30,7 +30,6 @@ const props = defineProps<{
3030
const nodeTypesStore = useNodeTypesStore();
3131
const workflowsStore = useWorkflowsStore();
3232
33-
const { trackOpeningRelatedExecution, resolveRelatedExecutionUrl } = useExecutionHelpers();
3433
const i18n = useI18n();
3534
3635
const consumedTokensSum = computed(() => {
@@ -105,15 +104,8 @@ const outputError = computed(() => {
105104
}}
106105
</n8n-tooltip>
107106
</li>
108-
<li v-if="runMeta?.subExecution">
109-
<a
110-
:href="resolveRelatedExecutionUrl(runMeta)"
111-
target="_blank"
112-
@click.stop="trackOpeningRelatedExecution(runMeta, 'ai')"
113-
>
114-
<N8nIcon icon="external-link-alt" size="xsmall" />
115-
{{ i18n.baseText('runData.openSubExecutionSingle') }}
116-
</a>
107+
<li v-if="runMeta">
108+
<ViewSubExecution :task-metadata="runMeta" :display-mode="'ai'" :inline="true" />
117109
</li>
118110
<li v-if="(consumedTokensSum?.totalTokens ?? 0) > 0" :class="$style.tokensUsage">
119111
{{
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<script setup lang="ts">
2+
import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
3+
import { useI18n } from '@/composables/useI18n';
4+
import type { IRunDataDisplayMode } from '@/Interface';
5+
import type { ITaskMetadata } from 'n8n-workflow';
6+
import { computed } from 'vue';
7+
8+
const { trackOpeningRelatedExecution, resolveRelatedExecutionUrl } = useExecutionHelpers();
9+
const i18n = useI18n();
10+
11+
const props = withDefaults(
12+
defineProps<{
13+
taskMetadata: ITaskMetadata;
14+
displayMode: IRunDataDisplayMode;
15+
inline?: boolean;
16+
}>(),
17+
{
18+
inline: false,
19+
},
20+
);
21+
22+
const hasRelatedExecution = computed(() => {
23+
return Boolean(props.taskMetadata.subExecution ?? props.taskMetadata.parentExecution);
24+
});
25+
26+
function getExecutionLinkLabel(task: ITaskMetadata): string | undefined {
27+
if (task.parentExecution) {
28+
return i18n.baseText('runData.openParentExecution', {
29+
interpolate: { id: task.parentExecution.executionId },
30+
});
31+
}
32+
33+
if (task.subExecution) {
34+
if (props.taskMetadata.subExecutionsCount === 1) {
35+
return i18n.baseText('runData.openSubExecutionSingle');
36+
} else {
37+
return i18n.baseText('runData.openSubExecutionWithId', {
38+
interpolate: { id: task.subExecution.executionId },
39+
});
40+
}
41+
}
42+
43+
return;
44+
}
45+
</script>
46+
47+
<template>
48+
<a
49+
v-if="hasRelatedExecution"
50+
:class="{ [$style.relatedExecutionInfo]: !inline }"
51+
data-test-id="related-execution-link"
52+
:href="resolveRelatedExecutionUrl(taskMetadata)"
53+
target="_blank"
54+
@click.stop="trackOpeningRelatedExecution(taskMetadata, displayMode)"
55+
>
56+
<N8nIcon icon="external-link-alt" size="xsmall" />
57+
{{ getExecutionLinkLabel(taskMetadata) }}
58+
</a>
59+
</template>
60+
61+
<style lang="scss" module>
62+
.relatedExecutionInfo {
63+
font-size: var(--font-size-s);
64+
margin-left: var(--spacing-3xs);
65+
66+
svg {
67+
padding-bottom: var(--spacing-5xs);
68+
}
69+
}
70+
</style>

0 commit comments

Comments
 (0)