feat: land page aggregate and phase7 document ai mainline
- 收口 page aggregate 读取、本地状态与命令客户端\n- 接入 phase7 document ai sidecar 与前端编排入口\n- 更新 architecture 与 design 状态迁移
This commit is contained in:
@@ -5468,12 +5468,12 @@ fn execute_command(
|
||||
}),
|
||||
}))
|
||||
}
|
||||
"documents.title.update" | "tree.node.rename" => {
|
||||
"documents.title.update" | "tree.node.rename" | "page.head.updateTitle" => {
|
||||
let payload: DocumentTitleCommandPayload = parse_payload(command_wire.payload.clone())?;
|
||||
let command_name = if command_wire.name == "tree.node.rename" {
|
||||
"tree.node.rename"
|
||||
} else {
|
||||
"documents.title.update"
|
||||
let command_name = match command_wire.name.as_str() {
|
||||
"tree.node.rename" => "tree.node.rename",
|
||||
"page.head.updateTitle" => "page.head.updateTitle",
|
||||
_ => "documents.title.update",
|
||||
};
|
||||
let command = CommandEnvelope {
|
||||
name: command_name.into(),
|
||||
@@ -5508,12 +5508,12 @@ fn execute_command(
|
||||
}),
|
||||
}))
|
||||
}
|
||||
"documents.save" => {
|
||||
"documents.save" | "page.body.save" => {
|
||||
let payload: DocumentSaveCommandPayload = parse_payload(command_wire.payload.clone())?;
|
||||
let editor_document = normalize_save_editor_document(&payload)?;
|
||||
let canonical_content = legacy_content_from_editor_document(&editor_document);
|
||||
let command = CommandEnvelope {
|
||||
name: "documents.save".into(),
|
||||
name: command_wire.name.clone(),
|
||||
command_id: command_wire.command_id.clone(),
|
||||
idempotency_key: command_wire.idempotency_key.clone(),
|
||||
actor: to_actor_payload(&command_wire.actor),
|
||||
@@ -5525,7 +5525,8 @@ fn execute_command(
|
||||
revision: payload.revision,
|
||||
content_json: serde_json::to_string(&canonical_content).map_err(|error| {
|
||||
BridgeError::validation(format!(
|
||||
"documents.save content 序列化失败: {error}"
|
||||
"{} content 序列化失败: {error}",
|
||||
command_wire.name
|
||||
))
|
||||
})?,
|
||||
conflict_detection_key: payload.conflict_detection_key.clone(),
|
||||
@@ -6186,21 +6187,19 @@ fn normalize_save_editor_document(
|
||||
payload: &DocumentSaveCommandPayload,
|
||||
) -> Result<EditorBlockDocument, BridgeError> {
|
||||
if let Some(editor_document) = payload.editor_document.clone() {
|
||||
let mut parsed =
|
||||
serde_json::from_value::<EditorBlockDocument>(editor_document).map_err(|error| {
|
||||
BridgeError::validation(format!("documents.save editorDocument 非法: {error}"))
|
||||
})?;
|
||||
if parsed.document_id.trim().is_empty() {
|
||||
parsed.document_id = payload.document_id.clone();
|
||||
if let Ok(mut parsed) = serde_json::from_value::<EditorBlockDocument>(editor_document) {
|
||||
if parsed.document_id.trim().is_empty() {
|
||||
parsed.document_id = payload.document_id.clone();
|
||||
}
|
||||
if parsed.root_block_ids.is_empty() {
|
||||
parsed.root_block_ids = parsed
|
||||
.blocks
|
||||
.iter()
|
||||
.map(|block| block.block_id.clone())
|
||||
.collect();
|
||||
}
|
||||
return Ok(parsed);
|
||||
}
|
||||
if parsed.root_block_ids.is_empty() {
|
||||
parsed.root_block_ids = parsed
|
||||
.blocks
|
||||
.iter()
|
||||
.map(|block| block.block_id.clone())
|
||||
.collect();
|
||||
}
|
||||
return Ok(parsed);
|
||||
}
|
||||
if let Some(tiptap_document) = payload.tiptap_document.clone() {
|
||||
let parsed = serde_json::from_value::<TiptapNode>(tiptap_document).map_err(|error| {
|
||||
@@ -7259,6 +7258,261 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documents_save_command_plan_falls_back_from_invalid_editor_document_to_tiptap() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
context: demo_context(),
|
||||
command: RuntimeCommandEnvelopeWire {
|
||||
name: "documents.save".into(),
|
||||
command_id: "cmd_save_2".into(),
|
||||
idempotency_key: Some("idem_save_2".into()),
|
||||
actor: RuntimeActorWire {
|
||||
actor_type: "user".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("sess_1".into()),
|
||||
},
|
||||
source: RuntimeSourceWire {
|
||||
channel: "next-route".into(),
|
||||
client: "wolai-frontend".into(),
|
||||
},
|
||||
target: Some(RuntimeTargetWire {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("doc_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: json!({
|
||||
"documentId": "doc_1",
|
||||
"workspaceId": "ws_1",
|
||||
"revision": 6,
|
||||
"editorDocument": {
|
||||
"documentId": "doc_1",
|
||||
"rootBlockIds": ["legacy_block_1"],
|
||||
"blocks": [
|
||||
{
|
||||
"blockId": "legacy_block_1",
|
||||
"blockType": "paragraph",
|
||||
"contentNodes": [
|
||||
{
|
||||
"attrs": {}
|
||||
}
|
||||
],
|
||||
"childBlockIds": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiptapDocument": {
|
||||
"type": "doc",
|
||||
"content": [
|
||||
{
|
||||
"type": "paragraph",
|
||||
"attrs": {
|
||||
"blockId": "p_1"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "来自 tiptap 回退"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"id": "content_block_1",
|
||||
"type": "paragraph",
|
||||
"content": "来自 content 回退"
|
||||
}
|
||||
],
|
||||
"conflictDetectionKey": "doc_1:6"
|
||||
}),
|
||||
reason: Some("保存正文".into()),
|
||||
refs: vec!["task-save-fallback".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
},
|
||||
})
|
||||
.expect("documents.save plan should build");
|
||||
|
||||
let RuntimeExecutionPlan::Command(plan) = plan else {
|
||||
panic!("expected command plan");
|
||||
};
|
||||
|
||||
assert_eq!(plan.function_name, "documents:updateContent");
|
||||
assert_eq!(plan.args_json.pointer("/content/0/id"), Some(&json!("p_1")));
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/content"),
|
||||
Some(&json!("来自 tiptap 回退"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/rootBlockIds/0"),
|
||||
Some(&json!("p_1"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/blocks/0/blockId"),
|
||||
Some(&json!("p_1"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documents_save_command_plan_prefers_valid_editor_document_over_other_sources() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
context: demo_context(),
|
||||
command: RuntimeCommandEnvelopeWire {
|
||||
name: "documents.save".into(),
|
||||
command_id: "cmd_save_3".into(),
|
||||
idempotency_key: Some("idem_save_3".into()),
|
||||
actor: RuntimeActorWire {
|
||||
actor_type: "user".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("sess_1".into()),
|
||||
},
|
||||
source: RuntimeSourceWire {
|
||||
channel: "next-route".into(),
|
||||
client: "wolai-frontend".into(),
|
||||
},
|
||||
target: Some(RuntimeTargetWire {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("doc_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: json!({
|
||||
"documentId": "doc_1",
|
||||
"workspaceId": "ws_1",
|
||||
"revision": 7,
|
||||
"editorDocument": {
|
||||
"documentId": "doc_1",
|
||||
"rootBlockIds": ["editor_block_1"],
|
||||
"blocks": [
|
||||
{
|
||||
"blockId": "editor_block_1",
|
||||
"blockType": "paragraph",
|
||||
"contentNodes": [
|
||||
{
|
||||
"payload": {
|
||||
"type": "text",
|
||||
"text": "来自 editorDocument",
|
||||
"marks": []
|
||||
},
|
||||
"attrs": {}
|
||||
}
|
||||
],
|
||||
"childBlockIds": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiptapDocument": {
|
||||
"type": "doc",
|
||||
"content": [
|
||||
{
|
||||
"type": "paragraph",
|
||||
"attrs": {
|
||||
"blockId": "p_1"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "来自 tiptap"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"id": "content_block_1",
|
||||
"type": "paragraph",
|
||||
"content": "来自 content"
|
||||
}
|
||||
],
|
||||
"conflictDetectionKey": "doc_1:7"
|
||||
}),
|
||||
reason: Some("保存正文".into()),
|
||||
refs: vec!["task-save-prefer-editor".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
},
|
||||
})
|
||||
.expect("documents.save plan should build");
|
||||
|
||||
let RuntimeExecutionPlan::Command(plan) = plan else {
|
||||
panic!("expected command plan");
|
||||
};
|
||||
|
||||
assert_eq!(plan.function_name, "documents:updateContent");
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/content"),
|
||||
Some(&json!("来自 editorDocument"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/blocks/0/contentNodes/0/payload/text"),
|
||||
Some(&json!("来自 editorDocument"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/id"),
|
||||
Some(&json!("editor_block_1"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documents_save_command_plan_supports_legacy_content_only_payloads() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
context: demo_context(),
|
||||
command: RuntimeCommandEnvelopeWire {
|
||||
name: "page.body.save".into(),
|
||||
command_id: "cmd_save_4".into(),
|
||||
idempotency_key: Some("idem_save_4".into()),
|
||||
actor: RuntimeActorWire {
|
||||
actor_type: "user".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("sess_1".into()),
|
||||
},
|
||||
source: RuntimeSourceWire {
|
||||
channel: "next-route".into(),
|
||||
client: "wolai-frontend".into(),
|
||||
},
|
||||
target: Some(RuntimeTargetWire {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("doc_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: json!({
|
||||
"documentId": "doc_1",
|
||||
"workspaceId": "ws_1",
|
||||
"revision": 8,
|
||||
"content": [
|
||||
{
|
||||
"id": "legacy_content_1",
|
||||
"type": "paragraph",
|
||||
"content": "来自旧式 content-only 保存"
|
||||
}
|
||||
],
|
||||
"conflictDetectionKey": "doc_1:8"
|
||||
}),
|
||||
reason: Some("保存正文".into()),
|
||||
refs: vec!["task-save-content-only".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
},
|
||||
})
|
||||
.expect("page.body.save plan should build");
|
||||
|
||||
let RuntimeExecutionPlan::Command(plan) = plan else {
|
||||
panic!("expected command plan");
|
||||
};
|
||||
|
||||
assert_eq!(plan.function_name, "documents:updateContent");
|
||||
assert_eq!(plan.args_json.pointer("/content/0/id"), Some(&json!("legacy_content_1")));
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/content"),
|
||||
Some(&json!("来自旧式 content-only 保存"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/rootBlockIds/0"),
|
||||
Some(&json!("legacy_content_1"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocks_move_command_plan_maps_to_blocks_move() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
|
||||
@@ -11,6 +11,7 @@ pub struct AppConfig {
|
||||
pub service_name: String,
|
||||
pub service_version: String,
|
||||
pub bind_addr: String,
|
||||
pub enable_debug_shell_routes: bool,
|
||||
pub hermes_base_path: String,
|
||||
pub compat_next_base_path: String,
|
||||
pub convex_url: Option<String>,
|
||||
@@ -29,7 +30,11 @@ impl AppConfig {
|
||||
service_name: env::var("MNOTE_WEB_SERVICE_NAME").unwrap_or_else(|_| "mnote-web".into()),
|
||||
service_version: env::var("MNOTE_WEB_SERVICE_VERSION")
|
||||
.unwrap_or_else(|_| env!("CARGO_PKG_VERSION").into()),
|
||||
bind_addr: env::var("MNOTE_WEB_BIND").unwrap_or_else(|_| "127.0.0.1:3104".into()),
|
||||
bind_addr: env::var("MNOTE_WEB_BIND").unwrap_or_else(|_| "127.0.0.1:0".into()),
|
||||
enable_debug_shell_routes: env::var("MNOTE_WEB_ENABLE_DEBUG_SHELL_ROUTES")
|
||||
.ok()
|
||||
.map(|value| matches!(value.trim(), "1" | "true" | "TRUE" | "yes" | "YES"))
|
||||
.unwrap_or(false),
|
||||
hermes_base_path: env::var("MNOTE_WEB_HERMES_BASE_PATH")
|
||||
.unwrap_or_else(|_| "/api/hermes".into()),
|
||||
compat_next_base_path: env::var("MNOTE_WEB_COMPAT_NEXT_BASE_PATH")
|
||||
|
||||
@@ -162,6 +162,7 @@ mod tests {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
@@ -102,6 +102,7 @@ mod tests {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
@@ -510,6 +510,7 @@ mod tests {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
@@ -1772,6 +1772,7 @@ mod tests {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: true,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
@@ -195,6 +195,7 @@ mod tests {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
@@ -20,12 +20,10 @@ use axum::Router;
|
||||
pub fn build_router(state: AppState) -> Router {
|
||||
let hermes_base_path = state.config().hermes_base_path.clone();
|
||||
let compat_next_base_path = state.config().compat_next_base_path.clone();
|
||||
let enable_debug_shell_routes = state.config().enable_debug_shell_routes;
|
||||
|
||||
Router::new()
|
||||
let mut router = Router::new()
|
||||
.route("/health", get(health::health))
|
||||
.route("/tree", get(tree::tree_shell))
|
||||
.route("/document-debug", get(editor::document_editor_shell))
|
||||
.route("/document", get(editor::document_editor_shell))
|
||||
.route("/api/documents/meta", get(documents::meta))
|
||||
.route("/api/documents/content", get(documents::content))
|
||||
.route("/api/documents/save", post(documents::save))
|
||||
@@ -63,6 +61,14 @@ pub fn build_router(state: AppState) -> Router {
|
||||
Router::new()
|
||||
.route("/ai-agent/run", post(compat::next_ai_agent_run))
|
||||
.route("/sidebar", get(compat::next_sidebar)),
|
||||
)
|
||||
.with_state(state)
|
||||
);
|
||||
|
||||
if enable_debug_shell_routes {
|
||||
router = router
|
||||
.route("/tree", get(tree::tree_shell))
|
||||
.route("/document-debug", get(editor::document_editor_shell))
|
||||
.route("/document", get(editor::document_editor_shell));
|
||||
}
|
||||
|
||||
router.with_state(state)
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ mod tests {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
@@ -2213,6 +2213,7 @@ mod tests {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: true,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
@@ -445,7 +445,8 @@ mod tests {
|
||||
AppConfig {
|
||||
service_name: "mnote-web".into(),
|
||||
service_version: "0.1.0".into(),
|
||||
bind_addr: "127.0.0.1:3104".into(),
|
||||
bind_addr: "127.0.0.1:0".into(),
|
||||
enable_debug_shell_routes: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: Some("http://127.0.0.1:3210".into()),
|
||||
|
||||
@@ -197,6 +197,45 @@ mod tests {
|
||||
.contains("\"name\":\"documents.title.update\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_head_update_title_command_maps_to_documents_update_title() {
|
||||
let command = CommandEnvelope {
|
||||
name: "page.head.updateTitle".into(),
|
||||
command_id: "cmd_page_title_1".into(),
|
||||
idempotency_key: Some("idem_page_title".into()),
|
||||
actor: ActorPayload {
|
||||
actor_type: "human".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("session_1".into()),
|
||||
},
|
||||
source: SourcePayload {
|
||||
channel: "next-route".into(),
|
||||
client: "wolai-frontend".into(),
|
||||
},
|
||||
target: Some(TargetRef {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("page_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: UpdatePageTitle {
|
||||
page_id: "page_1".into(),
|
||||
title: "新标题".into(),
|
||||
},
|
||||
reason: None,
|
||||
refs: vec![],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
};
|
||||
|
||||
let request =
|
||||
build_write_request(&demo_context(), &command).expect("write request should build");
|
||||
assert_eq!(request.function_name, "documents:updateTitle");
|
||||
assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
|
||||
assert!(request
|
||||
.payload_json
|
||||
.contains("\"name\":\"page.head.updateTitle\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn document_save_command_maps_to_documents_update_content() {
|
||||
let command = CommandEnvelope {
|
||||
@@ -237,6 +276,46 @@ mod tests {
|
||||
assert!(request.payload_json.contains("\"name\":\"documents.save\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_body_save_command_maps_to_documents_update_content() {
|
||||
let command = CommandEnvelope {
|
||||
name: "page.body.save".into(),
|
||||
command_id: "cmd_page_save_1".into(),
|
||||
idempotency_key: Some("idem_page_save".into()),
|
||||
actor: ActorPayload {
|
||||
actor_type: "human".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("session_1".into()),
|
||||
},
|
||||
source: SourcePayload {
|
||||
channel: "next-route".into(),
|
||||
client: "wolai-frontend".into(),
|
||||
},
|
||||
target: Some(TargetRef {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("page_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: SavePageContent {
|
||||
page_id: "page_1".into(),
|
||||
workspace_id: Some("ws_1".into()),
|
||||
revision: Some(42),
|
||||
content_json: "{\"type\":\"doc\"}".into(),
|
||||
conflict_detection_key: Some("rev:42".into()),
|
||||
},
|
||||
reason: Some("保存正文".into()),
|
||||
refs: vec!["checklist:c3".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
};
|
||||
|
||||
let request =
|
||||
build_write_request(&demo_context(), &command).expect("write request should build");
|
||||
assert_eq!(request.function_name, "documents:updateContent");
|
||||
assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
|
||||
assert!(request.payload_json.contains("\"name\":\"page.body.save\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn document_embed_command_maps_to_documents_update_content() {
|
||||
let command = CommandEnvelope {
|
||||
@@ -608,6 +687,57 @@ mod tests {
|
||||
.contains("\"name\":\"documents.options.update\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_layout_update_options_command_maps_to_documents_update_options() {
|
||||
let command = CommandEnvelope {
|
||||
name: "page.layout.updateOptions".into(),
|
||||
command_id: "cmd_page_options_1".into(),
|
||||
idempotency_key: Some("idem_page_options".into()),
|
||||
actor: ActorPayload {
|
||||
actor_type: "human".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("session_1".into()),
|
||||
},
|
||||
source: SourcePayload {
|
||||
channel: "next-route".into(),
|
||||
client: "wolai-frontend".into(),
|
||||
},
|
||||
target: Some(TargetRef {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("page_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: UpdatePageOptions {
|
||||
page_id: "page_1".into(),
|
||||
wide_layout: None,
|
||||
small_text: None,
|
||||
show_heading_numbers: None,
|
||||
show_toc: Some(true),
|
||||
show_structure: None,
|
||||
protect_editing: None,
|
||||
show_word_count: None,
|
||||
collapse_backlinks: None,
|
||||
page_font: None,
|
||||
layout_density: Some("compact".into()),
|
||||
hide_child_pages: None,
|
||||
show_block_ref_count: None,
|
||||
embed_default_block_id: None,
|
||||
},
|
||||
reason: None,
|
||||
refs: vec![],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
};
|
||||
|
||||
let request =
|
||||
build_write_request(&demo_context(), &command).expect("write request should build");
|
||||
assert_eq!(request.function_name, "documents:updateOptions");
|
||||
assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
|
||||
assert!(request
|
||||
.payload_json
|
||||
.contains("\"name\":\"page.layout.updateOptions\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn media_asset_writeback_command_maps_to_replace_storage_from_upload() {
|
||||
let command = CommandEnvelope {
|
||||
|
||||
@@ -54,9 +54,12 @@ pub fn map_command_name_to_convex(command_name: &str) -> &'static str {
|
||||
"documents.embed" => "documents:updateContent",
|
||||
"blocks.patch" => "documents:updateContent",
|
||||
"documents.save" => "documents:updateContent",
|
||||
"page.body.save" => "documents:updateContent",
|
||||
"documents.title.update" => "documents:updateTitle",
|
||||
"page.head.updateTitle" => "documents:updateTitle",
|
||||
"documents.stats.update" => "documents:updateStats",
|
||||
"documents.options.update" => "documents:updateOptions",
|
||||
"page.layout.updateOptions" => "documents:updateOptions",
|
||||
"mindmaps.put" => "mindmaps:put",
|
||||
"mindmaps.delete" => "mindmaps:softDelete",
|
||||
"mindmaps.restore" => "mindmaps:restore",
|
||||
|
||||
+7
-7
@@ -1038,37 +1038,37 @@ function __wbg_get_imports() {
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1204, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1226, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2593b18d2d6f8a75);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1295, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1317, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h36e788bd1cd1f0f7);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 949, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 971, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h1ea2b89742286ce6);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000004: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1130, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1152, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h03deb55668e1377f);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1206, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1228, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h837fba73fce77300);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1143, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1165, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hd17f30facfdd737f);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000007: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1205, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1227, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hf726e22cfd1ee0a9);
|
||||
return ret;
|
||||
},
|
||||
|
||||
BIN
Binary file not shown.
Reference in New Issue
Block a user