mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 18:41:14 +00:00
fix(editor): Fix schema view bugs (#14734)
Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
@@ -56,9 +56,6 @@ type Props = {
|
||||
node?: INodeUi | null;
|
||||
data?: IDataObject[];
|
||||
mappingEnabled?: boolean;
|
||||
runIndex?: number;
|
||||
outputIndex?: number;
|
||||
totalRuns?: number;
|
||||
paneType: 'input' | 'output';
|
||||
connectionType?: NodeConnectionType;
|
||||
search?: string;
|
||||
@@ -70,9 +67,6 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
distanceFromActive: 1,
|
||||
node: null,
|
||||
data: () => [],
|
||||
runIndex: 0,
|
||||
outputIndex: 0,
|
||||
totalRuns: 1,
|
||||
connectionType: NodeConnectionTypes.Main,
|
||||
search: '',
|
||||
mappingEnabled: false,
|
||||
@@ -91,20 +85,24 @@ const posthogStore = usePostHog();
|
||||
|
||||
const { getSchemaForExecutionData, getSchemaForJsonSchema, getSchema, filterSchema } =
|
||||
useDataSchema();
|
||||
const { closedNodes, flattenSchema, flattenMultipleSchemas, toggleLeaf, toggleNode } =
|
||||
useFlattenSchema();
|
||||
const { getNodeInputData, getNodeTaskData } = useNodeHelpers();
|
||||
const { closedNodes, flattenSchema, flattenMultipleSchemas, toggleNode } = useFlattenSchema();
|
||||
const { getNodeInputData, getLastRunIndexWithData, hasNodeExecuted } = useNodeHelpers();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'clear:search': [];
|
||||
}>();
|
||||
|
||||
const scroller = ref<RecycleScrollerInstance>();
|
||||
const closedNodesBeforeSearch = ref(new Set<string>());
|
||||
|
||||
const canDraggableDrop = computed(() => ndvStore.canDraggableDrop);
|
||||
const draggableStickyPosition = computed(() => ndvStore.draggableStickyPos);
|
||||
|
||||
const toggleNodeAndScrollTop = (id: string) => {
|
||||
const toggleNodeExclusiveAndScrollTop = (id: string) => {
|
||||
const isClosed = closedNodes.value.has(id);
|
||||
if (isClosed) {
|
||||
closedNodes.value = new Set(items.value.map((item) => item.id));
|
||||
}
|
||||
toggleNode(id);
|
||||
scroller.value?.scrollToItem(0);
|
||||
};
|
||||
@@ -112,13 +110,23 @@ const toggleNodeAndScrollTop = (id: string) => {
|
||||
const getNodeSchema = async (fullNode: INodeUi, connectedNode: IConnectedNode) => {
|
||||
const pinData = workflowsStore.pinDataByNodeName(connectedNode.name);
|
||||
const hasPinnedData = pinData ? pinData.length > 0 : false;
|
||||
const isNodeExecuted = getNodeTaskData(fullNode, props.runIndex) !== null || hasPinnedData;
|
||||
const isNodeExecuted = hasPinnedData || hasNodeExecuted(connectedNode.name);
|
||||
|
||||
const connectedOutputIndexes = connectedNode.indicies.length > 0 ? connectedNode.indicies : [0];
|
||||
const nodeData = connectedOutputIndexes.map((outputIndex) =>
|
||||
getNodeInputData(fullNode, props.runIndex, outputIndex, props.paneType, props.connectionType),
|
||||
);
|
||||
const hasBinary = nodeData.flat().some((data) => !isEmpty(data.binary));
|
||||
const data = pinData ?? nodeData.map(executionDataToJson).flat();
|
||||
const connectedOutputsWithData = connectedOutputIndexes
|
||||
.map((outputIndex) => ({
|
||||
outputIndex,
|
||||
runIndex: getLastRunIndexWithData(fullNode.name, outputIndex, props.connectionType),
|
||||
}))
|
||||
.filter(({ runIndex }) => runIndex !== -1);
|
||||
const nodeData = connectedOutputsWithData
|
||||
.map(({ outputIndex, runIndex }) =>
|
||||
getNodeInputData(fullNode, runIndex, outputIndex, props.paneType, props.connectionType),
|
||||
)
|
||||
.flat();
|
||||
const hasBinary = nodeData.some((data) => !isEmpty(data.binary));
|
||||
const data = pinData ?? executionDataToJson(nodeData);
|
||||
const isDataEmpty = data.length === 0;
|
||||
|
||||
let schema = getSchemaForExecutionData(data);
|
||||
let preview = false;
|
||||
@@ -135,9 +143,11 @@ const getNodeSchema = async (fullNode: INodeUi, connectedNode: IConnectedNode) =
|
||||
schema,
|
||||
connectedOutputIndexes,
|
||||
itemsCount: data.length,
|
||||
runIndex: connectedOutputsWithData[0]?.runIndex ?? 0,
|
||||
preview,
|
||||
hasBinary,
|
||||
isNodeExecuted,
|
||||
isDataEmpty,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -164,7 +174,7 @@ const contextSchema = computed(() => {
|
||||
$workflow: pick(workflowsStore.workflow, ['id', 'name', 'active']),
|
||||
};
|
||||
|
||||
return getSchema(schemaSource);
|
||||
return filterSchema(getSchema(schemaSource), props.search);
|
||||
});
|
||||
|
||||
const contextItems = computed(() => {
|
||||
@@ -178,10 +188,13 @@ const contextItems = computed(() => {
|
||||
|
||||
if (closedNodes.value.has(header.id)) return [header];
|
||||
|
||||
const fields: Renders[] = flattenSchema({
|
||||
schema: contextSchema.value,
|
||||
depth: 1,
|
||||
}).flatMap((renderItem) => {
|
||||
const schema = contextSchema.value;
|
||||
|
||||
if (!schema) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const fields: Renders[] = flattenSchema({ schema, depth: 1 }).flatMap((renderItem) => {
|
||||
const isVars =
|
||||
renderItem.type === 'item' && renderItem.depth === 1 && renderItem.title === '$vars';
|
||||
|
||||
@@ -252,8 +265,16 @@ const nodesSchemas = asyncComputed<SchemaNode[]>(async () => {
|
||||
const nodeType = nodeTypesStore.getNodeType(fullNode.type, fullNode.typeVersion);
|
||||
if (!nodeType) continue;
|
||||
|
||||
const { schema, connectedOutputIndexes, itemsCount, preview, hasBinary, isNodeExecuted } =
|
||||
await getNodeSchema(fullNode, node);
|
||||
const {
|
||||
schema,
|
||||
connectedOutputIndexes,
|
||||
itemsCount,
|
||||
preview,
|
||||
hasBinary,
|
||||
isNodeExecuted,
|
||||
isDataEmpty,
|
||||
runIndex,
|
||||
} = await getNodeSchema(fullNode, node);
|
||||
|
||||
const filteredSchema = filterSchema(schema, search);
|
||||
|
||||
@@ -269,6 +290,8 @@ const nodesSchemas = asyncComputed<SchemaNode[]>(async () => {
|
||||
preview,
|
||||
hasBinary,
|
||||
isNodeExecuted,
|
||||
isDataEmpty,
|
||||
runIndex,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -319,25 +342,28 @@ const noSearchResults = computed(() => {
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.search,
|
||||
(newSearch) => {
|
||||
if (!newSearch) return;
|
||||
closedNodes.value.clear();
|
||||
() => Boolean(props.search),
|
||||
(hasSearch) => {
|
||||
if (hasSearch) {
|
||||
closedNodesBeforeSearch.value = new Set(closedNodes.value);
|
||||
closedNodes.value.clear();
|
||||
} else if (closedNodes.value.size === 0) {
|
||||
closedNodes.value = closedNodesBeforeSearch.value;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Variables & context items should be collapsed by default
|
||||
watch(
|
||||
contextItems,
|
||||
(currentContextItems) => {
|
||||
currentContextItems
|
||||
// Collapse all nodes except the first
|
||||
const unwatchItems = watch(items, (newItems) => {
|
||||
if (newItems.length < 2) return;
|
||||
closedNodes.value = new Set(
|
||||
newItems
|
||||
.filter((item) => item.type === 'header')
|
||||
.forEach((item) => {
|
||||
closedNodes.value.add(item.id);
|
||||
});
|
||||
},
|
||||
{ once: true, immediate: true },
|
||||
);
|
||||
.slice(1)
|
||||
.map((item) => item.id),
|
||||
);
|
||||
unwatchItems();
|
||||
});
|
||||
|
||||
const onDragStart = (el: HTMLElement, data?: string) => {
|
||||
ndvStore.draggableStartDragging({
|
||||
@@ -356,13 +382,14 @@ const onDragEnd = (el: HTMLElement) => {
|
||||
|
||||
const isPreview = parentNode?.preview ?? false;
|
||||
const hasCredential = !isEmpty(parentNode?.node.credentials);
|
||||
const runIndex = Number(el.dataset.runIndex);
|
||||
|
||||
const telemetryPayload = {
|
||||
src_node_type: el.dataset.nodeType,
|
||||
src_field_name: el.dataset.name ?? '',
|
||||
src_nodes_back: el.dataset.depth,
|
||||
src_run_index: props.runIndex,
|
||||
src_runs_total: props.totalRuns,
|
||||
src_run_index: runIndex,
|
||||
src_runs_total: runIndex,
|
||||
src_field_nest_level: el.dataset.level ?? 0,
|
||||
src_view: isPreview ? 'schema_preview' : 'schema',
|
||||
src_has_credential: hasCredential,
|
||||
@@ -424,8 +451,8 @@ const onDragEnd = (el: HTMLElement) => {
|
||||
v-if="item.type === 'header'"
|
||||
v-bind="item"
|
||||
:collapsed="closedNodes.has(item.id)"
|
||||
@click:toggle="toggleLeaf(item.id)"
|
||||
@click="toggleNodeAndScrollTop(item.id)"
|
||||
@click:toggle="toggleNode(item.id)"
|
||||
@click="toggleNodeExclusiveAndScrollTop(item.id)"
|
||||
/>
|
||||
<VirtualSchemaItem
|
||||
v-else-if="item.type === 'item'"
|
||||
@@ -434,7 +461,7 @@ const onDragEnd = (el: HTMLElement) => {
|
||||
:draggable="mappingEnabled"
|
||||
:collapsed="closedNodes.has(item.id)"
|
||||
:highlight="ndvStore.highlightDraggables"
|
||||
@click="toggleLeaf(item.id)"
|
||||
@click="toggleNode(item.id)"
|
||||
>
|
||||
</VirtualSchemaItem>
|
||||
|
||||
@@ -461,13 +488,14 @@ const onDragEnd = (el: HTMLElement) => {
|
||||
>
|
||||
<template #link>
|
||||
<NodeExecuteButton
|
||||
:node-name="item.nodeName"
|
||||
v-if="ndvStore.activeNodeName"
|
||||
:node-name="ndvStore.activeNodeName"
|
||||
:label="i18n.baseText('ndv.input.noOutputData.executePrevious')"
|
||||
text
|
||||
telemetry-source="inputs"
|
||||
hide-icon
|
||||
size="small"
|
||||
class="execute-button"
|
||||
:class="$style.executeButton"
|
||||
/>
|
||||
</template>
|
||||
</i18n-t>
|
||||
@@ -481,6 +509,12 @@ const onDragEnd = (el: HTMLElement) => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" module>
|
||||
.executeButton {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.full-height {
|
||||
height: 100%;
|
||||
@@ -532,8 +566,4 @@ const onDragEnd = (el: HTMLElement) => {
|
||||
padding-bottom: var(--spacing-xs);
|
||||
margin-left: calc((var(--spacing-xl) * var(--schema-level)));
|
||||
}
|
||||
|
||||
.execute-button {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user