推进本地索引与 AI changed-files 审计
- 为本地工作区补充 search/backlinks/tags/resource 引用索引与 watcher 单文件刷新 - 在页面设置中增加索引页签,并展示本地反链、标签和 AI changed-files 审计 - 补充本地搜索与本地 AI changed-files 浏览器 smoke,并回填当前优先级 checklist
This commit is contained in:
@@ -67,7 +67,14 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
pageAiSessionSearchResults: [],
|
||||
pageAiSessionSearchTimer: 0,
|
||||
pageAiSessionError: '',
|
||||
pageAiPermissionRequests: []
|
||||
pageAiPermissionRequests: [],
|
||||
localIndexSummary: {
|
||||
scopeKey: '',
|
||||
loading: false,
|
||||
error: '',
|
||||
backlinks: null,
|
||||
tags: null
|
||||
}
|
||||
};
|
||||
|
||||
function closestAction(target, selector) {
|
||||
@@ -6497,6 +6504,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
'<div class="wolai-page-settings-tabs" data-testid="wolai-page-settings-tabs" role="tablist" aria-label="页面设置分组">' +
|
||||
'<button type="button" class="wolai-page-settings-tab is-active" role="tab" aria-selected="true" data-page-settings-tab="page">页面选项</button>' +
|
||||
'<button type="button" class="wolai-page-settings-tab" role="tab" aria-selected="false" data-page-settings-tab="custom">自定义页面</button>' +
|
||||
'<button type="button" class="wolai-page-settings-tab" role="tab" aria-selected="false" data-page-settings-tab="index">索引</button>' +
|
||||
'<button type="button" class="wolai-page-settings-tab" role="tab" aria-selected="false" data-page-settings-tab="global">全局选项</button>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-settings-section" data-page-settings-panel="page">' +
|
||||
@@ -6512,6 +6520,19 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
createPageOptionRow('hideChildPages', 'checkbox') +
|
||||
createPageOptionRow('showBlockRefCount', 'checkbox') +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-settings-section" data-page-settings-panel="index" hidden>' +
|
||||
'<div class="wolai-page-settings-index-panel" data-testid="wolai-page-settings-local-index-panel">' +
|
||||
'<div class="wolai-page-settings-index-status" data-testid="wolai-page-settings-local-index-status"></div>' +
|
||||
'<section class="wolai-page-settings-index-group">' +
|
||||
'<div class="wolai-page-settings-index-title">反链</div>' +
|
||||
'<div class="wolai-page-settings-index-list" data-testid="wolai-page-settings-local-index-backlinks"></div>' +
|
||||
'</section>' +
|
||||
'<section class="wolai-page-settings-index-group">' +
|
||||
'<div class="wolai-page-settings-index-title">标签</div>' +
|
||||
'<div class="wolai-page-settings-index-list" data-testid="wolai-page-settings-local-index-tags"></div>' +
|
||||
'</section>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-page-settings-section" data-page-settings-panel="global" hidden>' +
|
||||
createGlobalHeadingNumbersRow() +
|
||||
'</div>' +
|
||||
@@ -6528,6 +6549,149 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
return popover;
|
||||
}
|
||||
|
||||
function pageSettingsLocalIndexScopeKey() {
|
||||
return [
|
||||
currentSourceKind(),
|
||||
currentRootUri(),
|
||||
resolveWorkspaceId(document.body),
|
||||
currentDocumentId()
|
||||
].join('|');
|
||||
}
|
||||
|
||||
function pageSettingsLocalIndexIsAvailable() {
|
||||
return currentSourceKind() === 'local_folder' && Boolean(currentRootUri()) && Boolean(currentDocumentId());
|
||||
}
|
||||
|
||||
function pageSettingsLocalIndexEmpty(message) {
|
||||
return '<div class="wolai-page-settings-index-empty">' + escapeHtml(message) + '</div>';
|
||||
}
|
||||
|
||||
function renderPageSettingsLocalIndexList(items, kind) {
|
||||
var rows = Array.isArray(items) ? items : [];
|
||||
if (!rows.length) {
|
||||
return pageSettingsLocalIndexEmpty(kind === 'backlinks' ? '暂无反链' : '暂无标签');
|
||||
}
|
||||
if (kind === 'backlinks') {
|
||||
return rows.slice(0, 12).map(function(item) {
|
||||
var title = searchText(item && item.title) || searchText(item && item.path) || '未命名页面';
|
||||
var path = searchText(item && item.path);
|
||||
var snippet = searchText(item && item.snippet);
|
||||
return '' +
|
||||
'<div class="wolai-page-settings-index-row">' +
|
||||
'<div class="wolai-page-settings-index-row-title">' + escapeHtml(title) + '</div>' +
|
||||
(path ? '<div class="wolai-page-settings-index-row-meta">' + escapeHtml(path) + '</div>' : '') +
|
||||
(snippet ? '<div class="wolai-page-settings-index-row-snippet">' + escapeHtml(snippet) + '</div>' : '') +
|
||||
'</div>';
|
||||
}).join('');
|
||||
}
|
||||
return rows.slice(0, 16).map(function(item) {
|
||||
var tag = searchText(item && item.tag) || 'untagged';
|
||||
var count = Number(item && item.count || 0);
|
||||
return '' +
|
||||
'<div class="wolai-page-settings-index-row is-tag">' +
|
||||
'<div class="wolai-page-settings-index-row-title">#' + escapeHtml(tag) + '</div>' +
|
||||
'<div class="wolai-page-settings-index-row-meta">' + count + ' 个页面</div>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function renderPageSettingsLocalIndex(popover) {
|
||||
popover = popover || ensurePageSettingsPopover();
|
||||
var statusNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-status"]');
|
||||
var backlinksNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-backlinks"]');
|
||||
var tagsNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-tags"]');
|
||||
if (!(statusNode instanceof HTMLElement) || !(backlinksNode instanceof HTMLElement) || !(tagsNode instanceof HTMLElement)) return;
|
||||
|
||||
if (!pageSettingsLocalIndexIsAvailable()) {
|
||||
statusNode.textContent = '本地索引仅在本地工作区页面可用';
|
||||
backlinksNode.innerHTML = pageSettingsLocalIndexEmpty('未连接本地 root');
|
||||
tagsNode.innerHTML = pageSettingsLocalIndexEmpty('未连接本地 root');
|
||||
return;
|
||||
}
|
||||
|
||||
var summary = pageUiState.localIndexSummary || {};
|
||||
if (summary.loading) {
|
||||
statusNode.textContent = '正在读取本地索引...';
|
||||
backlinksNode.innerHTML = pageSettingsLocalIndexEmpty('加载中');
|
||||
tagsNode.innerHTML = pageSettingsLocalIndexEmpty('加载中');
|
||||
return;
|
||||
}
|
||||
if (summary.error) {
|
||||
statusNode.textContent = '本地索引读取失败';
|
||||
backlinksNode.innerHTML = pageSettingsLocalIndexEmpty(summary.error);
|
||||
tagsNode.innerHTML = pageSettingsLocalIndexEmpty(summary.error);
|
||||
return;
|
||||
}
|
||||
if (summary.scopeKey !== pageSettingsLocalIndexScopeKey()) {
|
||||
statusNode.textContent = '切换到索引页签后读取本地索引';
|
||||
backlinksNode.innerHTML = pageSettingsLocalIndexEmpty('等待读取');
|
||||
tagsNode.innerHTML = pageSettingsLocalIndexEmpty('等待读取');
|
||||
return;
|
||||
}
|
||||
|
||||
statusNode.textContent = '来自当前授权 root 的 .mnote/index/search-index.json';
|
||||
backlinksNode.innerHTML = renderPageSettingsLocalIndexList(summary.backlinks, 'backlinks');
|
||||
tagsNode.innerHTML = renderPageSettingsLocalIndexList(summary.tags, 'tags');
|
||||
}
|
||||
|
||||
async function loadPageSettingsLocalIndex(force) {
|
||||
if (!pageSettingsLocalIndexIsAvailable()) {
|
||||
renderPageSettingsLocalIndex();
|
||||
return;
|
||||
}
|
||||
var scopeKey = pageSettingsLocalIndexScopeKey();
|
||||
var current = pageUiState.localIndexSummary || {};
|
||||
if (!force && current.scopeKey === scopeKey && !current.error && !current.loading) {
|
||||
renderPageSettingsLocalIndex();
|
||||
return;
|
||||
}
|
||||
pageUiState.localIndexSummary = {
|
||||
scopeKey: scopeKey,
|
||||
loading: true,
|
||||
error: '',
|
||||
backlinks: null,
|
||||
tags: null
|
||||
};
|
||||
renderPageSettingsLocalIndex();
|
||||
try {
|
||||
var baseParams = new URLSearchParams();
|
||||
baseParams.set('workspaceId', resolveWorkspaceId(document.body));
|
||||
baseParams.set('rootUri', currentRootUri());
|
||||
var backlinksParams = new URLSearchParams(baseParams);
|
||||
backlinksParams.set('documentId', currentDocumentId());
|
||||
var backlinksUrl = '/api/search/local-index/backlinks?' + backlinksParams.toString();
|
||||
var tagsUrl = '/api/search/local-index/tags?' + baseParams.toString();
|
||||
var responses = await Promise.all([
|
||||
fetch(backlinksUrl, { headers: { accept: 'application/json' } }),
|
||||
fetch(tagsUrl, { headers: { accept: 'application/json' } })
|
||||
]);
|
||||
var backlinksPayload = await responses[0].json().catch(function(){ return null; });
|
||||
var tagsPayload = await responses[1].json().catch(function(){ return null; });
|
||||
if (!responses[0].ok || !backlinksPayload || backlinksPayload.ok !== true) {
|
||||
throw new Error('backlinks_' + responses[0].status);
|
||||
}
|
||||
if (!responses[1].ok || !tagsPayload || tagsPayload.ok !== true) {
|
||||
throw new Error('tags_' + responses[1].status);
|
||||
}
|
||||
pageUiState.localIndexSummary = {
|
||||
scopeKey: scopeKey,
|
||||
loading: false,
|
||||
error: '',
|
||||
backlinks: backlinksPayload.result && Array.isArray(backlinksPayload.result.backlinks) ? backlinksPayload.result.backlinks : [],
|
||||
tags: tagsPayload.result && Array.isArray(tagsPayload.result.tags) ? tagsPayload.result.tags : []
|
||||
};
|
||||
} catch (error) {
|
||||
pageUiState.localIndexSummary = {
|
||||
scopeKey: scopeKey,
|
||||
loading: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
backlinks: [],
|
||||
tags: []
|
||||
};
|
||||
}
|
||||
renderPageSettingsLocalIndex();
|
||||
}
|
||||
|
||||
function renderPageSettingsPopover() {
|
||||
var popover = ensurePageSettingsPopover();
|
||||
var options = currentPageOptions();
|
||||
@@ -6551,6 +6715,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
'<span>块数 ' + Number(stats.blockCount || 0) + '</span>' +
|
||||
'<span>待办 ' + Number(stats.todoDone || 0) + '/' + Number(stats.todoTotal || 0) + '</span>';
|
||||
}
|
||||
renderPageSettingsLocalIndex(popover);
|
||||
}
|
||||
|
||||
function setActivePageSettingsTab(tabName) {
|
||||
@@ -6563,6 +6728,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
popover.querySelectorAll('[data-page-settings-panel]').forEach(function(panel) {
|
||||
panel.hidden = panel.getAttribute('data-page-settings-panel') !== tabName;
|
||||
});
|
||||
if (tabName === 'index') void loadPageSettingsLocalIndex(false);
|
||||
}
|
||||
|
||||
async function persistPageOptionsPatch(patch) {
|
||||
|
||||
@@ -2835,6 +2835,76 @@ body {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-status {
|
||||
color: #8B8782;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-title {
|
||||
color: #1B1C1C;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-row,
|
||||
.wolai-page-settings-index-empty {
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
background: #F7F6F4;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-row {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-row.is-tag {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-row-title {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #1B1C1C;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.wolai-page-settings-index-row-meta,
|
||||
.wolai-page-settings-index-row-snippet,
|
||||
.wolai-page-settings-index-empty {
|
||||
color: #8B8782;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.wolai-page-setting-row {
|
||||
min-height: 48px;
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user