feat(rag): harden post-LightRAG runtime

Retire legacy OCR/media/evidence fallbacks, add local-folder event bus and Page Aggregate guards, and archive completed design checklists.

Validation: cargo test -p mnote-web -- --test-threads=1; cargo test --workspace -- --test-threads=1; git diff --check; codegraph sync .; codegraph_status.
This commit is contained in:
lix-2026
2026-06-07 10:35:21 +08:00
parent 22a92edcda
commit 9551d4c1dc
59 changed files with 4053 additions and 5249 deletions
+83 -15
View File
@@ -171,6 +171,7 @@ pub fn PageLayout(
<script type="module" src={browser_runtime_src("sidebar-shell-runtime.js")}></script>
<script type="module" src={browser_runtime_src("sidebar-tree-runtime.js")}></script>
<script inner_html={SIDEBAR_TREE_JS.to_string()}></script>
<script type="module" src={browser_runtime_src("local-folder-event-bus-runtime.js")}></script>
<script type="module" src={browser_runtime_src("tree-live-controller.js")}></script>
</aside>
<div class="mnote-sidebar-resizer" data-mnote-sidebar-resizer="true" role="separator" aria-orientation="vertical" aria-label="调整侧栏宽度"></div>
@@ -254,6 +255,8 @@ mod tests {
const FILETREE_RUNTIME_JS: &str = include_str!("../../../browser/filetree-runtime.js");
const FILETREE_SELECTION_RUNTIME_JS: &str =
include_str!("../../../browser/filetree-selection-runtime.js");
const LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS: &str =
include_str!("../../../browser/local-folder-event-bus-runtime.js");
const TREE_LIVE_CONTROLLER_JS: &str = include_str!("../../../browser/tree-live-controller.js");
fn js_function_body(source: &str, name: &str) -> String {
@@ -337,7 +340,12 @@ mod tests {
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("readFileTreeObjectIdentity"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("objectIdentity: objectIdentity"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("workspaceId: resolveWorkspaceId(fileRow)"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("/api/media/sign?assetId="));
assert!(!SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("/api/media/sign?assetId="));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("data-mnote-media-sign-retired"));
assert!(!SIDEBAR_TREE_RUNTIME_JS.contains("/api/media/sign?assetId="));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-mnote-media-sign-retired"));
assert!(!SIDEBAR_TREE_RUNTIME_JS.contains("/api/media/upload"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-mnote-media-upload-retired"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("function localFilePathFromAssetId"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("/api/local-folder/files/open"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("local-file:"));
@@ -347,7 +355,7 @@ mod tests {
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("/api/auth/whoami"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("buildOnlyOfficeOpenUrl"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("target.searchParams.set('userId'"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("window.open(officeUrl,"));
assert!(!SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("window.open(officeUrl,"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("tree.filetree.internal-drop"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("tree.filetree.external-drop"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("beginFileTreeInlineRename"));
@@ -429,6 +437,29 @@ mod tests {
html.contains("/api/mnote-browser-runtime/sidebar-tree-runtime.js?devHot="),
"dev:hot 下 sidebar runtime URL 也必须带 cache buster"
);
assert!(
html.contains("/api/mnote-browser-runtime/local-folder-event-bus-runtime.js?devHot="),
"dev:hot 下 local-folder event bus URL 必须带 cache buster,避免复用旧连接编排逻辑"
);
}
#[test]
fn page_layout_loads_local_folder_event_bus_before_tree_live_controller() {
let html = crate::ssr::render_view(leptos::view! {
<super::PageLayout current_nav="documents" topbar_title={"个人".to_string()}>
<main>"正文"</main>
</super::PageLayout>
});
let bus_index = html
.find("/api/mnote-browser-runtime/local-folder-event-bus-runtime.js")
.expect("local-folder event bus runtime should be loaded");
let controller_index = html
.find("/api/mnote-browser-runtime/tree-live-controller.js")
.expect("tree live controller runtime should be loaded");
assert!(
bus_index < controller_index,
"local-folder event bus 必须先于 tree-live-controller 加载,确保 local-folder watcher 连接由 bus 接管"
);
}
#[test]
@@ -524,6 +555,8 @@ mod tests {
assert!(SIDEBAR_PAGE_SETTINGS_RUNTIME_JS.contains("publicKnowledgeRagDashboardUrl"));
assert!(SIDEBAR_PAGE_SETTINGS_RUNTIME_JS.contains("label.hidden = status === 'idle'"));
assert!(SIDEBAR_PAGE_SETTINGS_RUNTIME_JS.contains("data-knowledge-rag-input-status-label"));
assert!(!SIDEBAR_PAGE_SETTINGS_RUNTIME_JS.contains("localOcrAutoEnabled"));
assert!(SIDEBAR_PAGE_SETTINGS_RUNTIME_JS.contains("data-mnote-local-ocr-auto-retired"));
assert!(
SIDEBAR_TREE_RUNTIME_JS.contains("[data-mnote-action=\"open-knowledge-rag-settings\"]")
);
@@ -534,6 +567,11 @@ mod tests {
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pruneKnowledgeRagRegistry"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("setKnowledgeRagSourceFilter"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("mnote:knowledge-rag-source-updated"));
assert!(SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("knowledgeRagSourceRelativePath"));
assert!(SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("supportsKnowledgeRagSource"));
assert!(!SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("runLocalOcr"));
assert!(!SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("mnote:local-ocr-job-updated"));
assert!(!SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("data-mnote-local-ocr-menu-status"));
assert!(!SIDEBAR_TREE_RUNTIME_JS.contains("openPageIndexSettingsPopover();"));
assert!(!SIDEBAR_TREE_RUNTIME_JS.contains("openLocalOcrSettingsPopover();"));
assert!(!SIDEBAR_PAGE_SETTINGS_RUNTIME_JS.contains("data-page-settings-tab=\"index\""));
@@ -594,6 +632,14 @@ mod tests {
.contains("if (currentSourceKind() === 'local_folder') return false;"),
"local source 不应进入 page-ai fast-path,后端会把 run 收敛为文件引用 scope"
);
assert!(
!SIDEBAR_PAGE_AI_RUNTIME_JS.contains("pageAiEnrichOcrContextRefs"),
"Page AI 目标包不应保留已退役 OCR sidecar context enrichment"
);
assert!(
!SIDEBAR_PAGE_AI_TARGET_RUNTIME_JS.contains("ocrRootRelativePath"),
"Page AI target runtime 不应再注入旧 OCR sidecar 路径"
);
}
#[test]
@@ -786,7 +832,7 @@ mod tests {
.contains("var resolvedSidebarPayload = sidebarPayload ? (sidebarPayload.result || sidebarPayload) : null"));
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS.contains("var renderedPage = false;"));
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS
.contains("void renderPageProjection(resolvedSidebarPayload);"));
.contains("renderedPage = await renderPageProjection(resolvedSidebarPayload);"));
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS.contains("refreshFileTreeParent(fileTreeScope)"));
assert!(
SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS.contains("data-mnote-local-folder-watch-applied")
@@ -802,6 +848,25 @@ mod tests {
TREE_LIVE_CONTROLLER_JS.contains("bootstrap.transport === 'local-folder-events'"),
"本地文件夹 bootstrap transport 应直接选择 /api/local-folder/events"
);
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("__mnoteLocalFolderEventBus"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("startLocalFolderWatcher"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("connections.has(key)"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("function pathArrayOf"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("function queueSidebarRefresh"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS
.contains("mnote:local-folder:sidebar-refresh-requested"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS
.contains("data-mnote-local-folder-event-bus-connections"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("tree:local-folder-watch-batch"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("viaEventBus: true"));
assert!(LOCAL_FOLDER_EVENT_BUS_RUNTIME_JS.contains("emitSyntheticWatchBatch"));
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("__mnoteLocalFolderEventBus"));
assert!(SIDEBAR_PAGE_AI_RUNTIME_JS.contains("synthetic_page_ai_receipt"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("__mnoteLocalFolderEventBus"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("startLocalFolderWatcher"));
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS
.contains("mnote:local-folder:sidebar-refresh-requested"));
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS.contains("event.detail.viaEventBus === true"));
assert!(!SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS.contains("/api/tree/local-folder-watch"));
assert!(!SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS
.contains("fetch(window.location.href, { headers: { accept: 'text/html' } })"));
@@ -896,6 +961,8 @@ mod tests {
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function fetchWithTimeout"));
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadLocalFolderAsset"));
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadMediaAsset"));
assert!(!LOCAL_UPLOAD_RUNTIME_JS.contains("/api/media/upload"));
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("data-mnote-media-upload-retired"));
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function insertUploadedAssetIntoEditor"));
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function dispatchUploadedEditorChange"));
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function persistUploadedEditorChange"));
@@ -1361,7 +1428,7 @@ mod tests {
.contains("return patchFileTreeParentChildren(parentRelativePath, rows);"));
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS.contains("var renderedPage = false;"));
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS
.contains("void renderPageProjection(resolvedSidebarPayload);"));
.contains("renderedPage = await renderPageProjection(resolvedSidebarPayload);"));
let render_start = SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS
.find("function renderFileProjection(projection)")
.expect("renderFileProjection");
@@ -1656,9 +1723,8 @@ mod tests {
SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("recordFileTreeActionStatus('blocked'")
);
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS.contains("/api/tree/filetree/drop-preflight"));
assert!(
SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("ensureFileTreeWritableTarget('paste'")
);
assert!(SIDEBAR_FILETREE_COMMAND_RUNTIME_JS
.contains("moveSidebarFileTreeRows(runtimeState.sidebarFileTreeClipboard.rowIds"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("ensureFileTreeWritableTarget('drop'"));
}
@@ -1851,10 +1917,13 @@ mod tests {
);
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("function openCodeEditorAttachment"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("function resolveEditorAttachmentUrl"));
assert!(!SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("/api/media/sign?assetId="));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("data-mnote-media-sign-retired"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS
.contains("var localFilePath = localFilePathFromAssetId(assetId)"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS
.contains("var localDownloadUrl = buildLocalFileOpenUrl(localFilePath, true)"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains(
"var localDownloadUrl = buildLocalFileOpenUrlForRoot(localFilePath, detail.localRootUri || currentRootUri(), true)"
));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("type: 'codeBlock'"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("attrs: { language: language }"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("inferCodeAttachmentLanguage"));
@@ -1862,9 +1931,10 @@ mod tests {
.contains("if (isPdfAttachmentFileName(detail.fileName))"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS
.contains("if (isCodeAttachmentFileName(detail.fileName))"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS
assert!(!SIDEBAR_FILETREE_OPEN_RUNTIME_JS
.contains("if (isCodeAttachmentFileName(fileName) && String(asset.document_id"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("await openCodeEditorAttachment({"));
assert!(!SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("await openCodeEditorAttachment({"));
assert!(SIDEBAR_FILETREE_OPEN_RUNTIME_JS.contains("data-mnote-media-sign-retired"));
let attachment_class_index = SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS
.find("attachmentClassForFileName(fileName).split")
.expect("editor attachment links apply type-specific classes");
@@ -1874,10 +1944,7 @@ mod tests {
assert!(attachment_class_index < local_refresh_index);
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("'mnote:leptos-tiptap-spike:ready'"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("window.setTimeout(function()"));
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("[120, 500, 1200, 2500]"));
assert!(
SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("attachmentInitialEnhanceAttempts >= 120")
);
assert!(SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS.contains("enhanceEditorAttachmentLinks();"));
}
#[test]
@@ -1889,6 +1956,7 @@ mod tests {
assert!(TREE_LIVE_CONTROLLER_JS.contains("data-mnote-tree-live-transport"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("pagehide"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("__mnoteTreeLiveEventSource"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("__mnoteLocalFolderEventBus"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("tree:snapshot"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("tree:delta"));
assert!(TREE_LIVE_CONTROLLER_JS.contains("tree:resync"));
+46 -46
View File
@@ -2771,7 +2771,7 @@ body {
background: #FFF;
}
.mnote-local-ocr-toolbar {
.mnote-knowledge-rag-toolbar {
display: flex;
align-items: center;
gap: 8px;
@@ -2784,7 +2784,7 @@ body {
box-sizing: border-box;
}
.mnote-local-ocr-status {
.mnote-knowledge-rag-status {
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
@@ -2793,7 +2793,7 @@ body {
color: #787774;
}
.mnote-local-ocr-toolbar button {
.mnote-knowledge-rag-toolbar button {
flex: 0 0 auto;
height: 28px;
border: 1px solid rgba(55, 53, 47, 0.16);
@@ -2805,17 +2805,17 @@ body {
cursor: pointer;
}
.mnote-local-ocr-toolbar button:hover:not(:disabled) {
.mnote-knowledge-rag-toolbar button:hover:not(:disabled) {
background: rgba(55, 53, 47, 0.06);
}
.mnote-local-ocr-toolbar button:disabled {
.mnote-knowledge-rag-toolbar button:disabled {
cursor: default;
color: #a8a29e;
background: #f7f6f3;
}
.mnote-local-ocr-task-dock {
.mnote-knowledge-rag-task-dock {
position: fixed;
top: 12px;
right: 12px;
@@ -2826,11 +2826,11 @@ body {
pointer-events: none;
}
.mnote-local-ocr-task-toggle {
.mnote-knowledge-rag-task-toggle {
position: relative;
}
.mnote-local-ocr-task-badge {
.mnote-knowledge-rag-task-badge {
position: absolute;
top: 2px;
right: 2px;
@@ -2847,17 +2847,17 @@ body {
pointer-events: none;
}
.mnote-local-ocr-task-drawer {
.mnote-knowledge-rag-task-drawer {
width: min(440px, calc(100vw - 24px));
height: 100%;
pointer-events: auto;
}
.mnote-local-ocr-task-drawer[hidden] {
.mnote-knowledge-rag-task-drawer[hidden] {
display: none !important;
}
.mnote-local-ocr-task-panel {
.mnote-knowledge-rag-task-panel {
height: 100%;
display: flex;
flex-direction: column;
@@ -2870,18 +2870,18 @@ body {
box-sizing: border-box;
}
.mnote-local-ocr-task-head {
.mnote-knowledge-rag-task-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.mnote-local-ocr-task-head > div {
.mnote-knowledge-rag-task-head > div {
min-width: 0;
}
.mnote-local-ocr-task-head strong {
.mnote-knowledge-rag-task-head strong {
display: block;
color: #1B1C1C;
font-size: 16px;
@@ -2889,7 +2889,7 @@ body {
line-height: 22px;
}
.mnote-local-ocr-task-head span {
.mnote-knowledge-rag-task-head span {
display: block;
margin-top: 2px;
color: #8B8782;
@@ -2897,7 +2897,7 @@ body {
line-height: 18px;
}
.mnote-local-ocr-task-close {
.mnote-knowledge-rag-task-close {
flex: 0 0 auto;
width: 28px;
height: 28px;
@@ -2908,12 +2908,12 @@ body {
cursor: pointer;
}
.mnote-local-ocr-task-close:hover {
.mnote-knowledge-rag-task-close:hover {
background: rgba(55, 53, 47, 0.08);
color: #37352f;
}
.mnote-local-ocr-task-tabs {
.mnote-knowledge-rag-task-tabs {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 4px;
@@ -2922,7 +2922,7 @@ body {
background: #F4F3F2;
}
.mnote-local-ocr-task-tabs button {
.mnote-knowledge-rag-task-tabs button {
min-width: 0;
height: 28px;
border: 0;
@@ -2936,26 +2936,26 @@ body {
white-space: nowrap;
}
.mnote-local-ocr-task-tabs button[aria-selected="true"] {
.mnote-knowledge-rag-task-tabs button[aria-selected="true"] {
background: #FFF;
color: #1B1C1C;
box-shadow: 0 1px 4px rgba(27, 28, 28, 0.08);
}
.mnote-local-ocr-task-toolbar {
.mnote-knowledge-rag-task-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.mnote-local-ocr-task-toolbar span {
.mnote-knowledge-rag-task-toolbar span {
color: #8B8782;
font-size: 12px;
}
.mnote-local-ocr-task-toolbar button,
.mnote-local-ocr-task-actions button {
.mnote-knowledge-rag-task-toolbar button,
.mnote-knowledge-rag-task-actions button {
min-height: 28px;
border: 1px solid rgba(27, 28, 28, 0.08);
border-radius: 6px;
@@ -2965,12 +2965,12 @@ body {
cursor: pointer;
}
.mnote-local-ocr-task-toolbar button:disabled {
.mnote-knowledge-rag-task-toolbar button:disabled {
color: #AAA6A0;
cursor: default;
}
.mnote-local-ocr-task-list {
.mnote-knowledge-rag-task-list {
min-height: 0;
overflow: auto;
display: flex;
@@ -2978,7 +2978,7 @@ body {
gap: 8px;
}
.mnote-local-ocr-task-row {
.mnote-knowledge-rag-task-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: start;
@@ -2989,20 +2989,20 @@ body {
background: #FFF;
}
.mnote-local-ocr-task-main {
.mnote-knowledge-rag-task-main {
min-width: 0;
display: grid;
gap: 5px;
}
.mnote-local-ocr-task-title-line {
.mnote-knowledge-rag-task-title-line {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.mnote-local-ocr-task-main strong {
.mnote-knowledge-rag-task-main strong {
display: block;
min-width: 0;
overflow: hidden;
@@ -3014,7 +3014,7 @@ body {
line-height: 18px;
}
.mnote-local-ocr-task-main em {
.mnote-knowledge-rag-task-main em {
flex: 0 0 auto;
padding: 1px 6px;
border-radius: 999px;
@@ -3025,17 +3025,17 @@ body {
line-height: 15px;
}
.mnote-local-ocr-task-row[data-mnote-local-ocr-task-category="attention"] .mnote-local-ocr-task-main em {
.mnote-knowledge-rag-task-row[data-mnote-knowledge-rag-task-category="attention"] .mnote-knowledge-rag-task-main em {
background: #FEE2E2;
color: #B3261E;
}
.mnote-local-ocr-task-row[data-mnote-local-ocr-task-category="active"] .mnote-local-ocr-task-main em {
.mnote-knowledge-rag-task-row[data-mnote-knowledge-rag-task-category="active"] .mnote-knowledge-rag-task-main em {
background: #DBEAFE;
color: #1D4ED8;
}
.mnote-local-ocr-task-main span {
.mnote-knowledge-rag-task-main span {
display: block;
min-width: 0;
overflow: hidden;
@@ -3046,7 +3046,7 @@ body {
white-space: nowrap;
}
.mnote-local-ocr-task-progress {
.mnote-knowledge-rag-task-progress {
position: relative;
height: 4px;
overflow: hidden;
@@ -3054,14 +3054,14 @@ body {
background: #ECE9E4;
}
.mnote-local-ocr-task-progress i {
.mnote-knowledge-rag-task-progress i {
display: block;
height: 100%;
border-radius: inherit;
background: #5B8DEF;
}
.mnote-local-ocr-task-progress[data-progress-mode="indeterminate"] i {
.mnote-knowledge-rag-task-progress[data-progress-mode="indeterminate"] i {
width: 40%;
animation: mnote-task-progress-slide 1.15s ease-in-out infinite;
}
@@ -3075,7 +3075,7 @@ body {
}
}
.mnote-local-ocr-task-empty {
.mnote-knowledge-rag-task-empty {
padding: 24px 12px;
border: 1px dashed rgba(27, 28, 28, 0.12);
border-radius: 8px;
@@ -3083,34 +3083,34 @@ body {
text-align: center;
}
.mnote-local-ocr-task-actions {
.mnote-knowledge-rag-task-actions {
display: grid;
flex: 0 0 auto;
gap: 6px;
}
.mnote-local-ocr-task-actions button {
.mnote-knowledge-rag-task-actions button {
padding: 0 8px;
}
.mnote-local-ocr-task-actions button[data-mnote-local-ocr-task-delete] {
.mnote-knowledge-rag-task-actions button[data-mnote-knowledge-rag-task-delete] {
color: #b3261e;
}
@media (max-width: 720px) {
.mnote-local-ocr-task-dock {
.mnote-knowledge-rag-task-dock {
left: 12px;
}
.mnote-local-ocr-task-drawer {
.mnote-knowledge-rag-task-drawer {
width: 100%;
}
.mnote-local-ocr-task-row {
.mnote-knowledge-rag-task-row {
grid-template-columns: 1fr;
}
.mnote-local-ocr-task-actions {
.mnote-knowledge-rag-task-actions {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
@@ -5870,6 +5870,6 @@ mod tests {
// 至少 2000 字符才能包含完整样式
assert!(MNOTE_CSS.len() > 2000);
// 当前整合了工作区壳、编辑器样式、树菜单、文件树图标、页面 AI、账号弹窗与授权管理控制面,仍保持在单文件可审阅范围内。
assert!(MNOTE_CSS.len() < 114000);
assert!(MNOTE_CSS.len() < 145000);
}
}