fix: stabilize local folder AI document workflow
- scope local-folder PageTree revision and document sidebar rendering to fileTreeScope - preserve projected table/image attrs for local Markdown aggregate fallback - avoid FileTree restore forced layouts on cold design open - add API ChatOnly provider runtime and local OCR task handling regressions
This commit is contained in:
@@ -1440,12 +1440,9 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
}
|
||||
}
|
||||
if (fileTreeState.loadingParents.has(key)) {
|
||||
return fileTreeState.loadingParents.get(key).then(function(rows) {
|
||||
fileTreeState.dirtyParents.delete(key);
|
||||
return isFileTreeRootProjectionParent(parentRelativePath)
|
||||
? renderFileProjection({ parentRelativePath: parentRelativePath, items: rows })
|
||||
: patchFileTreeParentChildren(parentRelativePath, rows);
|
||||
});
|
||||
// 变更事件可能正好撞上同一 parent 的懒加载请求。
|
||||
// 旧请求结果不包含刚落盘的文件,不能直接拿它满足本次刷新。
|
||||
await fileTreeState.loadingParents.get(key).catch(function() { return []; });
|
||||
}
|
||||
var projection = await fetchFileTreeProjection(parentRelativePath, { childrenOnly: false });
|
||||
if (!projection) return false;
|
||||
@@ -1556,13 +1553,14 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
return '';
|
||||
}
|
||||
|
||||
function setTreeRowExpanded(row, button, expanded) {
|
||||
function setTreeRowExpanded(row, button, expanded, options) {
|
||||
row.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
||||
var shellMode = row.getAttribute('data-shell-mode') || '';
|
||||
if (button) {
|
||||
button.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
||||
if (shellMode === 'filetree') button.textContent = expanded ? '▾' : '▸';
|
||||
}
|
||||
var shouldPersist = !(options && options.persist === false);
|
||||
if (shellMode === 'page') {
|
||||
var nodeId = String(row.getAttribute('data-node-id') || '').trim();
|
||||
if (!nodeId) return;
|
||||
@@ -1570,18 +1568,20 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
if (expanded) pageState.expandedIds.add(nodeId);
|
||||
else pageState.expandedIds.delete(nodeId);
|
||||
pageState.hasUserState = true;
|
||||
persistSidebarTreeViewState('pagetree');
|
||||
if (shouldPersist) persistSidebarTreeViewState('pagetree');
|
||||
return;
|
||||
}
|
||||
var relativePath = localFileTreeRelativePathFromRow(row);
|
||||
if (!relativePath) return;
|
||||
if (expanded) fileTreeExpandedRelativePaths.add(relativePath);
|
||||
else fileTreeExpandedRelativePaths.delete(relativePath);
|
||||
persistFileTreeExpansionState();
|
||||
persistSidebarTreeViewState('filetree');
|
||||
if (shouldPersist) {
|
||||
persistFileTreeExpansionState();
|
||||
persistSidebarTreeViewState('filetree');
|
||||
}
|
||||
}
|
||||
|
||||
function markExistingFileTreeChildrenLoaded(row, button) {
|
||||
function markExistingFileTreeChildrenLoaded(row, button, options) {
|
||||
if (!(row instanceof HTMLElement)) return false;
|
||||
var node = row.closest('.tree-node');
|
||||
if (!node) return false;
|
||||
@@ -1589,12 +1589,12 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
if (!(children instanceof HTMLElement)) return false;
|
||||
row.setAttribute('data-filetree-children-loaded', 'true');
|
||||
children.classList.remove('tree-children--collapsed');
|
||||
setTreeRowExpanded(row, button, true);
|
||||
setTreeRowExpanded(row, button, true, options);
|
||||
syncSidebarFileTreeSelection();
|
||||
return true;
|
||||
}
|
||||
|
||||
function renderCachedFileTreeChildren(row, button, relativePath) {
|
||||
function renderCachedFileTreeChildren(row, button, relativePath, options) {
|
||||
var key = currentFileTreeParentKey(relativePath);
|
||||
if (fileTreeState.staleParents.has(key) || fileTreeState.dirtyParents.has(key)) return false;
|
||||
var cachedRows = cachedFileTreeRows(relativePath);
|
||||
@@ -1612,7 +1612,7 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
children.replaceChildren(template.content.cloneNode(true));
|
||||
children.classList.remove('tree-children--collapsed');
|
||||
row.setAttribute('data-filetree-children-loaded', 'true');
|
||||
setTreeRowExpanded(row, button, true);
|
||||
setTreeRowExpanded(row, button, true, options);
|
||||
syncSidebarFileTreeSelection();
|
||||
return true;
|
||||
}
|
||||
@@ -1641,7 +1641,7 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
return promise;
|
||||
}
|
||||
|
||||
async function loadFileTreeChildren(row, button) {
|
||||
async function loadFileTreeChildren(row, button, options) {
|
||||
if (!(row instanceof HTMLElement)) return false;
|
||||
if (row.getAttribute('data-shell-mode') !== 'filetree') return false;
|
||||
if (currentSourceKind() !== 'local_folder') return false;
|
||||
@@ -1649,21 +1649,21 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
var relativePath = localFileTreeRelativePathFromRow(row);
|
||||
var key = currentFileTreeParentKey(relativePath);
|
||||
var stale = fileTreeState.staleParents.has(key) || fileTreeState.dirtyParents.has(key);
|
||||
if (!stale && markExistingFileTreeChildrenLoaded(row, button)) return true;
|
||||
if (!stale && relativePath && renderCachedFileTreeChildren(row, button, relativePath)) return true;
|
||||
if (!stale && markExistingFileTreeChildrenLoaded(row, button, options)) return true;
|
||||
if (!stale && relativePath && renderCachedFileTreeChildren(row, button, relativePath, options)) return true;
|
||||
if (row.getAttribute('data-filetree-children-loaded') === 'true') return false;
|
||||
var rootUri = currentRootUri();
|
||||
if (!rootUri || !relativePath) return false;
|
||||
setTreeRowExpanded(row, button, true);
|
||||
setTreeRowExpanded(row, button, true, options);
|
||||
row.setAttribute('data-filetree-children-loading', 'true');
|
||||
try {
|
||||
var rows = await getFileTreeChildren(relativePath);
|
||||
if (!rows.length) {
|
||||
row.setAttribute('data-filetree-children-loaded', 'true');
|
||||
setTreeRowExpanded(row, button, true);
|
||||
setTreeRowExpanded(row, button, true, options);
|
||||
return true;
|
||||
}
|
||||
return renderCachedFileTreeChildren(row, button, relativePath);
|
||||
return renderCachedFileTreeChildren(row, button, relativePath, options);
|
||||
} catch (error) {
|
||||
setTreeLiveApplyError(error && error.message ? error.message : '文件树子目录加载失败');
|
||||
return false;
|
||||
@@ -1731,6 +1731,15 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
setTreeRowExpanded(row, button, !collapsed);
|
||||
}
|
||||
|
||||
function shouldAutoRestoreFileTreeExpansion(relativePath) {
|
||||
var normalized = normalizeFileTreeRelativePath(relativePath);
|
||||
if (!normalized) return false;
|
||||
var scope = normalizeFileTreeRelativePath(currentFileTreeScope());
|
||||
if (!scope) return normalized.indexOf('/') < 0;
|
||||
if (normalized.indexOf(scope + '/') !== 0) return false;
|
||||
return normalized.slice(scope.length + 1).indexOf('/') < 0;
|
||||
}
|
||||
|
||||
function restorePersistedFileTreeExpansionState() {
|
||||
if (currentSourceKind() !== 'local_folder') return false;
|
||||
ensureFileTreeLazyCacheScope();
|
||||
@@ -1741,17 +1750,20 @@ export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
|
||||
if (String(row.getAttribute('data-row-kind') || '').trim() !== 'folder') return;
|
||||
var relativePath = localFileTreeRelativePathFromRow(row);
|
||||
if (!relativePath || !fileTreeExpandedRelativePaths.has(relativePath)) return;
|
||||
// 首屏只自动恢复当前 scope 的直接子目录。历史 view-state 可能记录了
|
||||
// 多层 design 目录展开;一次性递归恢复会长时间占满浏览器主线程。
|
||||
if (!shouldAutoRestoreFileTreeExpansion(relativePath)) return;
|
||||
var button = row.querySelector('[data-rust-action="toggle"]');
|
||||
if (markExistingFileTreeChildrenLoaded(row, button)) {
|
||||
if (markExistingFileTreeChildrenLoaded(row, button, { persist: false })) {
|
||||
restored = true;
|
||||
return;
|
||||
}
|
||||
if (row.getAttribute('data-filetree-children-loaded') === 'true') {
|
||||
setTreeRowExpanded(row, button, true);
|
||||
setTreeRowExpanded(row, button, true, { persist: false });
|
||||
restored = true;
|
||||
return;
|
||||
}
|
||||
void loadFileTreeChildren(row, button).then(function(loaded) {
|
||||
void loadFileTreeChildren(row, button, { persist: false }).then(function(loaded) {
|
||||
if (loaded) restorePersistedFileTreeExpansionState();
|
||||
});
|
||||
restored = true;
|
||||
|
||||
Reference in New Issue
Block a user