fix local markdown attachment regressions
This commit is contained in:
@@ -6,42 +6,42 @@ use crate::routes::command_support::{
|
||||
execute_runtime_command_via_legacy_cloud_with_artifacts, read_optional_non_empty,
|
||||
};
|
||||
use crate::routes::local_folder_source::{
|
||||
LocalAccessMode, ensure_local_workspace_access_with_state,
|
||||
ensure_local_workspace_read_access_with_state, execute_local_tree_command_with_sort,
|
||||
load_local_folder_file_tree_snapshot, load_local_folder_page_tree_snapshot,
|
||||
local_folder_watch_revision, local_workspace_id_from_root_uri,
|
||||
ensure_local_workspace_access_with_state, ensure_local_workspace_read_access_with_state,
|
||||
execute_local_tree_command_with_sort, load_local_folder_file_tree_snapshot,
|
||||
load_local_folder_page_tree_snapshot, local_folder_watch_revision,
|
||||
local_workspace_id_from_root_uri, LocalAccessMode,
|
||||
};
|
||||
use crate::routes::query_support::{
|
||||
fetch_documents_meta_via_legacy_cloud, resolve_effective_workspace_id,
|
||||
};
|
||||
use crate::routes::snapshot_support::{ProjectionSnapshotSpec, load_projection_snapshot};
|
||||
use crate::routes::snapshot_support::{load_projection_snapshot, ProjectionSnapshotSpec};
|
||||
use crate::transport::convex::execute_retired_mutation_by_name;
|
||||
use crate::tree_shell::filetree_renderer::{
|
||||
FileTreeInitialRenderInput, FileTreeRenderRow, render_initial_filetree_html,
|
||||
render_initial_filetree_html, FileTreeInitialRenderInput, FileTreeRenderRow,
|
||||
};
|
||||
use crate::tree_shell::filetree_selection::FileTreeSelectionState;
|
||||
use crate::tree_shell::page_renderer::{
|
||||
PageTreeInitialRenderInput, PageTreeRenderRow, render_initial_page_tree_html,
|
||||
render_initial_page_tree_html, PageTreeInitialRenderInput, PageTreeRenderRow,
|
||||
};
|
||||
use crate::tree_shell::picker_renderer::{
|
||||
PickerInitialRenderInput, PickerRenderRow, render_initial_picker_html,
|
||||
render_initial_picker_html, PickerInitialRenderInput, PickerRenderRow,
|
||||
};
|
||||
use crate::tree_shell::renderer_input::{
|
||||
FileTreeRendererInput, PageTreeRendererInput, PickerRendererInput, TreeShellCommandDispatcher,
|
||||
TreeShellRendererInput,
|
||||
};
|
||||
use crate::tree_shell::runtime_api::{
|
||||
TreeShellRuntimeRequest, TreeShellRuntimeResult,
|
||||
reduce_tree_shell_runtime as reduce_tree_shell_runtime_request,
|
||||
reduce_tree_shell_runtime as reduce_tree_shell_runtime_request, TreeShellRuntimeRequest,
|
||||
TreeShellRuntimeResult,
|
||||
};
|
||||
use axum::Json;
|
||||
use axum::extract::{Extension, Query, State};
|
||||
use axum::http::{HeaderValue, StatusCode, header};
|
||||
use axum::http::{header, HeaderValue, StatusCode};
|
||||
use axum::response::{Html, IntoResponse, Response};
|
||||
use axum::Json;
|
||||
use bridge_runtime::RuntimeCommandEnvelopeWire;
|
||||
use core_protocol::KernelProjectionKind;
|
||||
use serde::Deserialize;
|
||||
use serde_json::{Value, json};
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
@@ -850,6 +850,18 @@ fn build_tree_shell_html(
|
||||
exclude_ids: &[String],
|
||||
dataset: &Value,
|
||||
) -> String {
|
||||
let source_kind = projection
|
||||
.get("sourceKind")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("convex_workspace");
|
||||
let root_uri = projection
|
||||
.get("rootUri")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("");
|
||||
let watch_revision = projection
|
||||
.get("watchRevision")
|
||||
.cloned()
|
||||
.unwrap_or(Value::Null);
|
||||
let renderer_input = build_tree_shell_renderer_input(
|
||||
projection,
|
||||
mode,
|
||||
@@ -869,15 +881,9 @@ fn build_tree_shell_html(
|
||||
"channel": channel,
|
||||
"host": host,
|
||||
"mode": mode,
|
||||
"sourceKind": projection
|
||||
.get("sourceKind")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("convex_workspace"),
|
||||
"rootUri": projection
|
||||
.get("rootUri")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or(""),
|
||||
"localWatchRevision": projection.get("watchRevision").cloned().unwrap_or(Value::Null),
|
||||
"sourceKind": source_kind,
|
||||
"rootUri": root_uri,
|
||||
"localWatchRevision": watch_revision.clone(),
|
||||
"allowRootPick": allow_root_pick,
|
||||
"excludeIds": exclude_ids,
|
||||
"rendererInput": renderer_input,
|
||||
@@ -892,6 +898,22 @@ fn build_tree_shell_html(
|
||||
});
|
||||
let app_state_json = serde_json::to_string(&app_state).unwrap_or_else(|_| "{}".into());
|
||||
let projection_json = serde_json::to_string_pretty(projection).unwrap_or_else(|_| "{}".into());
|
||||
let tree_live_bootstrap = serde_json::json!({
|
||||
"schema": "mnote.tree_live_bootstrap.v1",
|
||||
"disabled": false,
|
||||
"transport": if source_kind == "local_folder" { "local-folder-events" } else { "tree-live-ws" },
|
||||
"endpoint": "/api/tree/events",
|
||||
"wsEndpoint": "/api/realtime/ws",
|
||||
"workspaceId": workspace_id,
|
||||
"rootIds": root_node_id
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(|value| vec![value])
|
||||
.unwrap_or_default(),
|
||||
"initialRevision": watch_revision,
|
||||
});
|
||||
let tree_live_bootstrap_json =
|
||||
serde_json::to_string(&tree_live_bootstrap).unwrap_or_else(|_| "{}".into());
|
||||
let initial_tree_html = match mode {
|
||||
"page" => render_initial_page_tree_html(&PageTreeInitialRenderInput {
|
||||
rows: collect_page_tree_render_rows(projection),
|
||||
@@ -1589,7 +1611,7 @@ fn build_tree_shell_html(
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body data-mnote-root-uri="__ROOT_URI__">
|
||||
<main>
|
||||
<section class="tree-card">
|
||||
<div class="tree-card-header">
|
||||
@@ -1606,7 +1628,9 @@ fn build_tree_shell_html(
|
||||
</main>
|
||||
|
||||
<script id="tree-shell-state" type="application/json">__APP_STATE__</script>
|
||||
<script type="module" src="/api/mnote-browser-runtime/tree-shell-runtime.js"></script>
|
||||
<script id="__MNOTE_TREE_LIVE_BOOTSTRAP__" type="application/json">__TREE_LIVE_BOOTSTRAP__</script>
|
||||
<script type="module" src="__TREE_SHELL_RUNTIME_SRC__"></script>
|
||||
<script type="module" src="__TREE_LIVE_CONTROLLER_SRC__"></script>
|
||||
</body>
|
||||
</html>
|
||||
"##;
|
||||
@@ -1615,9 +1639,22 @@ fn build_tree_shell_html(
|
||||
.replace("__WORKSPACE_ID__", &escape_html(workspace_id))
|
||||
.replace("__ROOT_LABEL__", &escape_html(root_label))
|
||||
.replace("__ACTIVE_LABEL__", &escape_html(active_label))
|
||||
.replace("__ROOT_URI__", &escape_html(root_uri))
|
||||
.replace("__PROJECTION_JSON__", &escape_html(&projection_json))
|
||||
.replace("__INITIAL_TREE_HTML__", &initial_tree_html)
|
||||
.replace("__APP_STATE__", &escape_inline_json(&app_state_json))
|
||||
.replace(
|
||||
"__TREE_SHELL_RUNTIME_SRC__",
|
||||
&crate::routes::web_shell::mnote_browser_runtime_src("tree-shell-runtime.js"),
|
||||
)
|
||||
.replace(
|
||||
"__TREE_LIVE_CONTROLLER_SRC__",
|
||||
&crate::routes::web_shell::mnote_browser_runtime_src("tree-live-controller.js"),
|
||||
)
|
||||
.replace(
|
||||
"__TREE_LIVE_BOOTSTRAP__",
|
||||
&escape_inline_json(&tree_live_bootstrap_json),
|
||||
)
|
||||
}
|
||||
|
||||
fn json_response(context: &RequestContext, result: Value) -> (StatusCode, Json<Value>) {
|
||||
@@ -2584,10 +2621,10 @@ mod tests {
|
||||
include_str!("../../browser/tree-shell-filetree-dnd-runtime.js");
|
||||
|
||||
use super::{
|
||||
TREE_DOCUMENT_COMPAT_ALIAS_CATALOG, TreeCommandEnvelopeContext, TreeCommandRequest,
|
||||
collect_filetree_render_rows, create_command_wire,
|
||||
collect_filetree_render_rows, create_command_wire, TreeCommandEnvelopeContext,
|
||||
TreeCommandRequest, TREE_DOCUMENT_COMPAT_ALIAS_CATALOG,
|
||||
};
|
||||
use crate::app::{AppConfig, AppState, build_app};
|
||||
use crate::app::{build_app, AppConfig, AppState};
|
||||
use crate::context::RequestContext;
|
||||
use crate::routes::command_support::build_runtime_command_plan;
|
||||
use axum::body::Body;
|
||||
@@ -2752,20 +2789,14 @@ mod tests {
|
||||
assert!(html.contains("data-rust-action=\"toggle\""));
|
||||
assert!(html.contains("data-testid=\"tree-node-toggle\""));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("hydrateInitialPageTree"));
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS
|
||||
.contains("const usedRustInitialPageRenderer = hydrateInitialPageTree();")
|
||||
);
|
||||
assert!(TREE_SHELL_RUNTIME_JS
|
||||
.contains("const usedRustInitialPageRenderer = hydrateInitialPageTree();"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("applyCreatedDocumentLocally"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("applyRemovedDocumentLocally"));
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS
|
||||
.contains("sourceKind === \"convex_workspace\" && applyCreatedDocumentLocally")
|
||||
);
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS
|
||||
.contains("if (!deletableItems.every((item) => !fileTreeRowById.has(item.rowId)))")
|
||||
);
|
||||
assert!(TREE_SHELL_RUNTIME_JS
|
||||
.contains("sourceKind === \"convex_workspace\" && applyCreatedDocumentLocally"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS
|
||||
.contains("if (!deletableItems.every((item) => !fileTreeRowById.has(item.rowId)))"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("application/x-mnote-page-tree-node"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("页面已拖放到"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("setAttribute(\"role\", \"treeitem\")"));
|
||||
@@ -2790,11 +2821,8 @@ mod tests {
|
||||
.expect("body");
|
||||
let html = String::from_utf8(body.to_vec()).expect("utf8");
|
||||
assert!(html.contains("id=\"tree-shell-state\""));
|
||||
assert!(
|
||||
html.contains(
|
||||
"type=\"module\" src=\"/api/mnote-browser-runtime/tree-shell-runtime.js\""
|
||||
)
|
||||
);
|
||||
assert!(html
|
||||
.contains("type=\"module\" src=\"/api/mnote-browser-runtime/tree-shell-runtime.js\""));
|
||||
assert!(
|
||||
!html.contains("const stateElement = document.getElementById(\"tree-shell-state\")"),
|
||||
"debug /tree runtime should live in browser/tree-shell-runtime.js, not inline Rust HTML"
|
||||
@@ -2829,23 +2857,17 @@ mod tests {
|
||||
assert!(html.contains("\"contractName\":\"rust_picker_state_reducer_v1\""));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("applyPickerStateAction"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("postPickerPickResultToHost"));
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS
|
||||
.contains("applyPickerFocusByItemKey(\"__root__\", { focusDom: true })")
|
||||
);
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS
|
||||
.contains("applyPickerFocusByItemKey(item.nodeId, { focusDom: true })")
|
||||
);
|
||||
assert!(TREE_SHELL_RUNTIME_JS
|
||||
.contains("applyPickerFocusByItemKey(\"__root__\", { focusDom: true })"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS
|
||||
.contains("applyPickerFocusByItemKey(item.nodeId, { focusDom: true })"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("const shouldFocusDom = options.focusDom === true"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("if (shouldFocusDom) focusPickerRowElement"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("patchPickerActiveDom"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("hydrateInitialPickerTree"));
|
||||
assert!(html.contains("tabindex=\""));
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS
|
||||
.contains("const usedRustInitialRenderer = hydrateInitialRenderer();")
|
||||
);
|
||||
assert!(TREE_SHELL_RUNTIME_JS
|
||||
.contains("const usedRustInitialRenderer = hydrateInitialRenderer();"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("__MNOTE_TREE_SHELL_OVERRIDE__"));
|
||||
}
|
||||
|
||||
@@ -2885,18 +2907,12 @@ mod tests {
|
||||
assert!(
|
||||
TREE_SHELL_FILETREE_RUNTIME_JS.contains("function getFileTreeRowOwnerDocumentId(item)")
|
||||
);
|
||||
assert!(
|
||||
TREE_SHELL_FILETREE_MENU_RUNTIME_JS
|
||||
.contains("function buildFileTreeMenuTarget(context")
|
||||
);
|
||||
assert!(
|
||||
TREE_SHELL_FILETREE_DND_RUNTIME_JS
|
||||
.contains("function createTreeShellFileTreeDndRuntime(context)")
|
||||
);
|
||||
assert!(
|
||||
TREE_SHELL_RENDER_RUNTIME_JS
|
||||
.contains("row.dataset.ownerDocumentId = ownerDocumentId || \"\";")
|
||||
);
|
||||
assert!(TREE_SHELL_FILETREE_MENU_RUNTIME_JS
|
||||
.contains("function buildFileTreeMenuTarget(context"));
|
||||
assert!(TREE_SHELL_FILETREE_DND_RUNTIME_JS
|
||||
.contains("function createTreeShellFileTreeDndRuntime(context)"));
|
||||
assert!(TREE_SHELL_RENDER_RUNTIME_JS
|
||||
.contains("row.dataset.ownerDocumentId = ownerDocumentId || \"\";"));
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS.contains("if (rowId && getFileTreeRowDocumentId(renameItem))")
|
||||
);
|
||||
@@ -2904,10 +2920,8 @@ mod tests {
|
||||
assert!(TREE_SHELL_RENDER_RUNTIME_JS.contains("documentId: ownerDocumentId || null"));
|
||||
assert!(TREE_SHELL_RENDER_RUNTIME_JS.contains("dragover"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("hydrateInitialFileTree"));
|
||||
assert!(
|
||||
TREE_SHELL_RUNTIME_JS
|
||||
.contains("const usedRustInitialRenderer = hydrateInitialRenderer();")
|
||||
);
|
||||
assert!(TREE_SHELL_RUNTIME_JS
|
||||
.contains("const usedRustInitialRenderer = hydrateInitialRenderer();"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -3065,8 +3079,16 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("/api/tree/local-folder-watch"));
|
||||
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("body");
|
||||
let html = String::from_utf8(body.to_vec()).expect("utf8");
|
||||
assert!(html.contains("__MNOTE_TREE_LIVE_BOOTSTRAP__"));
|
||||
assert!(html.contains("/api/mnote-browser-runtime/tree-live-controller.js"));
|
||||
assert!(html.contains("data-mnote-root-uri="));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("tree:local-folder-watch-batch"));
|
||||
assert!(TREE_SHELL_RUNTIME_JS.contains("refreshLocalFolderSnapshot"));
|
||||
assert!(!TREE_SHELL_RUNTIME_JS.contains("/api/tree/local-folder-watch"));
|
||||
assert!(!TREE_SHELL_RUNTIME_JS.contains("window.location.reload"));
|
||||
}
|
||||
|
||||
@@ -3120,8 +3142,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn tree_command_local_folder_create_rename_copy_trash_restore_and_purge_use_same_endpoint()
|
||||
{
|
||||
async fn tree_command_local_folder_create_rename_copy_trash_restore_and_purge_use_same_endpoint(
|
||||
) {
|
||||
let root =
|
||||
std::env::temp_dir().join(format!("mnote-local-tree-command-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
@@ -3236,12 +3258,11 @@ mod tests {
|
||||
String::from_utf8_lossy(&move_body)
|
||||
);
|
||||
assert!(!root.join("重命名页面").exists());
|
||||
assert!(
|
||||
root.join("docs")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists()
|
||||
);
|
||||
assert!(root
|
||||
.join("docs")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists());
|
||||
let move_payload: Value = serde_json::from_slice(&move_body).expect("move json");
|
||||
let moved_document_id = move_payload["result"]["documentId"]
|
||||
.as_str()
|
||||
@@ -3281,12 +3302,11 @@ mod tests {
|
||||
.as_str()
|
||||
.expect("copied document id")
|
||||
.to_string();
|
||||
assert!(
|
||||
root.join("docs")
|
||||
.join("重命名页面 2")
|
||||
.join("重命名页面 2.md")
|
||||
.exists()
|
||||
);
|
||||
assert!(root
|
||||
.join("docs")
|
||||
.join("重命名页面 2")
|
||||
.join("重命名页面 2.md")
|
||||
.exists());
|
||||
|
||||
let folder_response = app()
|
||||
.oneshot(
|
||||
@@ -3319,13 +3339,12 @@ mod tests {
|
||||
.expect("response");
|
||||
assert_eq!(delete_response.status(), StatusCode::OK);
|
||||
assert!(!root.join("docs").join("重命名页面").exists());
|
||||
assert!(
|
||||
root.join(".mnote")
|
||||
.join("trash")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists()
|
||||
);
|
||||
assert!(root
|
||||
.join(".mnote")
|
||||
.join("trash")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists());
|
||||
assert!(root.join(".mnote").join("trash-index.json").exists());
|
||||
assert!(!root.join(".mnote").join("page-ids.json").exists());
|
||||
|
||||
@@ -3352,12 +3371,11 @@ mod tests {
|
||||
"{}",
|
||||
String::from_utf8_lossy(&restore_body)
|
||||
);
|
||||
assert!(
|
||||
root.join("docs")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists()
|
||||
);
|
||||
assert!(root
|
||||
.join("docs")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists());
|
||||
let restore_payload: Value = serde_json::from_slice(&restore_body).expect("restore json");
|
||||
assert_eq!(
|
||||
restore_payload["result"]["documentId"].as_str(),
|
||||
@@ -3573,12 +3591,10 @@ mod tests {
|
||||
assert_eq!(status, StatusCode::BAD_REQUEST);
|
||||
assert_eq!(payload["ok"], false);
|
||||
assert_eq!(payload["code"], "local_folder_root_escape");
|
||||
assert!(
|
||||
payload["message"]
|
||||
.as_str()
|
||||
.unwrap_or_default()
|
||||
.contains("root")
|
||||
);
|
||||
assert!(payload["message"]
|
||||
.as_str()
|
||||
.unwrap_or_default()
|
||||
.contains("root"));
|
||||
assert!(payload["requestId"].as_str().unwrap_or_default().len() > 0);
|
||||
assert_eq!(
|
||||
headers
|
||||
@@ -3747,10 +3763,8 @@ mod tests {
|
||||
assert!(filetree_html.contains(
|
||||
"\"wasmModuleUrl\":\"/api/tree-shell-runtime/mnote-tree-shell-runtime_bg.wasm\""
|
||||
));
|
||||
assert!(
|
||||
filetree_html
|
||||
.contains("\"jsGlueUrl\":\"/api/tree-shell-runtime/mnote-tree-shell-runtime.js\"")
|
||||
);
|
||||
assert!(filetree_html
|
||||
.contains("\"jsGlueUrl\":\"/api/tree-shell-runtime/mnote-tree-shell-runtime.js\""));
|
||||
assert!(filetree_html.contains(
|
||||
"\"outputChannels\":[\"commandDispatchEvent\",\"domPatch\",\"intentEvent\"]"
|
||||
));
|
||||
@@ -3778,10 +3792,8 @@ mod tests {
|
||||
assert!(picker_html.contains(
|
||||
"\"wasmModuleUrl\":\"/api/tree-shell-runtime/mnote-tree-shell-runtime_bg.wasm\""
|
||||
));
|
||||
assert!(
|
||||
picker_html
|
||||
.contains("\"jsGlueUrl\":\"/api/tree-shell-runtime/mnote-tree-shell-runtime.js\"")
|
||||
);
|
||||
assert!(picker_html
|
||||
.contains("\"jsGlueUrl\":\"/api/tree-shell-runtime/mnote-tree-shell-runtime.js\""));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -4197,13 +4209,11 @@ mod tests {
|
||||
Some("convex://workspace/ws_demo")
|
||||
);
|
||||
assert_eq!(create_wire.source.workspace_id.as_deref(), Some("ws_demo"));
|
||||
assert!(
|
||||
create_wire
|
||||
.source
|
||||
.capabilities
|
||||
.iter()
|
||||
.any(|capability| capability == "execute-command")
|
||||
);
|
||||
assert!(create_wire
|
||||
.source
|
||||
.capabilities
|
||||
.iter()
|
||||
.any(|capability| capability == "execute-command"));
|
||||
|
||||
let rename_wire = create_command_wire(
|
||||
&context,
|
||||
@@ -4395,31 +4405,21 @@ mod tests {
|
||||
#[test]
|
||||
fn tree_documents_compat_alias_catalog_marks_cloud_retirement_boundary() {
|
||||
let aliases = TREE_DOCUMENT_COMPAT_ALIAS_CATALOG;
|
||||
assert!(
|
||||
aliases
|
||||
.iter()
|
||||
.all(|entry| entry.compat_command.starts_with("documents."))
|
||||
);
|
||||
assert!(
|
||||
aliases
|
||||
.iter()
|
||||
.all(|entry| entry.preferred_command.starts_with("tree."))
|
||||
);
|
||||
assert!(
|
||||
aliases
|
||||
.iter()
|
||||
.all(|entry| entry.source_kind == "convex_workspace")
|
||||
);
|
||||
assert!(
|
||||
aliases
|
||||
.iter()
|
||||
.all(|entry| entry.retained_for.contains("legacy cloud"))
|
||||
);
|
||||
assert!(
|
||||
aliases
|
||||
.iter()
|
||||
.all(|entry| entry.retirement_condition.contains("emit tree."))
|
||||
);
|
||||
assert!(aliases
|
||||
.iter()
|
||||
.all(|entry| entry.compat_command.starts_with("documents.")));
|
||||
assert!(aliases
|
||||
.iter()
|
||||
.all(|entry| entry.preferred_command.starts_with("tree.")));
|
||||
assert!(aliases
|
||||
.iter()
|
||||
.all(|entry| entry.source_kind == "convex_workspace"));
|
||||
assert!(aliases
|
||||
.iter()
|
||||
.all(|entry| entry.retained_for.contains("legacy cloud")));
|
||||
assert!(aliases
|
||||
.iter()
|
||||
.all(|entry| entry.retirement_condition.contains("emit tree.")));
|
||||
assert!(aliases.iter().any(|entry| {
|
||||
entry.compat_command == "documents.delete"
|
||||
&& entry.preferred_command == "tree.node.archive"
|
||||
|
||||
Reference in New Issue
Block a user