refactor: split editor mount and sidebar page ai
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -154,6 +154,10 @@ pub fn build_router(state: AppState) -> Router {
|
||||
"/api/mnote-browser-runtime/sidebar-attachment-open-runtime.js",
|
||||
get(web_shell::sidebar_attachment_open_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/sidebar-page-ai-runtime.js",
|
||||
get(web_shell::sidebar_page_ai_runtime_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/mnote-browser-runtime/sidebar-tree-runtime.js",
|
||||
get(web_shell::sidebar_tree_runtime_asset),
|
||||
@@ -650,6 +654,7 @@ mod tests {
|
||||
"/api/mnote-browser-runtime/sidebar-filetree-command-runtime.js",
|
||||
"/api/mnote-browser-runtime/sidebar-filetree-upload-runtime.js",
|
||||
"/api/mnote-browser-runtime/sidebar-attachment-open-runtime.js",
|
||||
"/api/mnote-browser-runtime/sidebar-page-ai-runtime.js",
|
||||
"/api/mnote-browser-runtime/sidebar-tree-runtime.js",
|
||||
"/api/mnote-browser-runtime/tree-live-controller.js",
|
||||
"/api/mnote-browser-runtime/tree-shell-runtime.js",
|
||||
|
||||
@@ -728,6 +728,20 @@ pub async fn sidebar_tree_runtime_asset() -> Response {
|
||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
pub async fn sidebar_page_ai_runtime_asset() -> Response {
|
||||
const JS: &str = include_str!("../../browser/sidebar-page-ai-runtime.js");
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header(
|
||||
header::CONTENT_TYPE,
|
||||
"application/javascript; charset=utf-8",
|
||||
)
|
||||
.header(header::CACHE_CONTROL, "no-store")
|
||||
.header(HEADER_MNOTE_WEB_OWNER, "mnote-web")
|
||||
.body(Body::from(JS))
|
||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
pub async fn sidebar_shell_runtime_asset() -> Response {
|
||||
const JS: &str = include_str!("../../browser/sidebar-shell-runtime.js");
|
||||
Response::builder()
|
||||
|
||||
@@ -215,6 +215,8 @@ mod tests {
|
||||
include_str!("../../../browser/sidebar-workspace-runtime.js");
|
||||
const SIDEBAR_PAGE_TREE_RUNTIME_JS: &str =
|
||||
include_str!("../../../browser/sidebar-page-tree-runtime.js");
|
||||
const SIDEBAR_PAGE_AI_RUNTIME_JS: &str =
|
||||
include_str!("../../../browser/sidebar-page-ai-runtime.js");
|
||||
const FILETREE_CONTEXT_MENU_RUNTIME_JS: &str =
|
||||
include_str!("../../../browser/filetree-context-menu-runtime.js");
|
||||
const FILETREE_DND_RUNTIME_JS: &str = include_str!("../../../browser/filetree-dnd-runtime.js");
|
||||
@@ -352,7 +354,7 @@ mod tests {
|
||||
#[test]
|
||||
fn page_ai_fast_path_is_not_local_first_main_path() {
|
||||
assert!(
|
||||
SIDEBAR_TREE_RUNTIME_JS
|
||||
SIDEBAR_PAGE_AI_RUNTIME_JS
|
||||
.contains("if (currentSourceKind() === 'local_folder') return false;"),
|
||||
"local-first 页面 AI 不应继续加厚 page-ai fast-path;本地编辑应走受控文件工具"
|
||||
);
|
||||
@@ -361,15 +363,15 @@ mod tests {
|
||||
#[test]
|
||||
fn page_ai_local_source_passes_file_reference_fields_to_agent_run() {
|
||||
assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("function currentRootUri()"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("sourceKind: currentSourceKind()"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("rootUri: currentRootUri()"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("sourceKind: currentSourceKind()"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("rootUri: currentRootUri()"));
|
||||
assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
|
||||
.contains("if (sourceKind && !payload.sourceKind) payload.sourceKind = sourceKind"));
|
||||
assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
|
||||
.contains("if (rootUri && !payload.rootUri) payload.rootUri = rootUri"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pageContext: scopedContext.pageContext"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("pageContext: scopedContext.pageContext"));
|
||||
assert!(
|
||||
SIDEBAR_TREE_RUNTIME_JS
|
||||
SIDEBAR_PAGE_AI_RUNTIME_JS
|
||||
.contains("if (currentSourceKind() === 'local_folder') return false;"),
|
||||
"local source 不应进入 page-ai fast-path,后端会把 run 收敛为文件引用 scope"
|
||||
);
|
||||
@@ -377,70 +379,70 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn page_ai_uses_backend_acp_session_runtime_store() {
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function pageAiLoadBackendSessions"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("/api/hermes/client/sessions?"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("params.set('source', 'acp')"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function pageAiLoadBackendSessionDetail"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function pageAiSearchBackendSessions"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-page-ai-session-rename"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-page-ai-session-delete"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-page-ai-session-resume"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-page-ai-session-search"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pageAiUsageSummary"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("usage.updated"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("thought.delta"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("permission.requested"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-page-ai-permission-action=\"allow\""));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-page-ai-permission-action=\"deny\""));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function pageAiHidePermissionDialog"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("if (!message.resolved)"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("function pageAiLoadBackendSessions"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("/api/hermes/client/sessions?"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("params.set('source', 'acp')"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("function pageAiLoadBackendSessionDetail"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("function pageAiSearchBackendSessions"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("data-page-ai-session-rename"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("data-page-ai-session-delete"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("data-page-ai-session-resume"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("data-page-ai-session-search"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("pageAiUsageSummary"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("usage.updated"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("thought.delta"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("permission.requested"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("data-page-ai-permission-action=\"allow\""));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("data-page-ai-permission-action=\"deny\""));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("function pageAiHidePermissionDialog"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("if (!message.resolved)"));
|
||||
assert!(
|
||||
!SIDEBAR_TREE_RUNTIME_JS.contains("(item.resolved ? ' disabled' : '')"),
|
||||
!SIDEBAR_PAGE_AI_RUNTIME_JS.contains("(item.resolved ? ' disabled' : '')"),
|
||||
"已决 ACP permission 事件不能继续展示假审批按钮"
|
||||
);
|
||||
assert!(
|
||||
SIDEBAR_TREE_RUNTIME_JS.contains("session.info.updated"),
|
||||
SIDEBAR_PAGE_AI_RUNTIME_JS.contains("session.info.updated"),
|
||||
"ACP SessionInfoUpdate 事件应通过 session.info.updated SSE 转发到前端"
|
||||
);
|
||||
assert!(
|
||||
SIDEBAR_TREE_RUNTIME_JS.contains("plan.updated"),
|
||||
SIDEBAR_PAGE_AI_RUNTIME_JS.contains("plan.updated"),
|
||||
"ACP PlanUpdate 事件应通过 plan.updated SSE 转发到前端"
|
||||
);
|
||||
assert!(
|
||||
SIDEBAR_TREE_RUNTIME_JS.contains("data-page-ai-plan"),
|
||||
SIDEBAR_PAGE_AI_RUNTIME_JS.contains("data-page-ai-plan"),
|
||||
"plan 消息应渲染为 data-page-ai-plan 标记的轻量系统状态面板"
|
||||
);
|
||||
assert!(
|
||||
SIDEBAR_TREE_RUNTIME_JS.contains("执行计划 · "),
|
||||
SIDEBAR_PAGE_AI_RUNTIME_JS.contains("执行计划 · "),
|
||||
"plan 面板标题应显示执行计划和步数"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_ai_session_ui_labels_local_shared_and_cloud_storage() {
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function pageAiSessionStorageLabel"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("local_private"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("local_shared"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("convex_acp_runtime_store"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("本地私有"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("共享会话"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("云端会话"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("sessionStorage:"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("permissionLevel:"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("shareId:"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("function pageAiSessionStorageLabel"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("local_private"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("local_shared"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("convex_acp_runtime_store"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("本地私有"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("共享会话"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("云端会话"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("sessionStorage:"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("permissionLevel:"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("shareId:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_ai_acp_runtime_defaults_to_reasonix_and_keeps_hermes_switch() {
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("var PAGE_AI_SESSION_STORAGE_VERSION = 3"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("var PAGE_AI_SESSION_STORAGE_VERSION = 3"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pageAiAcpRuntime: 'reasonix'"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function pageAiNormalizeAcpRuntimes"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("return ['reasonix', 'hermes']"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pageAiNormalizeAcpRuntimes(acpRuntimes)"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("function pageAiNormalizeAcpRuntimes"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("return ['reasonix', 'hermes']"));
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("pageAiNormalizeAcpRuntimes(acpRuntimes)"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pageAiAcpRuntimeSelect.value || 'reasonix'"));
|
||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
||||
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS
|
||||
.contains("activeAcpRuntime: pageUiState.pageAiAcpRuntime || 'reasonix'"));
|
||||
assert!(!SIDEBAR_TREE_RUNTIME_JS.contains("默认 (Hermes HTTP)"));
|
||||
assert!(!SIDEBAR_PAGE_AI_RUNTIME_JS.contains("默认 (Hermes HTTP)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user