fix(editor): Fix inaccurate message in log view when input data is empty (#16234)

This commit is contained in:
Suguru Inoue
2025-06-16 12:09:57 +02:00
committed by GitHub
parent 3fcabd40b3
commit e93fd1a689
4 changed files with 54 additions and 14 deletions

View File

@@ -193,7 +193,8 @@ const contextItems = computed(() => {
return []; return [];
} }
const fields: Renders[] = flattenSchema({ schema, depth: 1 }).flatMap((renderItem) => { const flatSchema = flattenSchema({ schema, depth: 1, isDataEmpty: false });
const fields: Renders[] = flatSchema.flatMap((renderItem) => {
const isVars = const isVars =
renderItem.type === 'item' && renderItem.depth === 1 && renderItem.title === '$vars'; renderItem.type === 'item' && renderItem.depth === 1 && renderItem.title === '$vars';
@@ -320,7 +321,14 @@ const flattenedNodes = computed(() =>
); );
const flattenNodeSchema = computed(() => const flattenNodeSchema = computed(() =>
nodeSchema.value ? flattenSchema({ schema: nodeSchema.value, depth: 0, level: -1 }) : [], nodeSchema.value
? flattenSchema({
schema: nodeSchema.value,
depth: 0,
level: -1,
isDataEmpty: props.data.length === 0,
})
: [],
); );
/** /**

View File

@@ -817,6 +817,7 @@ describe('useFlattenSchema', () => {
expect( expect(
useFlattenSchema().flattenSchema({ useFlattenSchema().flattenSchema({
schema, schema,
isDataEmpty: false,
}).length, }).length,
).toBe(3); ).toBe(3);
}); });
@@ -835,8 +836,18 @@ describe('useFlattenSchema', () => {
}, },
], ],
}; };
const node1Schema = flattenSchema({ schema, expressionPrefix: '$("First Node")', depth: 1 }); const node1Schema = flattenSchema({
const node2Schema = flattenSchema({ schema, expressionPrefix: '$("Second Node")', depth: 1 }); schema,
expressionPrefix: '$("First Node")',
depth: 1,
isDataEmpty: false,
});
const node2Schema = flattenSchema({
schema,
expressionPrefix: '$("Second Node")',
depth: 1,
isDataEmpty: false,
});
expect(node1Schema[0].id).not.toBe(node2Schema[0].id); expect(node1Schema[0].id).not.toBe(node2Schema[0].id);
}); });

View File

@@ -347,6 +347,7 @@ export const useFlattenSchema = () => {
}; };
const flattenSchema = ({ const flattenSchema = ({
isDataEmpty,
schema, schema,
nodeType, nodeType,
nodeName, nodeName,
@@ -356,6 +357,7 @@ export const useFlattenSchema = () => {
level = 0, level = 0,
preview, preview,
}: { }: {
isDataEmpty: boolean;
schema: Schema; schema: Schema;
expressionPrefix?: string; expressionPrefix?: string;
nodeType?: string; nodeType?: string;
@@ -367,7 +369,7 @@ export const useFlattenSchema = () => {
}): Renders[] => { }): Renders[] => {
// only show empty item for the first level // only show empty item for the first level
if (isEmptySchema(schema) && level < 0) { if (isEmptySchema(schema) && level < 0) {
return [emptyItem('emptyData')]; return [emptyItem(isDataEmpty ? 'emptyData' : 'emptySchema')];
} }
const expression = `{{ ${expressionPrefix ? expressionPrefix + schema.path : schema.path.slice(1)} }}`; const expression = `{{ ${expressionPrefix ? expressionPrefix + schema.path : schema.path.slice(1)} }}`;
@@ -403,6 +405,7 @@ export const useFlattenSchema = () => {
.map((item) => { .map((item) => {
const itemPrefix = schema.type === 'array' ? schema.key : ''; const itemPrefix = schema.type === 'array' ? schema.key : '';
return flattenSchema({ return flattenSchema({
isDataEmpty,
schema: item, schema: item,
expressionPrefix, expressionPrefix,
nodeType, nodeType,
@@ -474,6 +477,7 @@ export const useFlattenSchema = () => {
acc = acc.concat( acc = acc.concat(
flattenSchema({ flattenSchema({
isDataEmpty: item.isDataEmpty,
schema: item.schema, schema: item.schema,
depth: item.depth, depth: item.depth,
nodeType: item.node.type, nodeType: item.node.type,

View File

@@ -10,16 +10,13 @@ import {
createTestWorkflow, createTestWorkflow,
createTestWorkflowObject, createTestWorkflowObject,
} from '@/__tests__/mocks'; } from '@/__tests__/mocks';
import { mockedStore } from '@/__tests__/utils';
import { useSettingsStore } from '@/stores/settings.store';
import { type FrontendSettings } from '@n8n/api-types';
import { LOG_DETAILS_PANEL_STATE } from '@/features/logs/logs.constants'; import { LOG_DETAILS_PANEL_STATE } from '@/features/logs/logs.constants';
import type { LogEntry } from '../logs.types'; import type { LogEntry } from '../logs.types';
import { createTestLogEntry } from '../__test__/mocks'; import { createTestLogEntry } from '../__test__/mocks';
import { NodeConnectionTypes } from 'n8n-workflow';
describe('LogDetailsPanel', () => { describe('LogDetailsPanel', () => {
let pinia: TestingPinia; let pinia: TestingPinia;
let settingsStore: ReturnType<typeof mockedStore<typeof useSettingsStore>>;
const aiNode = createTestNode({ name: 'AI Agent' }); const aiNode = createTestNode({ name: 'AI Agent' });
const workflowData = createTestWorkflow({ const workflowData = createTestWorkflow({
@@ -84,11 +81,6 @@ describe('LogDetailsPanel', () => {
beforeEach(() => { beforeEach(() => {
pinia = createTestingPinia({ stubActions: false, fakeApp: true }); pinia = createTestingPinia({ stubActions: false, fakeApp: true });
settingsStore = mockedStore(useSettingsStore);
settingsStore.isEnterpriseFeatureEnabled = {} as FrontendSettings['enterprise'];
localStorage.clear();
}); });
it('should show name, run status, input, and output of the node', async () => { it('should show name, run status, input, and output of the node', async () => {
@@ -155,4 +147,29 @@ describe('LogDetailsPanel', () => {
expect(rendered.emitted()).toEqual({ toggleOutputOpen: [[false]] }); expect(rendered.emitted()).toEqual({ toggleOutputOpen: [[false]] });
}); });
it('should display correct message when input data is empty', async () => {
const nodeA = createTestNode({ name: 'A' });
const nodeB = createTestNode({ name: 'B' });
const runDataA = createTestTaskData({ data: { [NodeConnectionTypes.Main]: [[{ json: {} }]] } });
const runDataB = createTestTaskData({ source: [{ previousNode: 'A' }] });
const workflow = createTestWorkflowObject({ nodes: [nodeA, nodeB] });
const rendered = render({
isOpen: true,
logEntry: createLogEntry({
node: nodeB,
runIndex: 0,
runData: runDataB,
workflow,
execution: { resultData: { runData: { A: [runDataA], B: [runDataB] } } },
}),
panels: LOG_DETAILS_PANEL_STATE.BOTH,
});
expect(
await within(rendered.getByTestId('log-details-input')).findByText(
"No fields - item(s) exist, but they're empty",
),
).toBeInTheDocument();
});
}); });