chore: 收口 review 执行清单与 runtime 验证
- 补齐 design/10-review 执行清单、验收标准与相关设计治理记录 - 迁移已完成的 tree、mindmap、runtime fallback、AI kernel 等设计和缺陷条目 - 推进 Rust Web runtime、tree/sidebar、page aggregate、mindmap 与 OnlyOffice 路由侧验证支撑 - 增加 task177-task180 smoke/audit 脚本及前端相关测试覆盖
This commit is contained in:
@@ -9,6 +9,9 @@ pub struct WorkspaceShellProjection {
|
||||
pub workspace_name: String,
|
||||
pub active_page_id: Option<String>,
|
||||
pub active_page_title: Option<String>,
|
||||
pub degraded: bool,
|
||||
pub degraded_reason: Option<String>,
|
||||
pub dev_fixture: bool,
|
||||
pub starred_items: Vec<WorkspaceShellItem>,
|
||||
pub my_page_items: Vec<WorkspaceShellItem>,
|
||||
pub bottom_entries: Vec<WorkspaceShellEntry>,
|
||||
@@ -88,6 +91,23 @@ pub fn build_workspace_shell_projection(
|
||||
starred_items.sort_by_key(|item| (item.depth, item.title.clone(), item.id.clone()));
|
||||
|
||||
let active_page_title = active_title_from_items(&my_page_items, active_page_id.as_deref());
|
||||
let degraded = dataset
|
||||
.get("degraded")
|
||||
.or_else(|| dataset.get("is_degraded"))
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
let degraded_reason = dataset
|
||||
.get("degraded_reason")
|
||||
.or_else(|| dataset.get("degradedReason"))
|
||||
.and_then(Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned);
|
||||
let dev_fixture = dataset
|
||||
.get("dev_fixture")
|
||||
.or_else(|| dataset.get("devFixture"))
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
|
||||
WorkspaceShellProjection {
|
||||
schema: "mnote.workspace_shell.v1".into(),
|
||||
@@ -95,6 +115,9 @@ pub fn build_workspace_shell_projection(
|
||||
workspace_name,
|
||||
active_page_id,
|
||||
active_page_title,
|
||||
degraded,
|
||||
degraded_reason,
|
||||
dev_fixture,
|
||||
starred_items,
|
||||
my_page_items,
|
||||
bottom_entries: vec![
|
||||
@@ -278,6 +301,8 @@ mod tests {
|
||||
assert_eq!(projection.workspace_name, "开发用户 的工作区");
|
||||
assert_eq!(projection.active_page_id.as_deref(), Some("page_home"));
|
||||
assert_eq!(projection.active_page_title.as_deref(), Some("个人"));
|
||||
assert!(!projection.degraded);
|
||||
assert!(!projection.dev_fixture);
|
||||
assert_eq!(projection.starred_items.len(), 1);
|
||||
assert_eq!(projection.starred_items[0].title, "个人");
|
||||
assert_eq!(projection.my_page_items.len(), 2);
|
||||
@@ -368,6 +393,42 @@ mod tests {
|
||||
|
||||
assert!(html.contains("data-testid=\"wolai-sidebar-empty-state\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workspace_shell_sidebar_html_marks_degraded_and_dev_fixture_states() {
|
||||
let degraded_dataset = json!({
|
||||
"workspaces": [{ "id": "ws_demo", "name": "开发用户 的工作区" }],
|
||||
"documents": [],
|
||||
"degraded": true,
|
||||
"degraded_reason": "projection_unavailable"
|
||||
});
|
||||
let degraded_projection = build_workspace_shell_projection(
|
||||
°raded_dataset,
|
||||
"ws_demo",
|
||||
None,
|
||||
"开发用户 的工作区",
|
||||
);
|
||||
let degraded_html = render_workspace_shell_sidebar_html(°raded_projection, None, None);
|
||||
|
||||
assert!(degraded_projection.degraded);
|
||||
assert!(degraded_html.contains("data-mnote-workspace-shell-degraded=\"true\""));
|
||||
assert!(degraded_html.contains(
|
||||
"data-mnote-workspace-shell-degraded-reason=\"projection_unavailable\""
|
||||
));
|
||||
|
||||
let dev_dataset = json!({
|
||||
"workspaces": [{ "id": "ws_demo", "name": "开发用户 的工作区" }],
|
||||
"documents": [],
|
||||
"dev_fixture": true
|
||||
});
|
||||
let dev_projection =
|
||||
build_workspace_shell_projection(&dev_dataset, "ws_demo", None, "开发用户 的工作区");
|
||||
let dev_html = render_workspace_shell_sidebar_html(&dev_projection, None, None);
|
||||
|
||||
assert!(dev_projection.dev_fixture);
|
||||
assert!(dev_html.contains("data-mnote-dev-fixture=\"true\""));
|
||||
assert!(dev_html.contains("data-mnote-dev-fixture-kind=\"workspace-shell\""));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_workspace_shell_sidebar_html(
|
||||
@@ -434,9 +495,25 @@ pub fn render_workspace_shell_sidebar_html(
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("");
|
||||
let status_markers = format!(
|
||||
r#"{degraded_marker}{dev_fixture_marker}"#,
|
||||
degraded_marker = if projection.degraded {
|
||||
format!(
|
||||
r#"<span hidden data-mnote-workspace-shell-degraded="true" data-mnote-workspace-shell-degraded-reason="{}"></span>"#,
|
||||
escape_html(projection.degraded_reason.as_deref().unwrap_or("projection_unavailable")),
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
dev_fixture_marker = if projection.dev_fixture {
|
||||
r#"<span hidden data-mnote-dev-fixture="true" data-mnote-dev-fixture-kind="workspace-shell"></span>"#.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
);
|
||||
|
||||
format!(
|
||||
r#"<section class="wolai-sidebar-section wolai-starred-section" aria-label="星标置顶"><div class="wolai-section-title">{}星标置顶<span class="wolai-section-caret">⌄</span></div>{starred_rows}</section><section class="wolai-sidebar-section wolai-my-pages-section" aria-label="页面树" data-testid="wolai-sidebar-page-tree-shell"><div class="wolai-sidebar-tabs" data-testid="wolai-sidebar-tree-tabs" role="tablist" aria-label="页面树和文件树"><button type="button" class="wolai-sidebar-tab wolai-sidebar-tab-active" data-mnote-sidebar-tree-tab="page" aria-selected="true" aria-controls="wolai-sidebar-page-tree-panel">我的页面</button><button type="button" class="wolai-sidebar-tab wolai-sidebar-tab-muted" data-mnote-sidebar-tree-tab="filetree" aria-selected="false" aria-controls="wolai-sidebar-file-tree-panel">{}Explorer</button><span class="wolai-section-caret">⌄</span><button type="button" class="wolai-section-add" data-testid="wolai-sidebar-create-page" data-mnote-action="create-page" data-workspace-id="{}" title="新建页面" aria-label="新建页面">+</button></div><div class="wolai-sidebar-tab-panels"><div id="wolai-sidebar-page-tree-panel" class="wolai-sidebar-tab-panel" data-mnote-sidebar-tree-panel="page">{my_pages}</div><div id="wolai-sidebar-file-tree-panel" class="wolai-sidebar-tab-panel" data-mnote-sidebar-tree-panel="filetree" hidden>{file_tree_content}</div></div></section><div class="wolai-sidebar-footer">{bottom_entries}</div>"#,
|
||||
r#"{status_markers}<section class="wolai-sidebar-section wolai-starred-section" aria-label="星标置顶"><div class="wolai-section-title">{}星标置顶<span class="wolai-section-caret">⌄</span></div>{starred_rows}</section><section class="wolai-sidebar-section wolai-my-pages-section" aria-label="页面树" data-testid="wolai-sidebar-page-tree-shell"><div class="wolai-sidebar-tabs" data-testid="wolai-sidebar-tree-tabs" role="tablist" aria-label="页面树和文件树"><button type="button" class="wolai-sidebar-tab wolai-sidebar-tab-active" data-mnote-sidebar-tree-tab="page" aria-selected="true" aria-controls="wolai-sidebar-page-tree-panel">我的页面</button><button type="button" class="wolai-sidebar-tab wolai-sidebar-tab-muted" data-mnote-sidebar-tree-tab="filetree" aria-selected="false" aria-controls="wolai-sidebar-file-tree-panel">{}Explorer</button><span class="wolai-section-caret">⌄</span><button type="button" class="wolai-section-add" data-testid="wolai-sidebar-create-page" data-mnote-action="create-page" data-workspace-id="{}" title="新建页面" aria-label="新建页面">+</button></div><div class="wolai-sidebar-tab-panels"><div id="wolai-sidebar-page-tree-panel" class="wolai-sidebar-tab-panel" data-mnote-sidebar-tree-panel="page">{my_pages}</div><div id="wolai-sidebar-file-tree-panel" class="wolai-sidebar-tab-panel" data-mnote-sidebar-tree-panel="filetree" hidden>{file_tree_content}</div></div></section><div class="wolai-sidebar-footer">{bottom_entries}</div>"#,
|
||||
render_symbol("star", "wolai-section-icon"),
|
||||
render_symbol("folder_open", "wolai-folder-icon"),
|
||||
escape_html(&projection.workspace_id),
|
||||
|
||||
Reference in New Issue
Block a user