feat(core): Show sub-node error on the logs pane. Open logs pane on sub-node error (#10248)
This commit is contained in:
@@ -6,6 +6,7 @@ import type {
|
||||
SupplyData,
|
||||
ExecutionError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import type { Sandbox } from 'n8n-nodes-base/dist/nodes/Code/Sandbox';
|
||||
import { getSandboxContext } from 'n8n-nodes-base/dist/nodes/Code/Sandbox';
|
||||
@@ -208,7 +209,7 @@ export class ToolCode implements INodeType {
|
||||
try {
|
||||
response = await runFunction(query);
|
||||
} catch (error: unknown) {
|
||||
executionError = error as ExecutionError;
|
||||
executionError = new NodeOperationError(this.getNode(), error as ExecutionError);
|
||||
response = `There was an error: "${executionError.message}"`;
|
||||
}
|
||||
|
||||
@@ -229,6 +230,7 @@ export class ToolCode implements INodeType {
|
||||
} else {
|
||||
void this.addOutputData(NodeConnectionType.AiTool, index, [[{ json: { response } }]]);
|
||||
}
|
||||
|
||||
return response;
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -21,6 +21,7 @@ import type { BaseTextKey } from '@/plugins/i18n';
|
||||
|
||||
type Props = {
|
||||
error: NodeError | NodeApiError | NodeOperationError;
|
||||
compact?: boolean;
|
||||
};
|
||||
|
||||
const props = defineProps<Props>();
|
||||
@@ -377,7 +378,7 @@ function copySuccess() {
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="node-error-view__info">
|
||||
<div v-if="!compact" class="node-error-view__info">
|
||||
<div class="node-error-view__info-header">
|
||||
<p class="node-error-view__info-title">
|
||||
{{ i18n.baseText('nodeErrorView.details.title') }}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<div :class="$style.titleSection">
|
||||
<template v-if="hasAiMetadata">
|
||||
<n8n-radio-buttons
|
||||
data-test-id="ai-output-mode-select"
|
||||
v-model="outputMode"
|
||||
:options="outputTypes"
|
||||
@update:model-value="onUpdateOutputMode"
|
||||
@@ -83,6 +84,7 @@
|
||||
<template v-if="outputMode === 'logs' && node" #content>
|
||||
<RunDataAi :node="node" :run-index="runIndex" />
|
||||
</template>
|
||||
|
||||
<template #recovered-artificial-output-data>
|
||||
<div :class="$style.recoveredOutputData">
|
||||
<n8n-text tag="div" :bold="true" color="text-dark" size="large">{{
|
||||
@@ -101,8 +103,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import type { IRunData, IRunExecutionData, Workflow } from 'n8n-workflow';
|
||||
import { ref, computed, onMounted, watch } from 'vue';
|
||||
import type { IRunData, IRunExecutionData, NodeError, Workflow } from 'n8n-workflow';
|
||||
import RunData from './RunData.vue';
|
||||
import RunInfo from './RunInfo.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
@@ -183,7 +185,7 @@ const pinnedData = usePinnedData(activeNode, {
|
||||
|
||||
// Data
|
||||
|
||||
const outputMode = ref<OutputType>('regular');
|
||||
const outputMode = ref<OutputType>(OUTPUT_TYPE.REGULAR);
|
||||
const outputTypes = ref([
|
||||
{ label: i18n.baseText('ndv.output.outType.regular'), value: OUTPUT_TYPE.REGULAR },
|
||||
{ label: i18n.baseText('ndv.output.outType.logs'), value: OUTPUT_TYPE.LOGS },
|
||||
@@ -213,6 +215,16 @@ const hasAiMetadata = computed(() => {
|
||||
return false;
|
||||
});
|
||||
|
||||
// Determine the initial output mode to logs if the node has an error and the logs are available
|
||||
const defaultOutputMode = computed<OutputType>(() => {
|
||||
const hasError =
|
||||
workflowRunData.value &&
|
||||
node.value &&
|
||||
(workflowRunData.value[node.value.name]?.[props.runIndex]?.error as NodeError);
|
||||
|
||||
return Boolean(hasError) && hasAiMetadata.value ? OUTPUT_TYPE.LOGS : OUTPUT_TYPE.REGULAR;
|
||||
});
|
||||
|
||||
const isNodeRunning = computed(() => {
|
||||
return !!node.value && workflowsStore.isNodeExecuting(node.value.name);
|
||||
});
|
||||
@@ -351,6 +363,20 @@ const onUpdateOutputMode = (outputMode: OutputType) => {
|
||||
}
|
||||
};
|
||||
|
||||
// Set the initial output mode when the component is mounted
|
||||
onMounted(() => {
|
||||
outputMode.value = defaultOutputMode.value;
|
||||
});
|
||||
|
||||
// In case the output panel was opened when the node has not run yet,
|
||||
// defaultOutputMode will be "regular" at the time of mounting.
|
||||
// This is why we need to watch the defaultOutputMode and change the outputMode to "logs" if the node has run and criteria are met.
|
||||
watch(defaultOutputMode, (newValue: OutputType, oldValue: OutputType) => {
|
||||
if (newValue === OUTPUT_TYPE.LOGS && oldValue === OUTPUT_TYPE.REGULAR && hasNodeRun.value) {
|
||||
outputMode.value = defaultOutputMode.value;
|
||||
}
|
||||
});
|
||||
|
||||
const activatePane = () => {
|
||||
emit('activatePane');
|
||||
};
|
||||
|
||||
@@ -281,7 +281,15 @@
|
||||
})
|
||||
}}
|
||||
</n8n-text>
|
||||
<slot v-else-if="$slots['content']" name="content"></slot>
|
||||
<div v-else-if="$slots['content']">
|
||||
<NodeErrorView
|
||||
v-if="workflowRunErrorAsNodeError"
|
||||
:error="workflowRunErrorAsNodeError"
|
||||
:class="$style.inlineError"
|
||||
compact
|
||||
/>
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
<NodeErrorView
|
||||
v-else-if="workflowRunErrorAsNodeError"
|
||||
:error="workflowRunErrorAsNodeError"
|
||||
@@ -1147,7 +1155,7 @@ export default defineComponent({
|
||||
const error = this.workflowRunData?.[this.node.name]?.[this.runIndex]?.error;
|
||||
const errorsToTrack = ['unknown error'];
|
||||
|
||||
if (error && errorsToTrack.some((e) => error.message.toLowerCase().includes(e))) {
|
||||
if (error && errorsToTrack.some((e) => error.message?.toLowerCase().includes(e))) {
|
||||
this.$telemetry.track(
|
||||
`User encountered an error: "${error.message}"`,
|
||||
{
|
||||
@@ -1776,6 +1784,13 @@ export default defineComponent({
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.inlineError {
|
||||
line-height: var(--font-line-height-xloose);
|
||||
padding-left: var(--spacing-s);
|
||||
padding-right: var(--spacing-s);
|
||||
padding-bottom: var(--spacing-s);
|
||||
}
|
||||
|
||||
.outputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
Reference in New Issue
Block a user