20260513 mindmap优化01
This commit is contained in:
@@ -962,6 +962,25 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
return '';
|
||||
}
|
||||
|
||||
function fileObjectIdentity(item) {
|
||||
var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
|
||||
if (meta.objectIdentity && typeof meta.objectIdentity === 'object') return meta.objectIdentity;
|
||||
var rowKind = String(item && item.rowKind || '');
|
||||
var documentId = fileDocumentId(item) || null;
|
||||
var assetId = fileAssetId(item) || null;
|
||||
var iconKind = iconKindOf(item);
|
||||
var objectKind = rowKind === 'document' ? 'page' : rowKind === 'index' ? 'index' : iconKind === 'mindmap' ? 'mindmap' : 'attachment';
|
||||
return { objectKind: objectKind, documentId: documentId, blockId: null, assetId: assetId };
|
||||
}
|
||||
|
||||
function objectIdentityAttr(identity) {
|
||||
try {
|
||||
return JSON.stringify(identity || {});
|
||||
} catch (_error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function iconKindOf(item) {
|
||||
return String(item && (item.iconHint || item.rowKind || 'file') || 'file').trim() || 'file';
|
||||
}
|
||||
@@ -976,6 +995,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
var parent = parentIdOf(item);
|
||||
var documentId = fileDocumentId(item);
|
||||
var assetId = fileAssetId(item);
|
||||
var objectIdentity = fileObjectIdentity(item);
|
||||
var children = grouped.get(nodeId) || [];
|
||||
var expandable = Boolean(item.expandable || item.childCount > 0 || children.length);
|
||||
var expanded = expandable && item.expandedByDefault !== false;
|
||||
@@ -990,7 +1010,7 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
var childHtml = expandable
|
||||
? '<ul class="tree-children' + (expanded ? '' : ' tree-children--collapsed') + '">' + renderFileRows(nodeId, grouped, activeId) + '</ul>'
|
||||
: '';
|
||||
return '<li class="tree-node" data-node-id="' + escapeHtml(nodeId) + '"><div class="tree-row" role="treeitem" aria-level="' + (depth + 1) + '" aria-expanded="' + String(expandable && expanded) + '" data-rust-rendered-row="filetree" data-testid="' + testId + '" data-row-id="' + escapeHtml(rowId) + '" data-row-kind="' + escapeHtml(rowKind) + '" data-node-id="' + escapeHtml(nodeId) + '"' + (parent ? ' data-parent-id="' + escapeHtml(parent) + '"' : '') + ' data-document-id="' + escapeHtml(documentId) + '" data-doc-id="' + escapeHtml(documentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-shell-mode="filetree" data-selected="' + String(selected) + '" data-active="false" draggable="true">' + toggle + '<span class="tree-kind-badge" data-kind="' + escapeHtml(iconKindOf(item)) + '" aria-hidden="true"></span><button type="button" class="tree-link" data-rust-action="open" data-row-id="' + escapeHtml(rowId) + '" data-document-id="' + escapeHtml(documentId) + '" data-asset-id="' + escapeHtml(assetId) + '"><span class="tree-link-title">' + escapeHtml(title) + '</span></button><div class="tree-actions">' + createAction + '<button type="button" class="tree-action" data-testid="filetree-action-menu" data-rust-action="menu" data-row-id="' + escapeHtml(rowId) + '" aria-label="更多操作">…</button></div></div>' + childHtml + '</li>';
|
||||
return '<li class="tree-node" data-node-id="' + escapeHtml(nodeId) + '"><div class="tree-row" role="treeitem" aria-level="' + (depth + 1) + '" aria-expanded="' + String(expandable && expanded) + '" data-rust-rendered-row="filetree" data-testid="' + testId + '" data-row-id="' + escapeHtml(rowId) + '" data-row-kind="' + escapeHtml(rowKind) + '" data-node-id="' + escapeHtml(nodeId) + '"' + (parent ? ' data-parent-id="' + escapeHtml(parent) + '"' : '') + ' data-document-id="' + escapeHtml(documentId) + '" data-doc-id="' + escapeHtml(documentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-object-identity="' + escapeHtml(objectIdentityAttr(objectIdentity)) + '" data-object-kind="' + escapeHtml(String(objectIdentity.objectKind || '')) + '" data-shell-mode="filetree" data-selected="' + String(selected) + '" data-active="false" draggable="true">' + toggle + '<span class="tree-kind-badge" data-kind="' + escapeHtml(iconKindOf(item)) + '" aria-hidden="true"></span><button type="button" class="tree-link" data-rust-action="open" data-row-id="' + escapeHtml(rowId) + '" data-document-id="' + escapeHtml(documentId) + '" data-asset-id="' + escapeHtml(assetId) + '"><span class="tree-link-title">' + escapeHtml(title) + '</span></button><div class="tree-actions">' + createAction + '<button type="button" class="tree-action" data-testid="filetree-action-menu" data-rust-action="menu" data-row-id="' + escapeHtml(rowId) + '" aria-label="更多操作">…</button></div></div>' + childHtml + '</li>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
@@ -1066,11 +1086,10 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
if (['doc', 'docx', 'odt', 'rtf'].indexOf(ext) >= 0) return ext;
|
||||
if (['ppt', 'pptx', 'odp'].indexOf(ext) >= 0) return ext;
|
||||
if (['xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return ext;
|
||||
if (ext === 'pdf') return ext;
|
||||
if (isNonOfficeAttachmentName(name, ext)) return '';
|
||||
if (mt.indexOf('wordprocessingml') >= 0) return 'docx';
|
||||
if (mt.indexOf('presentationml') >= 0) return 'pptx';
|
||||
if (mt.indexOf('spreadsheetml') >= 0) return 'xlsx';
|
||||
if (mt.indexOf('pdf') >= 0) return 'pdf';
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -1098,6 +1117,32 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
return '/onlyoffice?' + params.toString();
|
||||
}
|
||||
|
||||
function buildMindmapOpenPath(documentId, assetId) {
|
||||
var doc = String(documentId || '').trim();
|
||||
var map = String(assetId || '').trim();
|
||||
if (!doc || !map) return '';
|
||||
return '/mindmap/' + encodeURIComponent(doc) + '/' + encodeURIComponent(map);
|
||||
}
|
||||
|
||||
function isMindmapAssetDetail(detail) {
|
||||
var assetId = String(detail && detail.assetId || '').trim();
|
||||
var assetType = String(detail && detail.assetType || '').trim();
|
||||
if (assetType === 'mindmap') return true;
|
||||
return assetId.indexOf('mindmap_') === 0 || assetId.indexOf('mindmap-') === 0;
|
||||
}
|
||||
|
||||
function readFileTreeObjectIdentity(row) {
|
||||
if (!row) return null;
|
||||
var raw = row.getAttribute('data-object-identity') || '';
|
||||
if (!raw) return null;
|
||||
try {
|
||||
var parsed = JSON.parse(raw);
|
||||
return parsed && typeof parsed === 'object' ? parsed : null;
|
||||
} catch (_error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchCurrentOnlyOfficeUserId() {
|
||||
try {
|
||||
var response = await fetch('/api/auth/whoami', {
|
||||
@@ -1115,6 +1160,16 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
async function openConvexAssetFromFileTree(detail) {
|
||||
var assetId = String(detail && detail.assetId || '').trim();
|
||||
if (!assetId) return;
|
||||
var documentId = String(detail && detail.documentId || '').trim();
|
||||
if (isMindmapAssetDetail(detail) && documentId) {
|
||||
var mindmapPath = buildMindmapOpenPath(documentId, assetId);
|
||||
if (mindmapPath) {
|
||||
document.documentElement.setAttribute('data-mnote-last-mindmap-asset-open-mode', 'mindmap-object-shell');
|
||||
document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', assetId);
|
||||
window.location.assign(mindmapPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var response = await fetch('/api/media/sign?assetId=' + encodeURIComponent(assetId), {
|
||||
method: 'GET',
|
||||
@@ -1142,6 +1197,17 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}), '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
if (isCodeAttachmentFileName(fileName) && String(asset.document_id || detail.documentId || '').trim() === currentDocumentId()) {
|
||||
await openCodeEditorAttachment({
|
||||
href: fileUrl,
|
||||
fileUrl: fileUrl,
|
||||
fileName: fileName,
|
||||
assetId: assetId,
|
||||
documentId: String(asset.document_id || detail.documentId || '').trim(),
|
||||
fileSize: uploadedFileSize(asset)
|
||||
});
|
||||
return;
|
||||
}
|
||||
window.open(fileUrl, '_blank', 'noopener,noreferrer');
|
||||
} catch (error) {
|
||||
window.alert(error && error.message ? error.message : '打开附件失败');
|
||||
@@ -1243,6 +1309,67 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
return match ? match[1] : '';
|
||||
}
|
||||
|
||||
function isNonOfficeAttachmentName(name, ext) {
|
||||
var codeFileNames = [
|
||||
'.dockerignore', '.editorconfig', '.env', '.eslintrc', '.gitattributes', '.gitignore', '.npmrc', '.prettierrc',
|
||||
'dockerfile', 'makefile', 'cmakelists.txt', 'gemfile', 'rakefile', 'procfile'
|
||||
];
|
||||
return [
|
||||
'pdf', 'toml', 'json', 'yaml', 'yml', 'md', 'markdown', 'txt', 'ini', 'env', 'xml', 'html', 'htm', 'css', 'scss',
|
||||
'less', 'js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'py', 'rs', 'go', 'java', 'c', 'cpp', 'h', 'hpp', 'cs',
|
||||
'php', 'rb', 'sh', 'bash', 'zsh', 'sql', 'lock', 'log', 'vue', 'svelte', 'astro', 'jsonc', 'json5',
|
||||
'mts', 'cts', 'lua', 'dart', 'kt', 'kts', 'swift', 'scala', 'gradle', 'groovy', 'clj',
|
||||
'ex', 'exs', 'erl', 'hrl', 'fs', 'fsx', 'r', 'jl', 'm', 'mm', 'pl', 'pm', 'ps1', 'bat', 'cmd',
|
||||
'psm1', 'psd1', 'dockerfile', 'containerfile', 'proto', 'graphql', 'gql', 'prisma', 'tf', 'tfvars',
|
||||
'hcl', 'nix', 'cmake', 'bazel', 'bzl', 'properties', 'conf', 'cfg', 'config', 'service', 'desktop',
|
||||
'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'prettierrc', 'eslintrc'
|
||||
].indexOf(ext) >= 0 || codeFileNames.indexOf(name) >= 0;
|
||||
}
|
||||
|
||||
function attachmentExtensionFromFileName(fileName) {
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
return name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||||
}
|
||||
|
||||
function isPdfAttachmentFileName(fileName) {
|
||||
return attachmentExtensionFromFileName(fileName) === 'pdf';
|
||||
}
|
||||
|
||||
function isCodeAttachmentFileName(fileName) {
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
var ext = attachmentExtensionFromFileName(name);
|
||||
return ext !== 'pdf' && isNonOfficeAttachmentName(name, ext);
|
||||
}
|
||||
|
||||
function inferCodeAttachmentLanguage(fileName) {
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
var ext = attachmentExtensionFromFileName(name);
|
||||
var byName = {
|
||||
'dockerfile': 'dockerfile',
|
||||
'makefile': 'makefile',
|
||||
'cmakelists.txt': 'cmake',
|
||||
'.gitignore': 'gitignore',
|
||||
'.gitattributes': 'gitattributes',
|
||||
'.editorconfig': 'ini',
|
||||
'.env': 'dotenv'
|
||||
};
|
||||
if (byName[name]) return byName[name];
|
||||
var byExt = {
|
||||
bash: 'bash', bat: 'batch', c: 'c', cjs: 'javascript', cmd: 'batch', conf: 'text', cpp: 'cpp',
|
||||
cs: 'csharp', css: 'css', cts: 'typescript', dart: 'dart', dockerfile: 'dockerfile', env: 'dotenv',
|
||||
go: 'go', gql: 'graphql', gradle: 'groovy', graphql: 'graphql', h: 'c', hcl: 'hcl', hpp: 'cpp',
|
||||
htm: 'html', html: 'html', ini: 'ini', java: 'java', js: 'javascript', json: 'json', json5: 'json',
|
||||
jsonc: 'jsonc', jsx: 'javascript', kt: 'kotlin', kts: 'kotlin', less: 'less', log: 'text',
|
||||
lua: 'lua', m: 'objective-c', markdown: 'markdown', md: 'markdown', mjs: 'javascript',
|
||||
mts: 'typescript', nix: 'nix', php: 'php', pl: 'perl', pm: 'perl', prisma: 'prisma',
|
||||
proto: 'protobuf', ps1: 'powershell', py: 'python', r: 'r', rb: 'ruby', rs: 'rust',
|
||||
scss: 'scss', sh: 'bash', sql: 'sql', svelte: 'svelte', swift: 'swift', tf: 'terraform',
|
||||
tfvars: 'terraform', toml: 'toml', ts: 'typescript', tsx: 'typescript', txt: 'text',
|
||||
vue: 'vue', xml: 'xml', yaml: 'yaml', yml: 'yaml', zsh: 'bash'
|
||||
};
|
||||
return byExt[ext] || 'text';
|
||||
}
|
||||
|
||||
function attachmentClassForFileName(fileName) {
|
||||
var name = String(fileName || '').trim().toLowerCase();
|
||||
var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : '';
|
||||
@@ -1250,6 +1377,9 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
if (['ppt', 'pptx', 'odp'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-ppt';
|
||||
if (['xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-sheet';
|
||||
if (ext === 'pdf') return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-pdf';
|
||||
if (isNonOfficeAttachmentName(name, ext)) {
|
||||
return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-code';
|
||||
}
|
||||
return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-file';
|
||||
}
|
||||
|
||||
@@ -3050,9 +3180,99 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
|
||||
function openEditorAttachmentDetail(detail) {
|
||||
if (!detail || !detail.href) return;
|
||||
if (isPdfAttachmentFileName(detail.fileName)) {
|
||||
void openPdfEditorAttachment(detail);
|
||||
return;
|
||||
}
|
||||
if (isCodeAttachmentFileName(detail.fileName)) {
|
||||
void openCodeEditorAttachment(detail);
|
||||
return;
|
||||
}
|
||||
window.open(detail.href, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
|
||||
async function resolveEditorAttachmentUrl(detail) {
|
||||
var assetId = String(detail && detail.assetId || '').trim();
|
||||
if (assetId) {
|
||||
var response = await fetch('/api/media/sign?assetId=' + encodeURIComponent(assetId), {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
cache: 'no-store'
|
||||
});
|
||||
var payload = await response.json().catch(function() { return null; });
|
||||
if (!response.ok || !payload) {
|
||||
throw new Error(payload && payload.error ? payload.error : '生成签名链接失败');
|
||||
}
|
||||
var signedUrl = String(payload && payload.signedUrl || '').trim();
|
||||
if (!signedUrl) throw new Error('附件链接不可用');
|
||||
return {
|
||||
url: signedUrl,
|
||||
asset: payload.asset && typeof payload.asset === 'object' ? payload.asset : {}
|
||||
};
|
||||
}
|
||||
var url = String(detail && (detail.fileUrl || detail.href) || '').trim();
|
||||
if (!url) throw new Error('附件链接不可用');
|
||||
return { url: url, asset: {} };
|
||||
}
|
||||
|
||||
async function openPdfEditorAttachment(detail) {
|
||||
try {
|
||||
var resolved = await resolveEditorAttachmentUrl(detail);
|
||||
window.open(resolved.url, '_blank', 'noopener,noreferrer');
|
||||
} catch (error) {
|
||||
window.alert(error && error.message ? error.message : '打开 PDF 失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function openCodeEditorAttachment(detail) {
|
||||
var resolved = null;
|
||||
try {
|
||||
resolved = await resolveEditorAttachmentUrl(detail);
|
||||
var size = Number(resolved.asset && (resolved.asset.file_size || resolved.asset.fileSize) || 0);
|
||||
if (Number.isFinite(size) && size > 1024 * 1024) {
|
||||
window.open(resolved.url, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
var response = await fetch(resolved.url, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
cache: 'no-store'
|
||||
});
|
||||
if (!response.ok) throw new Error('读取附件内容失败');
|
||||
var text = await response.text();
|
||||
if (text.length > 1024 * 1024) {
|
||||
window.open(resolved.url, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
var editorRoot = document.querySelector('.editor-surface .ProseMirror');
|
||||
var editor = editorRoot && editorRoot.editor;
|
||||
if (!editor || !editor.chain) {
|
||||
window.open(resolved.url, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
var title = String(detail.fileName || resolved.asset.file_name || '附件').trim() || '附件';
|
||||
var language = inferCodeAttachmentLanguage(title);
|
||||
editor.chain().focus().insertContent([
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [{ type: 'text', text: title }]
|
||||
},
|
||||
{
|
||||
type: 'codeBlock',
|
||||
attrs: { language: language },
|
||||
content: text ? [{ type: 'text', text: text.replace(/\r\n?/g, '\n') }] : []
|
||||
}
|
||||
]).run();
|
||||
} catch (error) {
|
||||
console.warn('[mnote attachment] open code attachment failed', error);
|
||||
if (resolved && resolved.url) {
|
||||
window.open(resolved.url, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
window.alert(error && error.message ? error.message : '打开代码附件失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function openEditorAttachmentDownload(detail) {
|
||||
if (!detail) return;
|
||||
if (detail.assetId) {
|
||||
@@ -3330,6 +3550,11 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
var rowKind = fileRow.getAttribute('data-row-kind') || '';
|
||||
var documentId = fileRow.getAttribute('data-document-id') || fileRow.getAttribute('data-doc-id') || '';
|
||||
var assetId = fileRow.getAttribute('data-asset-id') || '';
|
||||
var assetType = '';
|
||||
var kindBadge = fileRow.querySelector('.tree-kind-badge');
|
||||
if (kindBadge instanceof HTMLElement) {
|
||||
assetType = kindBadge.getAttribute('data-kind') || '';
|
||||
}
|
||||
if (fileAction === 'toggle') {
|
||||
e.preventDefault();
|
||||
toggleChildren(fileRow, fileBtn);
|
||||
@@ -3356,14 +3581,15 @@ const SIDEBAR_TREE_JS: &str = r##"
|
||||
}
|
||||
e.preventDefault();
|
||||
selectSidebarFileTreeRow(fileRow, { ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey });
|
||||
dispatchSidebarEvent('tree.filetree.open', { rowId: rowId, rowKind: rowKind, documentId: documentId || null, assetId: assetId || null });
|
||||
var objectIdentity = readFileTreeObjectIdentity(fileRow);
|
||||
dispatchSidebarEvent('tree.filetree.open', { rowId: rowId, rowKind: rowKind, documentId: documentId || null, assetId: assetId || null, assetType: assetType || null, objectIdentity: objectIdentity, workspaceId: resolveWorkspaceId(fileRow) });
|
||||
if (e.shiftKey || e.ctrlKey || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
if ((rowKind === 'document' || rowKind === 'index' || rowKind === 'markdown') && documentId) {
|
||||
navigateToDocument(documentId, resolveWorkspaceId(fileRow), { treeView: 'filetree' });
|
||||
} else if (assetId) {
|
||||
dispatchSidebarEvent('tree.asset.open', { rowId: rowId, rowKind: rowKind, documentId: documentId || null, assetId: assetId });
|
||||
dispatchSidebarEvent('tree.asset.open', { rowId: rowId, rowKind: rowKind, documentId: documentId || null, assetId: assetId, assetType: assetType || null, objectIdentity: objectIdentity, workspaceId: resolveWorkspaceId(fileRow) });
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3988,6 +4214,17 @@ mod tests {
|
||||
assert!(SIDEBAR_TREE_JS.contains("tree.filetree.open"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("tree.asset.open"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("openConvexAssetFromFileTree"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("buildMindmapOpenPath"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("isMindmapAssetDetail"));
|
||||
assert!(!SIDEBAR_TREE_JS.contains("openMindmapAssetInDocumentShell"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("data-mnote-last-mindmap-asset-open-mode"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("mindmap-object-shell"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("window.location.assign(mindmapPath)"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("assetType: assetType || null"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("data-object-identity"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("readFileTreeObjectIdentity"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("objectIdentity: objectIdentity"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("workspaceId: resolveWorkspaceId(fileRow)"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("/api/media/sign?assetId="));
|
||||
assert!(SIDEBAR_TREE_JS.contains("fetchCurrentOnlyOfficeUserId"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("/api/auth/whoami"));
|
||||
@@ -4031,6 +4268,40 @@ mod tests {
|
||||
assert!(SIDEBAR_TREE_JS.contains("/api/tree/projections/file"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sidebar_tree_runtime_keeps_pdf_and_code_assets_out_of_onlyoffice() {
|
||||
assert!(SIDEBAR_TREE_JS.contains("function inferOnlyOfficeFileType"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("isNonOfficeAttachmentName(name, ext)"));
|
||||
assert!(!SIDEBAR_TREE_JS.contains("if (ext === 'pdf') return ext;"));
|
||||
assert!(!SIDEBAR_TREE_JS.contains("mt.indexOf('pdf') >= 0"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("mnote-uploaded-attachment-pdf"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("mnote-uploaded-attachment-code"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'toml'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'json'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'yaml'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'md'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'vue'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'svelte'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'proto'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'dockerfile'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("'.gitignore'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sidebar_tree_runtime_opens_pdf_and_code_assets_with_builtin_tools() {
|
||||
assert!(SIDEBAR_TREE_JS.contains("function openPdfEditorAttachment"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("function openCodeEditorAttachment"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("function resolveEditorAttachmentUrl"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("type: 'codeBlock'"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("attrs: { language: language }"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("inferCodeAttachmentLanguage"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("if (isPdfAttachmentFileName(detail.fileName))"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("if (isCodeAttachmentFileName(detail.fileName))"));
|
||||
assert!(SIDEBAR_TREE_JS
|
||||
.contains("if (isCodeAttachmentFileName(fileName) && String(asset.document_id"));
|
||||
assert!(SIDEBAR_TREE_JS.contains("await openCodeEditorAttachment({"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tree_live_controller_marks_transport_and_closes_source_on_pagehide() {
|
||||
assert!(TREE_LIVE_CONTROLLER_JS.contains("convex-command-log-sse"));
|
||||
|
||||
@@ -18,17 +18,37 @@ pub fn MindmapPage(
|
||||
document_id: String,
|
||||
/// 思维导图 ID
|
||||
mindmap_id: String,
|
||||
/// 页面标题
|
||||
title: String,
|
||||
/// 侧栏页面树 HTML
|
||||
#[prop(optional)]
|
||||
sidebar_tree_html: Option<String>,
|
||||
/// 工作区名称
|
||||
#[prop(optional)]
|
||||
workspace_name: Option<String>,
|
||||
/// workspace shell 侧栏 sections HTML
|
||||
#[prop(optional)]
|
||||
workspace_sidebar_html: Option<String>,
|
||||
) -> impl IntoView {
|
||||
let object_identity = format!("resource:mindmap:{document_id}:{mindmap_id}");
|
||||
view! {
|
||||
<PageLayout current_nav="documents">
|
||||
<PageLayout
|
||||
current_nav="documents"
|
||||
sidebar_tree_html={sidebar_tree_html.unwrap_or_default()}
|
||||
workspace_name={workspace_name.unwrap_or_default()}
|
||||
workspace_sidebar_html={workspace_sidebar_html.unwrap_or_default()}
|
||||
topbar_title={title.clone()}
|
||||
>
|
||||
<main
|
||||
id="mnote-mindmap-shell"
|
||||
data-object-shell="mindmap"
|
||||
data-mnote-object-editor="mindmap"
|
||||
data-mnote-object-identity={object_identity}
|
||||
data-document-id={document_id}
|
||||
data-mindmap-id={mindmap_id}
|
||||
>
|
||||
<header>
|
||||
<h1>{"思维导图"}</h1>
|
||||
<h1>{title}</h1>
|
||||
</header>
|
||||
<section
|
||||
id="mnote-mindmap-island"
|
||||
|
||||
Reference in New Issue
Block a user