refactor: split sidebar filetree upload runtime
This commit is contained in:
+1
-1
@@ -167,7 +167,7 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web --lib routes::web_shell
|
|||||||
- [ ] C2. `sidebar-page-tree-runtime.js`:page tree row selection、rename title patch、breadcrumb/title sync。
|
- [ ] C2. `sidebar-page-tree-runtime.js`:page tree row selection、rename title patch、breadcrumb/title sync。
|
||||||
- [x] C3. `sidebar-filetree-open-runtime.js`:local markdown / resource open target、active resource tab dispatch。
|
- [x] C3. `sidebar-filetree-open-runtime.js`:local markdown / resource open target、active resource tab dispatch。
|
||||||
- [x] C4. `sidebar-filetree-command-runtime.js`:create/rename/delete/copy/move/trash/restore/purge command payload。
|
- [x] C4. `sidebar-filetree-command-runtime.js`:create/rename/delete/copy/move/trash/restore/purge command payload。
|
||||||
- [ ] C5. `sidebar-filetree-upload-runtime.js`:local upload target plan、drop/paste preflight、readonly guard。
|
- [x] C5. `sidebar-filetree-upload-runtime.js`:local upload target plan、drop/paste preflight、readonly guard。
|
||||||
- [x] C6. `sidebar-attachment-open-runtime.js`:OnlyOffice/PDF/code/image open mode guard。
|
- [x] C6. `sidebar-attachment-open-runtime.js`:OnlyOffice/PDF/code/image open mode guard。
|
||||||
- [x] C7. `sidebar-tree-live-apply-runtime.js`:WS/SSE snapshot/delta/resync DOM apply。
|
- [x] C7. `sidebar-tree-live-apply-runtime.js`:WS/SSE snapshot/delta/resync DOM apply。
|
||||||
- [ ] C8. `sidebar-tree-runtime.js` 保留为 entrypoint,目标少于 3,000 行。
|
- [ ] C8. `sidebar-tree-runtime.js` 保留为 entrypoint,目标少于 3,000 行。
|
||||||
|
|||||||
@@ -0,0 +1,288 @@
|
|||||||
|
export const createSidebarFileTreeUploadRuntime = (dependencies = {}) => {
|
||||||
|
const {
|
||||||
|
cssEscape,
|
||||||
|
currentDocumentId,
|
||||||
|
fileTreeRuntimeDeps,
|
||||||
|
fileTreeRuntimeFunction,
|
||||||
|
recordFileTreeAction,
|
||||||
|
recordFileTreeActionStatus,
|
||||||
|
resolveWorkspaceId,
|
||||||
|
rowTitle,
|
||||||
|
selectedSidebarFileTreeSelection,
|
||||||
|
} = dependencies;
|
||||||
|
const sidebarFileTreeSelection = selectedSidebarFileTreeSelection;
|
||||||
|
|
||||||
|
function fileTreeRowsForUploadPreflight() {
|
||||||
|
var runtimeFn = fileTreeRuntimeFunction('fileTreeRowsForUploadPreflight');
|
||||||
|
if (runtimeFn) return runtimeFn(fileTreeRuntimeDeps());
|
||||||
|
return Array.from(document.querySelectorAll('.tree-row[data-shell-mode="filetree"]')).map(function(row) {
|
||||||
|
return {
|
||||||
|
rowId: row.getAttribute('data-row-id') || '',
|
||||||
|
rowKind: row.getAttribute('data-row-kind') || '',
|
||||||
|
documentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null,
|
||||||
|
assetId: row.getAttribute('data-asset-id') || null,
|
||||||
|
assetDocumentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null,
|
||||||
|
assetType: row.querySelector('.tree-kind-badge') ? row.querySelector('.tree-kind-badge').getAttribute('data-kind') : null,
|
||||||
|
storagePath: null
|
||||||
|
};
|
||||||
|
}).filter(function(row) {
|
||||||
|
return row.rowId || row.documentId || row.assetId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileTreeRowCapabilities(row) {
|
||||||
|
if (!(row instanceof HTMLElement)) return [];
|
||||||
|
try {
|
||||||
|
var parsed = JSON.parse(row.getAttribute('data-capabilities') || '[]');
|
||||||
|
return Array.isArray(parsed) ? parsed.map(function(item) { return String(item || '').trim(); }).filter(Boolean) : [];
|
||||||
|
} catch (_) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileTreeRowIsReadonly(row) {
|
||||||
|
return fileTreeRowCapabilities(row).some(function(capability) {
|
||||||
|
return ['readonly', 'readOnly', 'permissionDenied'].indexOf(capability) >= 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function blockReadonlyFileTreeAction(action, detail, message) {
|
||||||
|
var normalizedAction = String(action || 'drop').trim() || 'drop';
|
||||||
|
var text = String(message || '目标位置是只读,不能拖放到这里').trim();
|
||||||
|
var targetRowId = String(detail && (detail.targetRowId || detail.rowId) || '').trim();
|
||||||
|
var documentId = String(detail && detail.documentId || '').trim();
|
||||||
|
var assetId = String(detail && detail.assetId || '').trim();
|
||||||
|
recordFileTreeAction(normalizedAction, {
|
||||||
|
rowId: targetRowId,
|
||||||
|
documentId: documentId,
|
||||||
|
assetId: assetId,
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
recordFileTreeActionStatus('blocked', {
|
||||||
|
rowId: targetRowId,
|
||||||
|
documentId: documentId,
|
||||||
|
assetId: assetId,
|
||||||
|
readonly: true,
|
||||||
|
fallback: 'alert'
|
||||||
|
});
|
||||||
|
document.documentElement.setAttribute('data-mnote-filetree-readonly-blocked', normalizedAction);
|
||||||
|
document.documentElement.setAttribute('data-mnote-filetree-readonly-message', text);
|
||||||
|
if (targetRowId) {
|
||||||
|
document.documentElement.setAttribute('data-mnote-filetree-readonly-target-row-id', targetRowId);
|
||||||
|
var row = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(targetRowId) + '"]');
|
||||||
|
if (row instanceof HTMLElement) {
|
||||||
|
row.setAttribute('data-readonly-blocked', normalizedAction);
|
||||||
|
row.setAttribute('data-readonly-message', text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.alert(text);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileTreeDocumentParentsForPreflight() {
|
||||||
|
var runtimeFn = fileTreeRuntimeFunction('fileTreeDocumentParentsForPreflight');
|
||||||
|
if (runtimeFn) return runtimeFn(fileTreeRuntimeDeps());
|
||||||
|
return Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]')).map(function(row) {
|
||||||
|
var documentId = row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '';
|
||||||
|
if (!documentId) return null;
|
||||||
|
var parentRowId = row.getAttribute('data-parent-id') || '';
|
||||||
|
var parentDocumentId = parentRowId.indexOf('doc:') === 0 ? parentRowId.slice(4) : parentRowId || null;
|
||||||
|
return { documentId: documentId, parentId: parentDocumentId };
|
||||||
|
}).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileTreeTargetChildrenForPreflight(targetRow) {
|
||||||
|
var runtimeFn = fileTreeRuntimeFunction('fileTreeTargetChildrenForPreflight');
|
||||||
|
if (runtimeFn) return runtimeFn(targetRow, fileTreeRuntimeDeps());
|
||||||
|
var node = targetRow instanceof HTMLElement ? targetRow.closest('.tree-node') : null;
|
||||||
|
if (!node) return [];
|
||||||
|
return Array.from(node.querySelectorAll(':scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"]')).map(function(row) {
|
||||||
|
return {
|
||||||
|
rowKind: row.getAttribute('data-row-kind') || '',
|
||||||
|
documentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null,
|
||||||
|
assetId: row.getAttribute('data-asset-id') || null,
|
||||||
|
title: rowTitle(row)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileTreeDropPreflightRows() {
|
||||||
|
var runtimeFn = fileTreeRuntimeFunction('fileTreeDropPreflightRows');
|
||||||
|
if (runtimeFn) return runtimeFn(Object.assign({}, fileTreeRuntimeDeps(), {
|
||||||
|
fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight
|
||||||
|
}));
|
||||||
|
return fileTreeRowsForUploadPreflight().map(function(row) {
|
||||||
|
var domRow = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(row.rowId) + '"]');
|
||||||
|
row.title = rowTitle(domRow);
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureFileTreeWritableTarget(action, targetRow, rowIds, copy) {
|
||||||
|
var normalizedAction = String(action || 'drop').trim() || 'drop';
|
||||||
|
if (!(targetRow instanceof HTMLElement)) return true;
|
||||||
|
var detail = {
|
||||||
|
targetRowId: targetRow.getAttribute('data-row-id') || '',
|
||||||
|
rowId: targetRow.getAttribute('data-row-id') || '',
|
||||||
|
documentId: targetRow.getAttribute('data-document-id') || targetRow.getAttribute('data-doc-id') || '',
|
||||||
|
assetId: targetRow.getAttribute('data-asset-id') || ''
|
||||||
|
};
|
||||||
|
if (fileTreeRowIsReadonly(targetRow)) {
|
||||||
|
return blockReadonlyFileTreeAction(normalizedAction, detail, '目标位置是只读,不能拖放到这里');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var response = await fetch('/api/tree/filetree/drop-preflight', {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
workspaceId: resolveWorkspaceId(targetRow),
|
||||||
|
copy: Boolean(copy),
|
||||||
|
sourceCapabilities: ['read', 'write', 'move'],
|
||||||
|
targetCapabilities: fileTreeRowCapabilities(targetRow),
|
||||||
|
targetDocumentId: detail.documentId || null,
|
||||||
|
targetRowId: detail.targetRowId || null,
|
||||||
|
focusedRowId: sidebarFileTreeSelection.focusedRowId || null,
|
||||||
|
activeDocumentId: currentDocumentId() || null,
|
||||||
|
rowIds: Array.isArray(rowIds) ? rowIds : [],
|
||||||
|
rows: fileTreeDropPreflightRows(),
|
||||||
|
targetChildren: fileTreeTargetChildrenForPreflight(targetRow),
|
||||||
|
documentParents: fileTreeDocumentParentsForPreflight()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (response.ok) return true;
|
||||||
|
var payload = await response.json().catch(function() { return null; });
|
||||||
|
var message = payload && (payload.error || payload.message) ? String(payload.error || payload.message) : '目标位置是只读,不能拖放到这里';
|
||||||
|
if (message.indexOf('只读') >= 0 || message.toLowerCase().indexOf('readonly') >= 0) {
|
||||||
|
return blockReadonlyFileTreeAction(normalizedAction, detail, message);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileTreeDocumentWorkspacesForUploadPreflight(workspaceId) {
|
||||||
|
var runtimeFn = fileTreeRuntimeFunction('fileTreeDocumentWorkspacesForUploadPreflight');
|
||||||
|
if (runtimeFn) {
|
||||||
|
return runtimeFn(workspaceId, Object.assign({}, fileTreeRuntimeDeps(), {
|
||||||
|
fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
var seen = new Set();
|
||||||
|
return fileTreeRowsForUploadPreflight().filter(function(row) {
|
||||||
|
if (!row.documentId || seen.has(row.documentId)) return false;
|
||||||
|
seen.add(row.documentId);
|
||||||
|
return true;
|
||||||
|
}).map(function(row) {
|
||||||
|
return { documentId: row.documentId, workspaceId: workspaceId || null };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function preflightFileTreeUploadTarget(detail) {
|
||||||
|
var bodyRuntime = fileTreeRuntimeFunction('fileTreeUploadTargetPreflightBody');
|
||||||
|
var body = bodyRuntime ? bodyRuntime(detail || {}, Object.assign({}, fileTreeRuntimeDeps(), {
|
||||||
|
focusedRowId: sidebarFileTreeSelection.focusedRowId || null,
|
||||||
|
fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight,
|
||||||
|
currentDocumentId: currentDocumentId,
|
||||||
|
resolveWorkspaceId: resolveWorkspaceId
|
||||||
|
})) : (function() {
|
||||||
|
var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim();
|
||||||
|
return {
|
||||||
|
workspaceId: workspaceId || null,
|
||||||
|
targetDocumentId: detail && detail.documentId ? String(detail.documentId) : null,
|
||||||
|
targetRowId: detail && detail.targetRowId ? String(detail.targetRowId) : null,
|
||||||
|
focusedRowId: sidebarFileTreeSelection.focusedRowId || null,
|
||||||
|
activeDocumentId: currentDocumentId() || null,
|
||||||
|
rows: fileTreeRowsForUploadPreflight(),
|
||||||
|
documentWorkspaces: fileTreeDocumentWorkspacesForUploadPreflight(workspaceId)
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
var response = await fetch('/api/tree/filetree/upload-target-preflight', {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
});
|
||||||
|
var payload = await response.json().catch(function() { return null; });
|
||||||
|
if (!response.ok || !payload || !payload.plan) {
|
||||||
|
throw new Error(payload && payload.error ? payload.error : '文件树上传目标预检失败');
|
||||||
|
}
|
||||||
|
return payload.plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fallbackFileTreeUploadTarget(detail) {
|
||||||
|
var runtimeFn = fileTreeRuntimeFunction('fileTreeUploadTargetFallback');
|
||||||
|
if (runtimeFn) {
|
||||||
|
return runtimeFn(detail || {}, {
|
||||||
|
resolveWorkspaceId: resolveWorkspaceId,
|
||||||
|
currentDocumentId: currentDocumentId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim();
|
||||||
|
var documentId = String(detail && detail.documentId || currentDocumentId() || '').trim();
|
||||||
|
if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
||||||
|
return {
|
||||||
|
workspaceId: workspaceId,
|
||||||
|
targetDocumentId: documentId,
|
||||||
|
targetMindmapId: null,
|
||||||
|
targetSubPath: null,
|
||||||
|
targetRelativePath: String(detail.targetRelativePath || ''),
|
||||||
|
uploadIntent: String(detail.uploadIntent || 'filetree.folder.drop')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!workspaceId || !documentId) {
|
||||||
|
throw new Error('请选择一个目标页面后再拖入文件');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
workspaceId: workspaceId,
|
||||||
|
targetDocumentId: documentId,
|
||||||
|
targetMindmapId: null,
|
||||||
|
targetSubPath: null,
|
||||||
|
uploadIntent: String(detail && detail.uploadIntent || 'editor.markdown.attach')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveFileTreeUploadTarget(detail) {
|
||||||
|
if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
||||||
|
return fallbackFileTreeUploadTarget(detail || {});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var plan = await preflightFileTreeUploadTarget(detail || {});
|
||||||
|
var normalizePlanRuntime = fileTreeRuntimeFunction('normalizeFileTreeUploadTargetPlan');
|
||||||
|
if (normalizePlanRuntime) {
|
||||||
|
return normalizePlanRuntime(detail || {}, plan);
|
||||||
|
}
|
||||||
|
if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
||||||
|
plan.targetRelativePath = String(detail.targetRelativePath || '');
|
||||||
|
}
|
||||||
|
if (detail && detail.uploadIntent) {
|
||||||
|
plan.uploadIntent = String(detail.uploadIntent);
|
||||||
|
} else if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
||||||
|
plan.uploadIntent = 'filetree.folder.drop';
|
||||||
|
} else if (!plan.uploadIntent) {
|
||||||
|
plan.uploadIntent = 'editor.markdown.attach';
|
||||||
|
}
|
||||||
|
return plan;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('[mnote upload] upload target preflight fallback', error);
|
||||||
|
return fallbackFileTreeUploadTarget(detail || {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
fileTreeRowsForUploadPreflight,
|
||||||
|
fileTreeRowCapabilities,
|
||||||
|
fileTreeRowIsReadonly,
|
||||||
|
blockReadonlyFileTreeAction,
|
||||||
|
fileTreeDocumentParentsForPreflight,
|
||||||
|
fileTreeTargetChildrenForPreflight,
|
||||||
|
fileTreeDropPreflightRows,
|
||||||
|
ensureFileTreeWritableTarget,
|
||||||
|
fileTreeDocumentWorkspacesForUploadPreflight,
|
||||||
|
preflightFileTreeUploadTarget,
|
||||||
|
fallbackFileTreeUploadTarget,
|
||||||
|
resolveFileTreeUploadTarget,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@ import { createSidebarTreeLiveApplyRuntime } from './sidebar-tree-live-apply-run
|
|||||||
import { createSidebarFileTreeOpenRuntime } from './sidebar-filetree-open-runtime.js';
|
import { createSidebarFileTreeOpenRuntime } from './sidebar-filetree-open-runtime.js';
|
||||||
import { createSidebarAttachmentOpenRuntime } from './sidebar-attachment-open-runtime.js';
|
import { createSidebarAttachmentOpenRuntime } from './sidebar-attachment-open-runtime.js';
|
||||||
import { createSidebarFileTreeCommandRuntime } from './sidebar-filetree-command-runtime.js';
|
import { createSidebarFileTreeCommandRuntime } from './sidebar-filetree-command-runtime.js';
|
||||||
|
import { createSidebarFileTreeUploadRuntime } from './sidebar-filetree-upload-runtime.js';
|
||||||
|
|
||||||
(function(){
|
(function(){
|
||||||
if (window.__mnoteSidebarTreeRuntimeStarted) return;
|
if (window.__mnoteSidebarTreeRuntimeStarted) return;
|
||||||
@@ -879,263 +880,19 @@ import { createSidebarFileTreeCommandRuntime } from './sidebar-filetree-command-
|
|||||||
const fetchCurrentOnlyOfficeUserId = (...args) => sidebarFileTreeOpen.fetchCurrentOnlyOfficeUserId(...args);
|
const fetchCurrentOnlyOfficeUserId = (...args) => sidebarFileTreeOpen.fetchCurrentOnlyOfficeUserId(...args);
|
||||||
const openConvexAssetFromFileTree = (...args) => sidebarFileTreeOpen.openConvexAssetFromFileTree(...args);
|
const openConvexAssetFromFileTree = (...args) => sidebarFileTreeOpen.openConvexAssetFromFileTree(...args);
|
||||||
|
|
||||||
function fileTreeRowsForUploadPreflight() {
|
var sidebarFileTreeUpload = null;
|
||||||
var runtimeFn = fileTreeRuntimeFunction('fileTreeRowsForUploadPreflight');
|
const fileTreeRowsForUploadPreflight = (...args) => sidebarFileTreeUpload.fileTreeRowsForUploadPreflight(...args);
|
||||||
if (runtimeFn) return runtimeFn(fileTreeRuntimeDeps());
|
const fileTreeRowCapabilities = (...args) => sidebarFileTreeUpload.fileTreeRowCapabilities(...args);
|
||||||
return Array.from(document.querySelectorAll('.tree-row[data-shell-mode="filetree"]')).map(function(row) {
|
const fileTreeRowIsReadonly = (...args) => sidebarFileTreeUpload.fileTreeRowIsReadonly(...args);
|
||||||
return {
|
const blockReadonlyFileTreeAction = (...args) => sidebarFileTreeUpload.blockReadonlyFileTreeAction(...args);
|
||||||
rowId: row.getAttribute('data-row-id') || '',
|
const fileTreeDocumentParentsForPreflight = (...args) => sidebarFileTreeUpload.fileTreeDocumentParentsForPreflight(...args);
|
||||||
rowKind: row.getAttribute('data-row-kind') || '',
|
const fileTreeTargetChildrenForPreflight = (...args) => sidebarFileTreeUpload.fileTreeTargetChildrenForPreflight(...args);
|
||||||
documentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null,
|
const fileTreeDropPreflightRows = (...args) => sidebarFileTreeUpload.fileTreeDropPreflightRows(...args);
|
||||||
assetId: row.getAttribute('data-asset-id') || null,
|
const ensureFileTreeWritableTarget = (...args) => sidebarFileTreeUpload.ensureFileTreeWritableTarget(...args);
|
||||||
assetDocumentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null,
|
const fileTreeDocumentWorkspacesForUploadPreflight = (...args) => sidebarFileTreeUpload.fileTreeDocumentWorkspacesForUploadPreflight(...args);
|
||||||
assetType: row.querySelector('.tree-kind-badge') ? row.querySelector('.tree-kind-badge').getAttribute('data-kind') : null,
|
const preflightFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.preflightFileTreeUploadTarget(...args);
|
||||||
storagePath: null
|
const fallbackFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.fallbackFileTreeUploadTarget(...args);
|
||||||
};
|
const resolveFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.resolveFileTreeUploadTarget(...args);
|
||||||
}).filter(function(row) {
|
|
||||||
return row.rowId || row.documentId || row.assetId;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileTreeRowCapabilities(row) {
|
|
||||||
if (!(row instanceof HTMLElement)) return [];
|
|
||||||
try {
|
|
||||||
var parsed = JSON.parse(row.getAttribute('data-capabilities') || '[]');
|
|
||||||
return Array.isArray(parsed) ? parsed.map(function(item) { return String(item || '').trim(); }).filter(Boolean) : [];
|
|
||||||
} catch (_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileTreeRowIsReadonly(row) {
|
|
||||||
return fileTreeRowCapabilities(row).some(function(capability) {
|
|
||||||
return ['readonly', 'readOnly', 'permissionDenied'].indexOf(capability) >= 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function blockReadonlyFileTreeAction(action, detail, message) {
|
|
||||||
var normalizedAction = String(action || 'drop').trim() || 'drop';
|
|
||||||
var text = String(message || '目标位置是只读,不能拖放到这里').trim();
|
|
||||||
var targetRowId = String(detail && (detail.targetRowId || detail.rowId) || '').trim();
|
|
||||||
var documentId = String(detail && detail.documentId || '').trim();
|
|
||||||
var assetId = String(detail && detail.assetId || '').trim();
|
|
||||||
recordFileTreeAction(normalizedAction, {
|
|
||||||
rowId: targetRowId,
|
|
||||||
documentId: documentId,
|
|
||||||
assetId: assetId,
|
|
||||||
readonly: true
|
|
||||||
});
|
|
||||||
recordFileTreeActionStatus('blocked', {
|
|
||||||
rowId: targetRowId,
|
|
||||||
documentId: documentId,
|
|
||||||
assetId: assetId,
|
|
||||||
readonly: true,
|
|
||||||
fallback: 'alert'
|
|
||||||
});
|
|
||||||
document.documentElement.setAttribute('data-mnote-filetree-readonly-blocked', normalizedAction);
|
|
||||||
document.documentElement.setAttribute('data-mnote-filetree-readonly-message', text);
|
|
||||||
if (targetRowId) {
|
|
||||||
document.documentElement.setAttribute('data-mnote-filetree-readonly-target-row-id', targetRowId);
|
|
||||||
var row = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(targetRowId) + '"]');
|
|
||||||
if (row instanceof HTMLElement) {
|
|
||||||
row.setAttribute('data-readonly-blocked', normalizedAction);
|
|
||||||
row.setAttribute('data-readonly-message', text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.alert(text);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileTreeDocumentParentsForPreflight() {
|
|
||||||
var runtimeFn = fileTreeRuntimeFunction('fileTreeDocumentParentsForPreflight');
|
|
||||||
if (runtimeFn) return runtimeFn(fileTreeRuntimeDeps());
|
|
||||||
return Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]')).map(function(row) {
|
|
||||||
var documentId = row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '';
|
|
||||||
if (!documentId) return null;
|
|
||||||
var parentRowId = row.getAttribute('data-parent-id') || '';
|
|
||||||
var parentDocumentId = parentRowId.indexOf('doc:') === 0 ? parentRowId.slice(4) : parentRowId || null;
|
|
||||||
return { documentId: documentId, parentId: parentDocumentId };
|
|
||||||
}).filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileTreeTargetChildrenForPreflight(targetRow) {
|
|
||||||
var runtimeFn = fileTreeRuntimeFunction('fileTreeTargetChildrenForPreflight');
|
|
||||||
if (runtimeFn) return runtimeFn(targetRow, fileTreeRuntimeDeps());
|
|
||||||
var node = targetRow instanceof HTMLElement ? targetRow.closest('.tree-node') : null;
|
|
||||||
if (!node) return [];
|
|
||||||
return Array.from(node.querySelectorAll(':scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"]')).map(function(row) {
|
|
||||||
return {
|
|
||||||
rowKind: row.getAttribute('data-row-kind') || '',
|
|
||||||
documentId: row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || null,
|
|
||||||
assetId: row.getAttribute('data-asset-id') || null,
|
|
||||||
title: rowTitle(row)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileTreeDropPreflightRows() {
|
|
||||||
var runtimeFn = fileTreeRuntimeFunction('fileTreeDropPreflightRows');
|
|
||||||
if (runtimeFn) return runtimeFn(Object.assign({}, fileTreeRuntimeDeps(), {
|
|
||||||
fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight
|
|
||||||
}));
|
|
||||||
return fileTreeRowsForUploadPreflight().map(function(row) {
|
|
||||||
var domRow = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(row.rowId) + '"]');
|
|
||||||
row.title = rowTitle(domRow);
|
|
||||||
return row;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ensureFileTreeWritableTarget(action, targetRow, rowIds, copy) {
|
|
||||||
var normalizedAction = String(action || 'drop').trim() || 'drop';
|
|
||||||
if (!(targetRow instanceof HTMLElement)) return true;
|
|
||||||
var detail = {
|
|
||||||
targetRowId: targetRow.getAttribute('data-row-id') || '',
|
|
||||||
rowId: targetRow.getAttribute('data-row-id') || '',
|
|
||||||
documentId: targetRow.getAttribute('data-document-id') || targetRow.getAttribute('data-doc-id') || '',
|
|
||||||
assetId: targetRow.getAttribute('data-asset-id') || ''
|
|
||||||
};
|
|
||||||
if (fileTreeRowIsReadonly(targetRow)) {
|
|
||||||
return blockReadonlyFileTreeAction(normalizedAction, detail, '目标位置是只读,不能拖放到这里');
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
var response = await fetch('/api/tree/filetree/drop-preflight', {
|
|
||||||
method: 'POST',
|
|
||||||
credentials: 'include',
|
|
||||||
headers: { 'content-type': 'application/json' },
|
|
||||||
body: JSON.stringify({
|
|
||||||
workspaceId: resolveWorkspaceId(targetRow),
|
|
||||||
copy: Boolean(copy),
|
|
||||||
sourceCapabilities: ['read', 'write', 'move'],
|
|
||||||
targetCapabilities: fileTreeRowCapabilities(targetRow),
|
|
||||||
targetDocumentId: detail.documentId || null,
|
|
||||||
targetRowId: detail.targetRowId || null,
|
|
||||||
focusedRowId: sidebarFileTreeSelection.focusedRowId || null,
|
|
||||||
activeDocumentId: currentDocumentId() || null,
|
|
||||||
rowIds: Array.isArray(rowIds) ? rowIds : [],
|
|
||||||
rows: fileTreeDropPreflightRows(),
|
|
||||||
targetChildren: fileTreeTargetChildrenForPreflight(targetRow),
|
|
||||||
documentParents: fileTreeDocumentParentsForPreflight()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
if (response.ok) return true;
|
|
||||||
var payload = await response.json().catch(function() { return null; });
|
|
||||||
var message = payload && (payload.error || payload.message) ? String(payload.error || payload.message) : '目标位置是只读,不能拖放到这里';
|
|
||||||
if (message.indexOf('只读') >= 0 || message.toLowerCase().indexOf('readonly') >= 0) {
|
|
||||||
return blockReadonlyFileTreeAction(normalizedAction, detail, message);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (_) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileTreeDocumentWorkspacesForUploadPreflight(workspaceId) {
|
|
||||||
var runtimeFn = fileTreeRuntimeFunction('fileTreeDocumentWorkspacesForUploadPreflight');
|
|
||||||
if (runtimeFn) {
|
|
||||||
return runtimeFn(workspaceId, Object.assign({}, fileTreeRuntimeDeps(), {
|
|
||||||
fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
var seen = new Set();
|
|
||||||
return fileTreeRowsForUploadPreflight().filter(function(row) {
|
|
||||||
if (!row.documentId || seen.has(row.documentId)) return false;
|
|
||||||
seen.add(row.documentId);
|
|
||||||
return true;
|
|
||||||
}).map(function(row) {
|
|
||||||
return { documentId: row.documentId, workspaceId: workspaceId || null };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function preflightFileTreeUploadTarget(detail) {
|
|
||||||
var bodyRuntime = fileTreeRuntimeFunction('fileTreeUploadTargetPreflightBody');
|
|
||||||
var body = bodyRuntime ? bodyRuntime(detail || {}, Object.assign({}, fileTreeRuntimeDeps(), {
|
|
||||||
focusedRowId: sidebarFileTreeSelection.focusedRowId || null,
|
|
||||||
fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight,
|
|
||||||
currentDocumentId: currentDocumentId,
|
|
||||||
resolveWorkspaceId: resolveWorkspaceId
|
|
||||||
})) : (function() {
|
|
||||||
var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim();
|
|
||||||
return {
|
|
||||||
workspaceId: workspaceId || null,
|
|
||||||
targetDocumentId: detail && detail.documentId ? String(detail.documentId) : null,
|
|
||||||
targetRowId: detail && detail.targetRowId ? String(detail.targetRowId) : null,
|
|
||||||
focusedRowId: sidebarFileTreeSelection.focusedRowId || null,
|
|
||||||
activeDocumentId: currentDocumentId() || null,
|
|
||||||
rows: fileTreeRowsForUploadPreflight(),
|
|
||||||
documentWorkspaces: fileTreeDocumentWorkspacesForUploadPreflight(workspaceId)
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
var response = await fetch('/api/tree/filetree/upload-target-preflight', {
|
|
||||||
method: 'POST',
|
|
||||||
credentials: 'include',
|
|
||||||
headers: { 'content-type': 'application/json' },
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
});
|
|
||||||
var payload = await response.json().catch(function() { return null; });
|
|
||||||
if (!response.ok || !payload || !payload.plan) {
|
|
||||||
throw new Error(payload && payload.error ? payload.error : '文件树上传目标预检失败');
|
|
||||||
}
|
|
||||||
return payload.plan;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fallbackFileTreeUploadTarget(detail) {
|
|
||||||
var runtimeFn = fileTreeRuntimeFunction('fileTreeUploadTargetFallback');
|
|
||||||
if (runtimeFn) {
|
|
||||||
return runtimeFn(detail || {}, {
|
|
||||||
resolveWorkspaceId: resolveWorkspaceId,
|
|
||||||
currentDocumentId: currentDocumentId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim();
|
|
||||||
var documentId = String(detail && detail.documentId || currentDocumentId() || '').trim();
|
|
||||||
if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
|
||||||
return {
|
|
||||||
workspaceId: workspaceId,
|
|
||||||
targetDocumentId: documentId,
|
|
||||||
targetMindmapId: null,
|
|
||||||
targetSubPath: null,
|
|
||||||
targetRelativePath: String(detail.targetRelativePath || ''),
|
|
||||||
uploadIntent: String(detail.uploadIntent || 'filetree.folder.drop')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!workspaceId || !documentId) {
|
|
||||||
throw new Error('请选择一个目标页面后再拖入文件');
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
workspaceId: workspaceId,
|
|
||||||
targetDocumentId: documentId,
|
|
||||||
targetMindmapId: null,
|
|
||||||
targetSubPath: null,
|
|
||||||
uploadIntent: String(detail && detail.uploadIntent || 'editor.markdown.attach')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveFileTreeUploadTarget(detail) {
|
|
||||||
if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
|
||||||
return fallbackFileTreeUploadTarget(detail || {});
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
var plan = await preflightFileTreeUploadTarget(detail || {});
|
|
||||||
var normalizePlanRuntime = fileTreeRuntimeFunction('normalizeFileTreeUploadTargetPlan');
|
|
||||||
if (normalizePlanRuntime) {
|
|
||||||
return normalizePlanRuntime(detail || {}, plan);
|
|
||||||
}
|
|
||||||
if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
|
||||||
plan.targetRelativePath = String(detail.targetRelativePath || '');
|
|
||||||
}
|
|
||||||
if (detail && detail.uploadIntent) {
|
|
||||||
plan.uploadIntent = String(detail.uploadIntent);
|
|
||||||
} else if (detail && Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
|
|
||||||
plan.uploadIntent = 'filetree.folder.drop';
|
|
||||||
} else if (!plan.uploadIntent) {
|
|
||||||
plan.uploadIntent = 'editor.markdown.attach';
|
|
||||||
}
|
|
||||||
return plan;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('[mnote upload] upload target preflight fallback', error);
|
|
||||||
return fallbackFileTreeUploadTarget(detail || {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function localUploadRuntimeFunction(name) {
|
function localUploadRuntimeFunction(name) {
|
||||||
var runtime = window.__mnoteLocalUploadRuntime;
|
var runtime = window.__mnoteLocalUploadRuntime;
|
||||||
@@ -2323,6 +2080,18 @@ import { createSidebarFileTreeCommandRuntime } from './sidebar-filetree-command-
|
|||||||
const pasteSidebarFileTreeClipboard = (...args) => sidebarFileTreeCommand.pasteSidebarFileTreeClipboard(...args);
|
const pasteSidebarFileTreeClipboard = (...args) => sidebarFileTreeCommand.pasteSidebarFileTreeClipboard(...args);
|
||||||
const deleteSelectedSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.deleteSelectedSidebarFileTreeRows(...args);
|
const deleteSelectedSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.deleteSelectedSidebarFileTreeRows(...args);
|
||||||
|
|
||||||
|
sidebarFileTreeUpload = createSidebarFileTreeUploadRuntime({
|
||||||
|
cssEscape,
|
||||||
|
currentDocumentId,
|
||||||
|
fileTreeRuntimeDeps,
|
||||||
|
fileTreeRuntimeFunction,
|
||||||
|
recordFileTreeAction,
|
||||||
|
recordFileTreeActionStatus,
|
||||||
|
resolveWorkspaceId,
|
||||||
|
rowTitle,
|
||||||
|
selectedSidebarFileTreeSelection: sidebarFileTreeSelection,
|
||||||
|
});
|
||||||
|
|
||||||
function ensureSearchModal() {
|
function ensureSearchModal() {
|
||||||
var existing = document.querySelector('[data-testid="wolai-search-modal"]');
|
var existing = document.querySelector('[data-testid="wolai-search-modal"]');
|
||||||
if (existing instanceof HTMLElement) return existing;
|
if (existing instanceof HTMLElement) return existing;
|
||||||
|
|||||||
@@ -142,6 +142,10 @@ pub fn build_router(state: AppState) -> Router {
|
|||||||
"/api/mnote-browser-runtime/sidebar-filetree-command-runtime.js",
|
"/api/mnote-browser-runtime/sidebar-filetree-command-runtime.js",
|
||||||
get(web_shell::sidebar_filetree_command_runtime_asset),
|
get(web_shell::sidebar_filetree_command_runtime_asset),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/api/mnote-browser-runtime/sidebar-filetree-upload-runtime.js",
|
||||||
|
get(web_shell::sidebar_filetree_upload_runtime_asset),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/mnote-browser-runtime/sidebar-attachment-open-runtime.js",
|
"/api/mnote-browser-runtime/sidebar-attachment-open-runtime.js",
|
||||||
get(web_shell::sidebar_attachment_open_runtime_asset),
|
get(web_shell::sidebar_attachment_open_runtime_asset),
|
||||||
@@ -603,6 +607,7 @@ mod tests {
|
|||||||
"/api/mnote-browser-runtime/sidebar-tree-live-apply-runtime.js",
|
"/api/mnote-browser-runtime/sidebar-tree-live-apply-runtime.js",
|
||||||
"/api/mnote-browser-runtime/sidebar-filetree-open-runtime.js",
|
"/api/mnote-browser-runtime/sidebar-filetree-open-runtime.js",
|
||||||
"/api/mnote-browser-runtime/sidebar-filetree-command-runtime.js",
|
"/api/mnote-browser-runtime/sidebar-filetree-command-runtime.js",
|
||||||
|
"/api/mnote-browser-runtime/sidebar-filetree-upload-runtime.js",
|
||||||
"/api/mnote-browser-runtime/sidebar-attachment-open-runtime.js",
|
"/api/mnote-browser-runtime/sidebar-attachment-open-runtime.js",
|
||||||
"/api/mnote-browser-runtime/sidebar-tree-runtime.js",
|
"/api/mnote-browser-runtime/sidebar-tree-runtime.js",
|
||||||
"/api/mnote-browser-runtime/tree-live-controller.js",
|
"/api/mnote-browser-runtime/tree-live-controller.js",
|
||||||
|
|||||||
@@ -798,6 +798,20 @@ pub async fn sidebar_filetree_command_runtime_asset() -> Response {
|
|||||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn sidebar_filetree_upload_runtime_asset() -> Response {
|
||||||
|
const JS: &str = include_str!("../../browser/sidebar-filetree-upload-runtime.js");
|
||||||
|
Response::builder()
|
||||||
|
.status(StatusCode::OK)
|
||||||
|
.header(
|
||||||
|
header::CONTENT_TYPE,
|
||||||
|
"application/javascript; charset=utf-8",
|
||||||
|
)
|
||||||
|
.header(header::CACHE_CONTROL, "no-store")
|
||||||
|
.header(HEADER_MNOTE_WEB_OWNER, "mnote-web")
|
||||||
|
.body(Body::from(JS))
|
||||||
|
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn sidebar_attachment_open_runtime_asset() -> Response {
|
pub async fn sidebar_attachment_open_runtime_asset() -> Response {
|
||||||
const JS: &str = include_str!("../../browser/sidebar-attachment-open-runtime.js");
|
const JS: &str = include_str!("../../browser/sidebar-attachment-open-runtime.js");
|
||||||
Response::builder()
|
Response::builder()
|
||||||
|
|||||||
@@ -205,6 +205,8 @@ mod tests {
|
|||||||
include_str!("../../../browser/sidebar-filetree-open-runtime.js");
|
include_str!("../../../browser/sidebar-filetree-open-runtime.js");
|
||||||
const SIDEBAR_FILETREE_COMMAND_RUNTIME_JS: &str =
|
const SIDEBAR_FILETREE_COMMAND_RUNTIME_JS: &str =
|
||||||
include_str!("../../../browser/sidebar-filetree-command-runtime.js");
|
include_str!("../../../browser/sidebar-filetree-command-runtime.js");
|
||||||
|
const SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS: &str =
|
||||||
|
include_str!("../../../browser/sidebar-filetree-upload-runtime.js");
|
||||||
const SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS: &str =
|
const SIDEBAR_ATTACHMENT_OPEN_RUNTIME_JS: &str =
|
||||||
include_str!("../../../browser/sidebar-attachment-open-runtime.js");
|
include_str!("../../../browser/sidebar-attachment-open-runtime.js");
|
||||||
const SIDEBAR_SHELL_RUNTIME_JS: &str =
|
const SIDEBAR_SHELL_RUNTIME_JS: &str =
|
||||||
@@ -599,15 +601,15 @@ mod tests {
|
|||||||
assert!(
|
assert!(
|
||||||
SIDEBAR_TREE_RUNTIME_JS.contains("fileTreeRuntimeFunction('appendUploadedAssetRow')")
|
SIDEBAR_TREE_RUNTIME_JS.contains("fileTreeRuntimeFunction('appendUploadedAssetRow')")
|
||||||
);
|
);
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('fileTreeUploadTargetFallback')"));
|
.contains("fileTreeRuntimeFunction('fileTreeUploadTargetFallback')"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('fileTreeRowsForUploadPreflight')"));
|
.contains("fileTreeRuntimeFunction('fileTreeRowsForUploadPreflight')"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('fileTreeDocumentParentsForPreflight')"));
|
.contains("fileTreeRuntimeFunction('fileTreeDocumentParentsForPreflight')"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('fileTreeTargetChildrenForPreflight')"));
|
.contains("fileTreeRuntimeFunction('fileTreeTargetChildrenForPreflight')"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('fileTreeDropPreflightRows')"));
|
.contains("fileTreeRuntimeFunction('fileTreeDropPreflightRows')"));
|
||||||
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS
|
assert!(SIDEBAR_TREE_LIVE_APPLY_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('readProjection')"));
|
.contains("fileTreeRuntimeFunction('readProjection')"));
|
||||||
@@ -741,11 +743,11 @@ mod tests {
|
|||||||
assert!(FILETREE_RUNTIME_JS.contains("requestMethod: requestMethod"));
|
assert!(FILETREE_RUNTIME_JS.contains("requestMethod: requestMethod"));
|
||||||
assert!(FILETREE_RUNTIME_JS
|
assert!(FILETREE_RUNTIME_JS
|
||||||
.contains("requestBodyHasMindmapCreateOnly: requestBodyHasMindmapCreateOnly"));
|
.contains("requestBodyHasMindmapCreateOnly: requestBodyHasMindmapCreateOnly"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('fileTreeDocumentWorkspacesForUploadPreflight')"));
|
.contains("fileTreeRuntimeFunction('fileTreeDocumentWorkspacesForUploadPreflight')"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRuntimeFunction('fileTreeUploadTargetPreflightBody')"));
|
.contains("fileTreeRuntimeFunction('fileTreeUploadTargetPreflightBody')"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS
|
||||||
.contains("fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight"));
|
.contains("fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("fileTreeRuntimeFunction('shortMindmapFileName')"));
|
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("fileTreeRuntimeFunction('shortMindmapFileName')"));
|
||||||
assert!(
|
assert!(
|
||||||
@@ -1023,13 +1025,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sidebar_filetree_blocks_readonly_paste_and_drop_with_action_status() {
|
fn sidebar_filetree_blocks_readonly_paste_and_drop_with_action_status() {
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function blockReadonlyFileTreeAction"));
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS.contains("function blockReadonlyFileTreeAction"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-mnote-filetree-readonly-blocked"));
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS.contains("data-mnote-filetree-readonly-blocked"));
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-mnote-filetree-readonly-message"));
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS.contains("data-mnote-filetree-readonly-message"));
|
||||||
assert!(
|
assert!(
|
||||||
SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("recordFileTreeActionStatus('blocked'")
|
SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("recordFileTreeActionStatus('blocked'")
|
||||||
);
|
);
|
||||||
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("/api/tree/filetree/drop-preflight"));
|
assert!(SIDEBAR_FILETREE_UPLOAD_RUNTIME_JS.contains("/api/tree/filetree/drop-preflight"));
|
||||||
assert!(
|
assert!(
|
||||||
SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("ensureFileTreeWritableTarget('paste'")
|
SIDEBAR_FILETREE_COMMAND_RUNTIME_JS.contains("ensureFileTreeWritableTarget('paste'")
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user