fix(flow): stabilize preview import and dynamic-group rendering

- hide dynamic-group containers in preview graph sanitization

- keep dynamic-group plugin registered in render-only/interactive presets

- refresh canvas immediately after JSON import
This commit is contained in:
2026-02-28 00:38:53 +08:00
parent 92e482e854
commit 1b7596954a
3 changed files with 19 additions and 9 deletions

View File

@@ -111,12 +111,15 @@ const sanitizeLabelProperty = (properties: unknown): Record<string, any> | undef
return nextProperties
}
const sanitizeGraphData = (input?: GraphData | null): GraphData => {
const sanitizeGraphData = (
input?: GraphData | null,
options?: { hideDynamicGroups?: boolean }
): GraphData => {
if (!input || !Array.isArray(input.nodes) || !Array.isArray(input.edges)) {
return { nodes: [], edges: [] }
}
const nodes = input.nodes
const rawNodes = input.nodes
.filter((node): node is NodeData => isPlainObject(node))
.map((node) => {
const nextNode: NodeData = { ...node }
@@ -127,6 +130,12 @@ const sanitizeGraphData = (input?: GraphData | null): GraphData => {
return nextNode
})
const hiddenDynamicGroup = options?.hideDynamicGroups === true
const nodes = hiddenDynamicGroup
? rawNodes.filter((node) => node.type !== 'dynamic-group')
: rawNodes
const nodeIdSet = new Set(nodes.map((node) => node.id))
const edges = input.edges
.filter((edge): edge is EdgeData => isPlainObject(edge))
.map((edge) => {
@@ -137,6 +146,7 @@ const sanitizeGraphData = (input?: GraphData | null): GraphData => {
}
return nextEdge
})
.filter((edge) => !hiddenDynamicGroup || (nodeIdSet.has(edge.sourceNodeId) && nodeIdSet.has(edge.targetNodeId)))
return { nodes, edges }
}
@@ -328,7 +338,7 @@ const initPreviewMode = () => {
// 渲染数据
if (props.data) {
previewLf.value.render(sanitizeGraphData(props.data))
previewLf.value.render(sanitizeGraphData(props.data, { hideDynamicGroups: true }))
}
}
@@ -362,7 +372,7 @@ const getGraphData = (): GraphData | null => {
}
const setGraphData = (data: GraphData) => {
const safeData = sanitizeGraphData(data)
const safeData = sanitizeGraphData(data, { hideDynamicGroups: props.mode === 'preview' })
if (props.mode === 'edit') {
const lfInstance = getLogicFlowInstance()
if (lfInstance) {

View File

@@ -928,7 +928,7 @@ const handleImport = () => {
const target = e.target as FileReader;
const data = JSON.parse(target.result as string);
filesStore.importData(data);
// refreshLogicFlowCanvas('LogicFlow 画布已重新渲染(导入数据)');
refreshLogicFlowCanvas('LogicFlow 画布已重新渲染(导入数据)');
} catch (error) {
console.error('Failed to import file', error);
showMessage('error', '文件格式错误');

View File

@@ -1,5 +1,5 @@
import type LogicFlow from '@logicflow/core'
import { Menu, Label, Snapshot, SelectionSelect, MiniMap, Control } from '@logicflow/extension'
import { Menu, Label, Snapshot, SelectionSelect, MiniMap, Control, DynamicGroup } from '@logicflow/extension'
import { register } from '@logicflow/vue-node-registry'
import ImageNode from './components/flow/nodes/common/ImageNode.vue'
@@ -27,8 +27,9 @@ const DEFAULT_FLOW_NODES: FlowNodeRegistration[] = [
]
const FLOW_PLUGIN_PRESETS: Record<FlowCapabilityLevel, FlowPlugin[]> = {
'render-only': [Snapshot],
interactive: [Menu, Label, Snapshot, SelectionSelect, MiniMap, Control]
// 预览模式也需要 DynamicGroup避免包含 dynamic-group 节点的图在只读渲染时报错
'render-only': [DynamicGroup, Snapshot],
interactive: [DynamicGroup, Menu, Label, Snapshot, SelectionSelect, MiniMap, Control]
}
export function getFlowPluginsByCapability(capability: FlowCapabilityLevel): FlowPlugin[] {
@@ -60,4 +61,3 @@ export function registerFlowNodes(lfInstance: LogicFlow, nodes?: FlowNodeRegistr
const registrations = resolveFlowNodes(nodes)
registrations.forEach((registration) => register(registration, lfInstance))
}