389 lines
12 KiB
Rust
389 lines
12 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
use std::collections::BTreeMap;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapProjection {
|
|
pub schema: String,
|
|
pub map_id: String,
|
|
pub root_node: String,
|
|
#[serde(default)]
|
|
pub nodes: Vec<MindmapProjectionNode>,
|
|
#[serde(default)]
|
|
pub edges: Vec<MindmapProjectionEdge>,
|
|
#[serde(default)]
|
|
pub layout_hints: Value,
|
|
pub revision: u64,
|
|
pub owner: MindmapProjectionOwner,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapProjectionNode {
|
|
pub node_id: String,
|
|
pub title: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub parent_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapProjectionEdge {
|
|
pub edge_id: String,
|
|
pub from_node_id: String,
|
|
pub to_node_id: String,
|
|
pub edge_kind: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub enum MindmapProjectionOwner {
|
|
RustKernel,
|
|
CompatBlob,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub enum MindmapProjectionSource {
|
|
Kernel,
|
|
CompatBlob,
|
|
AdapterCache,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapKernelProjection {
|
|
pub schema: String,
|
|
pub document_id: String,
|
|
pub mindmap_id: String,
|
|
pub root_node_id: String,
|
|
pub revision: u64,
|
|
#[serde(default)]
|
|
pub nodes: Vec<MindmapKernelNode>,
|
|
#[serde(default)]
|
|
pub edges: Vec<MindmapKernelEdge>,
|
|
#[serde(default)]
|
|
pub summaries: Vec<MindmapSummary>,
|
|
#[serde(default)]
|
|
pub associative_lines: Vec<MindmapAssociativeLine>,
|
|
#[serde(default)]
|
|
pub layout: Value,
|
|
#[serde(default)]
|
|
pub theme: Value,
|
|
#[serde(default)]
|
|
pub view: Value,
|
|
pub capabilities: MindmapKernelCapabilities,
|
|
pub source: MindmapProjectionSource,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapKernelNode {
|
|
pub node_id: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub parent_id: Option<String>,
|
|
pub text: String,
|
|
#[serde(default)]
|
|
pub order: i64,
|
|
#[serde(default)]
|
|
pub collapsed: bool,
|
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
|
pub style: BTreeMap<String, Value>,
|
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
|
pub refs: BTreeMap<String, Value>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapKernelEdge {
|
|
pub edge_id: String,
|
|
pub from_node_id: String,
|
|
pub to_node_id: String,
|
|
pub edge_kind: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapSummary {
|
|
pub summary_id: String,
|
|
pub parent_node_id: String,
|
|
#[serde(default)]
|
|
pub node_ids: Vec<String>,
|
|
pub text: String,
|
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
|
pub style: BTreeMap<String, Value>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapAssociativeLine {
|
|
pub line_id: String,
|
|
pub from_node_id: String,
|
|
pub to_node_id: String,
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
pub text: Option<String>,
|
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
|
pub style: BTreeMap<String, Value>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapKernelCapabilities {
|
|
pub can_edit: bool,
|
|
pub can_edit_text: bool,
|
|
pub can_insert_child: bool,
|
|
pub can_insert_sibling_after: bool,
|
|
pub can_delete_node: bool,
|
|
pub can_move_node: bool,
|
|
pub can_patch_view: bool,
|
|
pub can_set_layout: bool,
|
|
pub can_set_theme: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapAdapterProjection {
|
|
pub schema: String,
|
|
pub runtime: String,
|
|
pub root: Value,
|
|
#[serde(default)]
|
|
pub layout: Value,
|
|
#[serde(default)]
|
|
pub theme: Value,
|
|
#[serde(default)]
|
|
pub theme_config: Value,
|
|
#[serde(default)]
|
|
pub view: Value,
|
|
#[serde(default)]
|
|
pub config: Value,
|
|
#[serde(default)]
|
|
pub compat_payload: Value,
|
|
pub kernel_revision: u64,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
pub enum MindmapKernelCommand {
|
|
UpdateText {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
#[serde(rename = "nodeId", alias = "node_id")]
|
|
node_id: String,
|
|
text: String,
|
|
},
|
|
InsertChild {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
#[serde(rename = "parentNodeId", alias = "parent_node_id", alias = "parentId")]
|
|
parent_node_id: String,
|
|
node: MindmapNodeInput,
|
|
},
|
|
InsertSiblingAfter {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
#[serde(rename = "targetNodeId", alias = "target_node_id")]
|
|
target_node_id: String,
|
|
node: MindmapNodeInput,
|
|
},
|
|
DeleteNode {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
#[serde(rename = "nodeId", alias = "node_id")]
|
|
node_id: String,
|
|
},
|
|
MoveNode {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
#[serde(rename = "nodeId", alias = "node_id")]
|
|
node_id: String,
|
|
#[serde(
|
|
rename = "newParentNodeId",
|
|
alias = "new_parent_node_id",
|
|
alias = "newParentId"
|
|
)]
|
|
new_parent_node_id: String,
|
|
#[serde(rename = "order", alias = "sortOrder", alias = "sort_order")]
|
|
order: Option<i64>,
|
|
},
|
|
PatchView {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
patch: Value,
|
|
},
|
|
SetLayout {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
layout: Value,
|
|
},
|
|
SetTheme {
|
|
#[serde(rename = "mindmapId", alias = "mindmap_id", alias = "mapId")]
|
|
mindmap_id: String,
|
|
theme: Value,
|
|
#[serde(default)]
|
|
#[serde(rename = "themeConfig", alias = "theme_config")]
|
|
theme_config: Value,
|
|
},
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
pub enum MindmapCommand {
|
|
CreateNode {
|
|
#[serde(rename = "mapId", alias = "map_id")]
|
|
map_id: String,
|
|
#[serde(rename = "parentId", alias = "parent_id")]
|
|
parent_id: String,
|
|
node: MindmapNodeInput,
|
|
},
|
|
RenameNode {
|
|
#[serde(rename = "mapId", alias = "map_id")]
|
|
map_id: String,
|
|
#[serde(rename = "nodeId", alias = "node_id")]
|
|
node_id: String,
|
|
title: String,
|
|
},
|
|
MoveNode {
|
|
#[serde(rename = "mapId", alias = "map_id")]
|
|
map_id: String,
|
|
#[serde(rename = "nodeId", alias = "node_id")]
|
|
node_id: String,
|
|
#[serde(rename = "newParentId", alias = "new_parent_id")]
|
|
new_parent_id: String,
|
|
#[serde(rename = "sortOrder", alias = "sort_order")]
|
|
sort_order: Option<i64>,
|
|
},
|
|
DeleteNode {
|
|
#[serde(rename = "mapId", alias = "map_id")]
|
|
map_id: String,
|
|
#[serde(rename = "nodeId", alias = "node_id")]
|
|
node_id: String,
|
|
},
|
|
SetLayout {
|
|
#[serde(rename = "mapId", alias = "map_id")]
|
|
map_id: String,
|
|
#[serde(rename = "layoutHints", alias = "layout_hints")]
|
|
layout_hints: Value,
|
|
},
|
|
AttachPageRef {
|
|
#[serde(rename = "mapId", alias = "map_id")]
|
|
map_id: String,
|
|
#[serde(rename = "nodeId", alias = "node_id")]
|
|
node_id: String,
|
|
#[serde(rename = "pageId", alias = "page_id")]
|
|
page_id: String,
|
|
},
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapNodeRef {
|
|
pub kind: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub asset_id: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub file_url: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub page: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub slide: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub title: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub snippet: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapNodeData {
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub uid: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub text: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub hyperlink: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub note: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub refs: Option<Vec<MindmapNodeRef>>,
|
|
#[serde(flatten, default)]
|
|
pub extra: BTreeMap<String, Value>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
pub struct MindmapTreeNode {
|
|
pub data: MindmapNodeData,
|
|
#[serde(default)]
|
|
pub children: Vec<MindmapTreeNode>,
|
|
#[serde(flatten, default)]
|
|
pub extra: BTreeMap<String, Value>,
|
|
}
|
|
|
|
/// 兼容 DTO:对应 simple-mind-map / KMind 风格树节点。
|
|
/// 长期事实源应使用 `MindmapKernelProjection` 与 kernel command。
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct MindmapNodeInput {
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub uid: Option<String>,
|
|
pub text: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub hyperlink: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub note: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub refs: Option<Vec<MindmapNodeRef>>,
|
|
}
|
|
|
|
/// 兼容 DTO:用于历史 AI 工具和旧 blob 操作。
|
|
/// 新的 leptos-mindmap 写面应优先使用 `MindmapKernelCommand`。
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
#[serde(tag = "op", rename_all = "camelCase")]
|
|
pub enum MindmapOp {
|
|
#[serde(alias = "add_child")]
|
|
AddChild {
|
|
#[serde(rename = "parentUid")]
|
|
#[serde(alias = "parent_uid")]
|
|
parent_uid: String,
|
|
node: MindmapNodeInput,
|
|
},
|
|
#[serde(alias = "add_sibling_after")]
|
|
AddSiblingAfter {
|
|
#[serde(rename = "targetUid")]
|
|
#[serde(alias = "target_uid")]
|
|
target_uid: String,
|
|
node: MindmapNodeInput,
|
|
},
|
|
#[serde(alias = "update_node", alias = "updateNode")]
|
|
UpdateText {
|
|
uid: String,
|
|
#[serde(alias = "value")]
|
|
text: String,
|
|
},
|
|
#[serde(alias = "set_link", alias = "set_hyperlink")]
|
|
SetHyperlink {
|
|
#[serde(alias = "id")]
|
|
uid: String,
|
|
#[serde(alias = "url")]
|
|
hyperlink: Option<String>,
|
|
},
|
|
#[serde(alias = "set_refs")]
|
|
SetRefs {
|
|
#[serde(alias = "id")]
|
|
uid: String,
|
|
refs: Vec<MindmapNodeRef>,
|
|
},
|
|
#[serde(alias = "append_note")]
|
|
AppendNote {
|
|
#[serde(alias = "id")]
|
|
uid: String,
|
|
#[serde(alias = "note")]
|
|
markdown: String,
|
|
},
|
|
#[serde(alias = "delete_node")]
|
|
DeleteNode {
|
|
#[serde(alias = "id")]
|
|
uid: String,
|
|
},
|
|
}
|