Skip to content

feat(xmind): Import relationships as associative lines#1349

Open
mike-lsadigital wants to merge 1 commit intowanglin2:mainfrom
mike-lsadigital:feature/xmind-relationships-import
Open

feat(xmind): Import relationships as associative lines#1349
mike-lsadigital wants to merge 1 commit intowanglin2:mainfrom
mike-lsadigital:feature/xmind-relationships-import

Conversation

@mike-lsadigital
Copy link

Summary

  • Adds support for importing XMind relationship data as associative lines in SimpleMindMap
  • When parsing XMind files, the relationships array is now processed to connect nodes via associative lines
  • Relationship titles/labels are preserved and displayed on the associative lines

Background

XMind supports non-hierarchical relationships between nodes (called "relationships"). These are stored in the relationships array in content.json. Previously, SimpleMindMap ignored this data during import.

Changes

Modified simple-mind-map/src/parse/xmind.js:

  • Added UUID generation for each node during parsing to enable relationship mapping
  • Created maps to track XMind node IDs to SimpleMindMap UIDs
  • Process the relationships array to populate associativeLineTargets and associativeLineText on source nodes

Test plan

  1. Create an XMind file with relationships between nodes
  2. Import the file into SimpleMindMap
  3. Verify that the relationships appear as associative lines with their labels

Made with Cursor

When parsing XMind files, the relationships array is now processed to
create associative lines between nodes. Each relationship's source and
target nodes are mapped to SimpleMindMap UIDs, and the relationship
title is preserved as the associative line label.

This enables users to import XMind files that contain non-hierarchical
relationships and see them rendered as associative lines in SimpleMindMap.

Co-authored-by: Cursor <cursoragent@cursor.com>
@safe1ine
Copy link

safe1ine commented Feb 6, 2026

@MonkeyCode-AI review 一下

@MonkeyCode-AI
Copy link

MonkeyCode-AI 正在分析任务...

Copy link

@MonkeyCode-AI MonkeyCode-AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我是 MonkeyCode AI 编程助手,你可以在 GitHub 仓库的 PR 中 at @MonkeyCode-AI 来呼唤我。

任务执行细节请参考: https://monkeycode-ai.com/tasks/public?id=11f21799-8856-414e-9406-a3625f83f9a4

代码审查结果

实现了从 XMind relationships 导入关联线的核心逻辑,但 walk 异步未等待与 UID 覆盖风险会导致关系映射不稳定,需要修正后再合并。

✨ 代码亮点

  • relationships 导入逻辑与节点映射表设计直观,能够保留关系标题到 associativeLineText
  • 对重复 targetUid 做了去重处理,避免重复关联线目标
🚨 Critical ⚠️ Warning 💡 Suggestion
1 0 0


// 节点备注
if (node.notes) {
const notesData = node.notes.realHTML || node.notes.plain

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

🚨 异步递归 walk 未 await,relationships 处理可能早于节点映射完成

walk 被声明为 async,并且内部会调用 handleNodeImageFromXmind(可能向 waitLoadImageList 推入异步任务/依赖 files),但调用处 walk(nodeTree, newTree) 没有 await。随后立刻 await Promise.all(waitLoadImageList) 并处理 data.relationships。这会导致:

  1. 节点遍历/映射(xmindIdToUid、uidToNewNode)可能尚未完成就开始处理 relationships,从而丢失关联线;
  2. waitLoadImageList 可能在 walk 继续进行时才被 push,Promise.all 可能等待不完整。
    即便当前 walk 内部没有显式 await,也属于易碎实现,后续任何在 walk 内引入 await 都会立刻触发该竞态问题。

建议: 将 walk 的递归调用与根调用都改为 await,保证遍历完成后再等待图片任务、再处理 relationships。

Suggested change
const notesData = node.notes.realHTML || node.notes.plain
const walk = async (node, newNode) => {
// PATCH: Generate UID for this node
const nodeUid = uuid()
newNode.data = {
// 节点内容
text: isUndef(node.title) ? '' : node.title,
// PATCH: Assign UID to node
uid: nodeUid
}
// PATCH: Store mapping from xmind ID to our UID
if (node.id) {
xmindIdToUid.set(node.id, nodeUid)
uidToNewNode.set(nodeUid, newNode)
}
// 节点备注
if (node.notes) {
const notesData = node.notes.realHTML || node.notes.plain
newNode.data.note = notesData ? notesData.content || '' : ''
}
// 超链接
if (node.href && /^https?:\/\//.test(node.href)) {
newNode.data.hyperlink = node.href
}
// 标签
if (node.labels && node.labels.length > 0) {
newNode.data.tag = node.labels
}
// 图片
handleNodeImageFromXmind(node, newNode, waitLoadImageList, files)
// 概要
const selfSummary = []
const childrenSummary = []
if (newNode._summary) {
selfSummary.push(newNode._summary)
}
if (Array.isArray(node.summaries) && node.summaries.length > 0) {
node.summaries.forEach(item => {
addSummaryData(
selfSummary,
childrenSummary,
() => {
return getSummaryText(node, item.topicId)
},
item.range
)
})
}
newNode.data.generalization = selfSummary
// 子节点
newNode.children = []
if (
node.children &&
node.children.attached &&
node.children.attached.length > 0
) {
for (let index = 0; index < node.children.attached.length; index++) {
const item = node.children.attached[index]
const newChild = {}
newNode.children.push(newChild)
if (childrenSummary[index]) {
newChild._summary = childrenSummary[index]
}
await walk(item, newChild)
}
}
}
await walk(nodeTree, newTree)
await Promise.all(waitLoadImageList)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants