Close workbench P0 resource lifecycle gaps
This commit is contained in:
@@ -3254,6 +3254,81 @@ pub(crate) fn render_editor_island_adapter_script() -> &'static str {
|
||||
});
|
||||
};
|
||||
|
||||
const showResourceTabCloseGuardNotice = (entry, reason) => {
|
||||
const nodes = resourceTabHostNodes();
|
||||
const messages = {
|
||||
dirty: '当前资源有未保存的修改,保存完成后再关闭。',
|
||||
saving: '当前资源正在保存中,请稍后再关闭。',
|
||||
hasExternalConflict: '当前资源存在外部冲突,请先处理冲突。',
|
||||
};
|
||||
const message = messages[reason] || '当前资源暂时无法关闭。';
|
||||
let notice = document.getElementById('mnote-resource-close-guard-notice');
|
||||
if (!notice) {
|
||||
notice = document.createElement('div');
|
||||
notice.id = 'mnote-resource-close-guard-notice';
|
||||
notice.className = 'mnote-close-guard-notice';
|
||||
notice.setAttribute('role', 'status');
|
||||
notice.setAttribute('aria-live', 'polite');
|
||||
notice.setAttribute('data-mnote-resource-close-guard', '');
|
||||
const parent = nodes.strip?.parentNode;
|
||||
if (parent instanceof HTMLElement) {
|
||||
const panels = parent.querySelector('.mnote-main-tab-panels');
|
||||
if (panels && panels.parentNode === parent) parent.insertBefore(notice, panels);
|
||||
else parent.append(notice);
|
||||
}
|
||||
}
|
||||
notice.textContent = `${entry?.title || '资源'}:${message}`;
|
||||
notice.setAttribute('data-mnote-resource-close-guard', reason || 'blocked');
|
||||
notice.className = `mnote-close-guard-notice is-${reason || 'blocked'}`;
|
||||
if (notice._mnoteHideTimer) window.clearTimeout(notice._mnoteHideTimer);
|
||||
notice._mnoteHideTimer = window.setTimeout(() => {
|
||||
notice.classList.add('is-hiding');
|
||||
window.setTimeout(() => {
|
||||
if (notice.parentNode) notice.remove();
|
||||
}, 260);
|
||||
}, 4000);
|
||||
};
|
||||
|
||||
const cssSafe = (value) => {
|
||||
const text = String(value || '');
|
||||
if (window.CSS && typeof window.CSS.escape === 'function') return window.CSS.escape(text);
|
||||
return text.replace(/["\\]/g, '\\$&');
|
||||
};
|
||||
|
||||
const syncActiveResourceFileTreeRow = (activeResource) => {
|
||||
document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-active="true"]').forEach((row) => {
|
||||
if (row instanceof HTMLElement) row.setAttribute('data-active', 'false');
|
||||
});
|
||||
const entry = activeResource ? resourceTabRegistry.get(activeResource) : null;
|
||||
if (!entry) return;
|
||||
const assetId = String(entry.assetId || entry.session?.assetId || '').trim();
|
||||
const path = String(entry.path || entry.session?.resourcePath || '').trim();
|
||||
const identity = String(entry.objectIdentity || activeResource || '').trim();
|
||||
if (assetId) {
|
||||
const row = document.querySelector(`#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-asset-id="${cssSafe(assetId)}"]`);
|
||||
if (row instanceof HTMLElement) {
|
||||
row.setAttribute('data-active', 'true');
|
||||
return;
|
||||
}
|
||||
}
|
||||
const rows = document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-object-identity]');
|
||||
for (const row of rows) {
|
||||
if (!(row instanceof HTMLElement)) continue;
|
||||
const objectIdentity = row.getAttribute('data-object-identity') || '';
|
||||
if ((identity && objectIdentity.includes(identity)) || (path && objectIdentity.includes(path))) {
|
||||
row.setAttribute('data-active', 'true');
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const syncActiveResourceUrlState = (activeResource) => {
|
||||
const url = currentUrl();
|
||||
if (activeResource) url.searchParams.set('resourceTab', activeResource);
|
||||
else url.searchParams.delete('resourceTab');
|
||||
replaceUrlState(url);
|
||||
};
|
||||
|
||||
const activateMainEditorTab = (objectIdentity) => {
|
||||
const nodes = resourceTabHostNodes();
|
||||
const activeResource = String(objectIdentity || '').trim();
|
||||
@@ -3279,6 +3354,8 @@ pub(crate) fn render_editor_island_adapter_script() -> &'static str {
|
||||
if (entry.panel instanceof HTMLElement) entry.panel.hidden = !active;
|
||||
syncResourceTabCloseGuard(entry);
|
||||
});
|
||||
syncActiveResourceFileTreeRow(activeResource);
|
||||
syncActiveResourceUrlState(activeResource);
|
||||
};
|
||||
|
||||
const bindMainEditorPageTab = () => {
|
||||
@@ -3300,6 +3377,7 @@ pub(crate) fn render_editor_island_adapter_script() -> &'static str {
|
||||
if (guardReason) {
|
||||
console.warn(`mnote resource tab 关闭阻止: ${entry.title} (${guardReason})`);
|
||||
syncResourceTabCloseGuard(entry);
|
||||
showResourceTabCloseGuardNotice(entry, guardReason);
|
||||
return;
|
||||
}
|
||||
removeFromResourceTabMru(key);
|
||||
@@ -3358,7 +3436,17 @@ pub(crate) fn render_editor_island_adapter_script() -> &'static str {
|
||||
panel.hidden = true;
|
||||
nodes.strip.append(tab);
|
||||
nodes.panelRoot.append(panel);
|
||||
return { objectIdentity, title, kind, tab, panel, view: null, session: null };
|
||||
return {
|
||||
objectIdentity,
|
||||
title,
|
||||
kind,
|
||||
tab,
|
||||
panel,
|
||||
view: null,
|
||||
session: null,
|
||||
assetId: String(input.assetId || '').trim(),
|
||||
path: String(input.path || '').trim(),
|
||||
};
|
||||
};
|
||||
|
||||
const localResourceReadUrl = (rootUri, path) => {
|
||||
|
||||
Reference in New Issue
Block a user