Files
mnote/rust/crates/mnote-web/browser/filetree-runtime.js
T

514 lines
25 KiB
JavaScript

// MNote 主壳文件树运行时外置模块。
// 当前先承接 SIDEBAR_TREE_JS 中低风险的行数据解析 helper;
// inline script 保留 fallback,避免模块加载顺序影响首屏行为。
function fileTreeRowKind(row) {
if (!(row instanceof HTMLElement)) return '';
return String(row.getAttribute('data-row-kind') || '').trim();
}
function fileTreeRowDocumentId(row) {
if (!(row instanceof HTMLElement)) return '';
return String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim();
}
function fileTreeRowAssetId(row, deps) {
if (!(row instanceof HTMLElement)) return '';
var assetId = String(row.getAttribute('data-asset-id') || '').trim();
if (assetId) return assetId;
var currentSourceKind = deps && typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; };
if (currentSourceKind() === 'local_folder' && fileTreeRowKind(row) === 'asset') {
return String(row.getAttribute('data-row-id') || '').trim();
}
return '';
}
function decodeLocalEncodedPath(value) {
var path = String(value || '').trim().replace(/~2F/g, '/');
if (!path) return '';
try {
return decodeURIComponent(path);
} catch (_) {
return path;
}
}
function fileTreeRowLocalRelativePath(row, deps) {
if (!(row instanceof HTMLElement)) return '';
var direct = String(row.getAttribute('data-local-relative-path') || '').trim();
if (direct) return direct;
var localFilePathFromAssetId = deps && typeof deps.localFilePathFromAssetId === 'function'
? deps.localFilePathFromAssetId
: function() { return ''; };
var assetPath = localFilePathFromAssetId(fileTreeRowAssetId(row, deps));
if (assetPath) return assetPath;
var rowId = String(row.getAttribute('data-row-id') || '').trim();
var nodeId = String(row.getAttribute('data-node-id') || '').trim();
var documentId = fileTreeRowDocumentId(row);
var kind = fileTreeRowKind(row);
if (rowId.indexOf('local:asset:') === 0) return rowId.slice('local:asset:'.length);
if (rowId.indexOf('local:markdown:') === 0) return rowId.slice('local:markdown:'.length);
if (rowId.indexOf('local:folder:') === 0) return rowId.slice('local:folder:'.length);
if (rowId.indexOf('local:node:') === 0) return rowId.slice('local:node:'.length);
if (nodeId.indexOf('local:node:') === 0) return nodeId.slice('local:node:'.length);
if ((kind === 'document' || kind === 'doc' || kind === 'markdown') && documentId.indexOf('local-md:') === 0) {
return decodeLocalEncodedPath(documentId.slice('local-md:'.length));
}
if ((kind === 'folder' || kind === 'directory' || kind === 'index') && documentId.indexOf('local-dir:') === 0) {
return decodeLocalEncodedPath(documentId.slice('local-dir:'.length));
}
return '';
}
function fileTreeRowLocalUploadTargetRelativePath(row, deps) {
if (!(row instanceof HTMLElement)) return '';
var kind = fileTreeRowKind(row);
var relativePath = fileTreeRowLocalRelativePath(row, deps);
if (!relativePath) return '';
if (kind === 'folder' || kind === 'directory') return relativePath;
var lastSlash = relativePath.lastIndexOf('/');
return lastSlash >= 0 ? relativePath.slice(0, lastSlash) : '';
}
function isFileTreeDownloadableAssetRow(row, deps) {
if (!(row instanceof HTMLElement)) return false;
var kind = fileTreeRowKind(row);
if (kind === 'document' || kind === 'doc' || kind === 'index' || kind === 'markdown' || kind === 'folder' || kind === 'directory') return false;
return Boolean(fileTreeRowAssetId(row, deps));
}
function isFileTreeDownloadableRow(row, deps) {
if (!(row instanceof HTMLElement)) return false;
var currentSourceKind = deps && typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; };
if (currentSourceKind() !== 'local_folder') return isFileTreeDownloadableAssetRow(row, deps);
return Boolean(fileTreeRowLocalRelativePath(row, deps) || isFileTreeDownloadableAssetRow(row, deps));
}
function fileTreeAssetDownloadDetail(row, deps) {
if (!isFileTreeDownloadableRow(row, deps)) return null;
var rowTitle = deps && typeof deps.rowTitle === 'function' ? deps.rowTitle : function() { return ''; };
var resolveWorkspaceId = deps && typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; };
var title = rowTitle(row);
var relativePath = fileTreeRowLocalRelativePath(row, deps);
var assetId = fileTreeRowAssetId(row, deps) || (relativePath ? 'local-file:' + relativePath : '');
return {
contextKind: 'filetree',
documentId: fileTreeRowDocumentId(row),
rowId: row.getAttribute('data-row-id') || '',
rowKind: fileTreeRowKind(row),
assetId: assetId,
localRelativePath: relativePath,
title: title,
fileName: title,
workspaceId: resolveWorkspaceId(row)
};
}
function fileTreeRowsByRowIds(rowIds, deps) {
var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
return (rowIds || []).map(function(rowId) {
return document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(rowId) + '"]');
}).filter(function(row) { return row instanceof HTMLElement; });
}
function fileTreeChildCount(documentId, deps) {
if (!documentId) return 0;
var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
var row = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + documentId) + '"]');
var node = row ? row.closest('.tree-node') : null;
var children = node ? node.querySelectorAll(':scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"][data-row-kind="document"], :scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"][data-row-kind="doc"]') : [];
return children.length;
}
function defaultEscapeHtml(value) {
return String(value == null ? '' : value)
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function defaultObjectIdentityAttr(identity) {
try {
return JSON.stringify(identity || {});
} catch (_) {
return '';
}
}
function readProjection(value) {
if (!value || typeof value !== 'object') return null;
if (value.result && typeof value.result === 'object') return value.result;
if (value.snapshot && value.snapshot.tree) return value.snapshot.tree;
if (value.data && value.data.tree) return value.data.tree;
if (value.tree && typeof value.tree === 'object') return value.tree;
return value;
}
function readSidebarDataset(value) {
if (!value || typeof value !== 'object') return null;
if (value.snapshot && value.snapshot.dataset && typeof value.snapshot.dataset === 'object') return value.snapshot.dataset;
if (value.data && value.data.dataset && typeof value.data.dataset === 'object') return value.data.dataset;
if (value.dataset && typeof value.dataset === 'object') return value.dataset;
if (value.sidebar && typeof value.sidebar === 'object') return value.sidebar;
return null;
}
function readDatasetProjection(value, snakeCaseKey, camelCaseKey) {
var dataset = readSidebarDataset(value);
if (!dataset || typeof dataset !== 'object') return null;
if (dataset[snakeCaseKey] && typeof dataset[snakeCaseKey] === 'object') return dataset[snakeCaseKey];
if (dataset[camelCaseKey] && typeof dataset[camelCaseKey] === 'object') return dataset[camelCaseKey];
return null;
}
function projectionItems(projection) {
var resolved = readProjection(projection);
return resolved && Array.isArray(resolved.items) ? resolved.items : [];
}
function hasProjectionItems(projection) {
var resolved = readProjection(projection);
return Boolean(resolved && Array.isArray(resolved.items));
}
function nodeIdOf(item) {
return String(item && (item.nodeId || item.id || item.documentId) || '').trim();
}
function rowIdOf(item) {
return String(item && (item.rowId || item.nodeId || item.id) || '').trim();
}
function parentIdOf(item) {
return String(item && (item.parentNodeId || item.parentId || '') || '').trim();
}
function titleOf(item) {
return String(item && item.title || '无标题').trim() || '无标题';
}
function fileWorkspaceRelativePath(item) {
var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
var workspacePath = meta.workspacePath && typeof meta.workspacePath === 'object' ? meta.workspacePath : {};
var fromWorkspacePath = String(workspacePath.relativePath || '').trim();
if (fromWorkspacePath) return fromWorkspacePath;
var extra = meta.extra && typeof meta.extra === 'object' ? meta.extra : {};
var source = extra.source && typeof extra.source === 'object' ? extra.source : {};
var fromSource = String(source.relativePath || '').trim();
if (fromSource) return fromSource;
return String(item && (item.relativePath || item.rootRelativePath) || '').trim();
}
function groupRowsByParent(rows) {
rows = Array.isArray(rows) ? rows : [];
var ids = new Set(rows.map(nodeIdOf).filter(Boolean));
var grouped = new Map();
rows.forEach(function(item) {
var parentId = parentIdOf(item);
if (!ids.has(parentId)) parentId = '';
if (!grouped.has(parentId)) grouped.set(parentId, []);
grouped.get(parentId).push(item);
});
return grouped;
}
function replaceSidebarTreeFromDocument(nextDocument, rootId) {
var current = document.getElementById(rootId);
var next = nextDocument ? nextDocument.getElementById(rootId) : null;
if (!(current instanceof HTMLElement) || !(next instanceof HTMLElement)) return false;
current.innerHTML = next.innerHTML;
Array.from(next.attributes || []).forEach(function(attr) {
current.setAttribute(attr.name, attr.value);
});
return true;
}
function applyLocalFolderSidebarSnapshot(nextDocument, options) {
options = options || {};
var pageRootId = String(options.pageRootId || 'sidebar-tree-root');
var fileRootId = String(options.fileRootId || 'sidebar-file-tree-root');
var appliedPage = replaceSidebarTreeFromDocument(nextDocument, pageRootId);
var appliedFile = replaceSidebarTreeFromDocument(nextDocument, fileRootId);
var applied = appliedPage || appliedFile;
if (applied && typeof options.onApplied === 'function') options.onApplied({
pageRootApplied: appliedPage,
fileRootApplied: appliedFile
});
return applied;
}
function markLocalFolderWatchApplied(value) {
var appliedValue = String(value || 'projection');
if (!document || !document.documentElement) return false;
document.documentElement.setAttribute('data-mnote-local-folder-watch-applied', appliedValue);
return true;
}
function revealFileTreeRow(row) {
if (!(row instanceof HTMLElement)) return;
var node = row.closest('.tree-node');
while (node && node.parentElement) {
if (node.parentElement.classList && node.parentElement.classList.contains('tree-children')) {
node.parentElement.classList.remove('tree-children--collapsed');
var parentNode = node.parentElement.closest('.tree-node');
var parentRow = parentNode ? parentNode.querySelector(':scope > .tree-row') : null;
if (parentRow instanceof HTMLElement) {
parentRow.setAttribute('aria-expanded', 'true');
var toggle = parentRow.querySelector('[data-rust-action="toggle"]');
if (toggle) toggle.setAttribute('aria-expanded', 'true');
}
}
node = node.parentElement.closest('.tree-node');
}
try { row.scrollIntoView({ block: 'nearest' }); } catch (_) {}
}
function revealFileTreeAssetRow(assetId, deps) {
if (!assetId) return false;
var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
var row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(assetId) + '"]');
if (!(row instanceof HTMLElement)) return false;
revealFileTreeRow(row);
return true;
}
function appendUploadedAssetRow(asset, documentId, deps) {
deps = deps || {};
var cssEscape = typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
var escapeHtml = typeof deps.escapeHtml === 'function' ? deps.escapeHtml : defaultEscapeHtml;
var objectIdentityAttr = typeof deps.objectIdentityAttr === 'function' ? deps.objectIdentityAttr : defaultObjectIdentityAttr;
var uploadedAssetTitle = typeof deps.uploadedAssetTitle === 'function' ? deps.uploadedAssetTitle : function(nextAsset) {
return String(nextAsset && (nextAsset.file_name || nextAsset.title || nextAsset.name) || '未命名附件').trim() || '未命名附件';
};
var uploadedAssetType = typeof deps.uploadedAssetType === 'function' ? deps.uploadedAssetType : function(nextAsset) {
return String(nextAsset && (nextAsset.asset_type || nextAsset.assetType || nextAsset.mime_type || '') || '').trim();
};
var fileTreeIconKindForFileName = typeof deps.fileTreeIconKindForFileName === 'function' ? deps.fileTreeIconKindForFileName : function() { return ''; };
var currentDocumentId = typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; };
var currentSourceKind = typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; };
var assetId = String(asset && asset.id || '').trim();
if (!assetId) return false;
if (revealFileTreeAssetRow(assetId, { cssEscape: cssEscape })) return true;
var objectKind = String(asset && (asset.objectKind || asset.resourceKind || '') || '').trim();
if (!objectKind && (String(asset && (asset.asset_type || asset.assetType) || '').trim() === 'mindmap' || /\.mindmap\.json$/i.test(assetId))) {
objectKind = 'mindmap';
}
var targetDocumentId = String(documentId || asset.document_id || asset.documentId || currentDocumentId() || '').trim();
var parentRow = targetDocumentId
? document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + targetDocumentId) + '"]')
: null;
if (!parentRow && currentSourceKind() === 'local_folder' && objectKind === 'mindmap') return false;
if (!parentRow) parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-kind="document"]');
var root = document.querySelector('#sidebar-file-tree-root .tree-root');
if (!root && !parentRow) return false;
var parentLi = parentRow ? parentRow.closest('.tree-node') : null;
var children = parentLi ? parentLi.querySelector(':scope > .tree-children') : null;
if (parentLi && !children) {
children = document.createElement('ul');
children.className = 'tree-children';
parentLi.appendChild(children);
}
if (children) {
children.classList.remove('tree-children--collapsed');
if (parentRow) {
parentRow.setAttribute('aria-expanded', 'true');
var toggle = parentRow.querySelector('[data-rust-action="toggle"]');
if (toggle) toggle.setAttribute('aria-expanded', 'true');
}
}
var container = children || root;
var li = document.createElement('li');
li.className = 'tree-node';
var objectIdentity = {
objectKind: objectKind || 'attachment',
documentId: targetDocumentId || null,
blockId: null,
assetId: assetId
};
li.setAttribute('data-node-id', 'asset:' + assetId);
var title = uploadedAssetTitle(asset);
var iconKind = fileTreeIconKindForFileName(title) || uploadedAssetType(asset) || 'file';
if (objectKind === 'mindmap') iconKind = 'mindmap';
li.innerHTML =
'<div class="tree-row" role="treeitem" aria-level="' + (parentRow ? '2' : '1') + '" aria-expanded="false" data-rust-rendered-row="filetree" data-testid="filetree-asset-row" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-row-kind="asset" data-node-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-doc-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-object-identity="' + escapeHtml(objectIdentityAttr(objectIdentity)) + '" data-object-kind="' + escapeHtml(objectKind || 'attachment') + '" data-shell-mode="filetree" data-selected="false" data-active="false" draggable="true">' +
'<span class="tree-spacer" aria-hidden="true"></span><span class="tree-kind-badge" data-kind="' + escapeHtml(iconKind) + '" aria-hidden="true"></span>' +
'<button type="button" class="tree-link" data-rust-action="open" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '"><span class="tree-link-title">' + escapeHtml(title) + '</span></button>' +
'<div class="tree-actions"><button type="button" class="tree-action" data-testid="filetree-action-menu" data-rust-action="menu" data-row-id="' + escapeHtml('asset:' + assetId) + '" aria-label="更多操作">…</button></div></div>';
container.appendChild(li);
revealFileTreeRow(li.querySelector('.tree-row'));
document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId);
return true;
}
function fileTreeUploadTargetFallback(detail, deps) {
detail = detail || {};
deps = deps || {};
var resolveWorkspaceId = typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; };
var currentDocumentId = typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; };
var workspaceId = String(detail.workspaceId || resolveWorkspaceId(document.body) || '').trim();
var documentId = String(detail.documentId || currentDocumentId() || '').trim();
if (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.uploadIntent || 'editor.markdown.attach')
};
}
function normalizeFileTreeUploadTargetPlan(detail, plan) {
detail = detail || {};
plan = plan && typeof plan === 'object' ? Object.assign({}, plan) : {};
if (Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
plan.targetRelativePath = String(detail.targetRelativePath || '');
}
if (detail.uploadIntent) {
plan.uploadIntent = String(detail.uploadIntent);
} else if (Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
plan.uploadIntent = 'filetree.folder.drop';
} else if (!plan.uploadIntent) {
plan.uploadIntent = 'editor.markdown.attach';
}
return plan;
}
function fileTreeRowsForUploadPreflight(deps) {
deps = deps || {};
var fileTreeRowKind = typeof deps.fileTreeRowKind === 'function' ? deps.fileTreeRowKind : function(row) {
return row instanceof HTMLElement ? String(row.getAttribute('data-row-kind') || '').trim() : '';
};
var fileTreeRowDocumentId = typeof deps.fileTreeRowDocumentId === 'function' ? deps.fileTreeRowDocumentId : function(row) {
return row instanceof HTMLElement ? String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim() : '';
};
var fileTreeRowAssetId = typeof deps.fileTreeRowAssetId === 'function' ? deps.fileTreeRowAssetId : function(row) {
return row instanceof HTMLElement ? String(row.getAttribute('data-asset-id') || '').trim() : '';
};
return Array.from(document.querySelectorAll('.tree-row[data-shell-mode="filetree"]')).map(function(row) {
var documentId = fileTreeRowDocumentId(row);
var assetId = fileTreeRowAssetId(row) || null;
var badge = row.querySelector('.tree-kind-badge');
return {
rowId: row.getAttribute('data-row-id') || '',
rowKind: fileTreeRowKind(row),
documentId: documentId || null,
assetId: assetId,
assetDocumentId: documentId || null,
assetType: badge ? badge.getAttribute('data-kind') : null,
storagePath: null
};
}).filter(function(row) {
return row.rowId || row.documentId || row.assetId;
});
}
function fileTreeDocumentParentsForPreflight(deps) {
deps = deps || {};
var fileTreeRowDocumentId = typeof deps.fileTreeRowDocumentId === 'function' ? deps.fileTreeRowDocumentId : function(row) {
return row instanceof HTMLElement ? String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim() : '';
};
return Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]')).map(function(row) {
var documentId = fileTreeRowDocumentId(row);
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, deps) {
deps = deps || {};
var fileTreeRowKind = typeof deps.fileTreeRowKind === 'function' ? deps.fileTreeRowKind : function(row) {
return row instanceof HTMLElement ? String(row.getAttribute('data-row-kind') || '').trim() : '';
};
var fileTreeRowDocumentId = typeof deps.fileTreeRowDocumentId === 'function' ? deps.fileTreeRowDocumentId : function(row) {
return row instanceof HTMLElement ? String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim() : '';
};
var fileTreeRowAssetId = typeof deps.fileTreeRowAssetId === 'function' ? deps.fileTreeRowAssetId : function(row) {
return row instanceof HTMLElement ? String(row.getAttribute('data-asset-id') || '').trim() : '';
};
var rowTitle = typeof deps.rowTitle === 'function' ? deps.rowTitle : function(row) {
if (!(row instanceof HTMLElement)) return '';
var titleNode = row.querySelector('.tree-link-title');
return String(titleNode && titleNode.textContent || row.getAttribute('title') || '').trim();
};
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: fileTreeRowKind(row),
documentId: fileTreeRowDocumentId(row) || null,
assetId: fileTreeRowAssetId(row) || null,
title: rowTitle(row)
};
});
}
function fileTreeDropPreflightRows(deps) {
deps = deps || {};
var cssEscape = typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
var rowTitle = typeof deps.rowTitle === 'function' ? deps.rowTitle : function(row) {
if (!(row instanceof HTMLElement)) return '';
var titleNode = row.querySelector('.tree-link-title');
return String(titleNode && titleNode.textContent || row.getAttribute('title') || '').trim();
};
var rows = typeof deps.fileTreeRowsForUploadPreflight === 'function'
? deps.fileTreeRowsForUploadPreflight()
: fileTreeRowsForUploadPreflight(deps);
return rows.map(function(row) {
var domRow = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(row.rowId) + '"]');
return Object.assign({}, row, { title: rowTitle(domRow) });
});
}
window.__mnoteFileTreeRuntime = {
readProjection: readProjection,
readSidebarDataset: readSidebarDataset,
readDatasetProjection: readDatasetProjection,
projectionItems: projectionItems,
hasProjectionItems: hasProjectionItems,
nodeIdOf: nodeIdOf,
rowIdOf: rowIdOf,
parentIdOf: parentIdOf,
titleOf: titleOf,
fileWorkspaceRelativePath: fileWorkspaceRelativePath,
groupRowsByParent: groupRowsByParent,
replaceSidebarTreeFromDocument: replaceSidebarTreeFromDocument,
applyLocalFolderSidebarSnapshot: applyLocalFolderSidebarSnapshot,
markLocalFolderWatchApplied: markLocalFolderWatchApplied,
fileTreeRowKind: fileTreeRowKind,
fileTreeRowDocumentId: fileTreeRowDocumentId,
fileTreeRowAssetId: fileTreeRowAssetId,
decodeLocalEncodedPath: decodeLocalEncodedPath,
fileTreeRowLocalRelativePath: fileTreeRowLocalRelativePath,
fileTreeRowLocalUploadTargetRelativePath: fileTreeRowLocalUploadTargetRelativePath,
isFileTreeDownloadableAssetRow: isFileTreeDownloadableAssetRow,
isFileTreeDownloadableRow: isFileTreeDownloadableRow,
fileTreeAssetDownloadDetail: fileTreeAssetDownloadDetail,
fileTreeRowsByRowIds: fileTreeRowsByRowIds,
fileTreeChildCount: fileTreeChildCount,
revealFileTreeRow: revealFileTreeRow,
revealFileTreeAssetRow: revealFileTreeAssetRow,
appendUploadedAssetRow: appendUploadedAssetRow,
fileTreeUploadTargetFallback: fileTreeUploadTargetFallback,
normalizeFileTreeUploadTargetPlan: normalizeFileTreeUploadTargetPlan,
fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight,
fileTreeDocumentParentsForPreflight: fileTreeDocumentParentsForPreflight,
fileTreeTargetChildrenForPreflight: fileTreeTargetChildrenForPreflight,
fileTreeDropPreflightRows: fileTreeDropPreflightRows
};