fix: scope files plugin to workspace folders

This commit is contained in:
mirivlad 2026-06-19 23:37:10 +08:00
parent da49788504
commit 12d491a786
3 changed files with 54 additions and 12 deletions

View File

@ -29,7 +29,8 @@
'.files-item{display:flex;align-items:center;gap:0.6rem;padding:0.4rem 0.75rem;cursor:pointer;font-size:0.85rem}', '.files-item{display:flex;align-items:center;gap:0.6rem;padding:0.4rem 0.75rem;cursor:pointer;font-size:0.85rem}',
'.files-item:hover{background:#1a1a2e}', '.files-item:hover{background:#1a1a2e}',
'.files-item.selected{background:#1a2a3a}', '.files-item.selected{background:#1a2a3a}',
'.files-item-icon{font-size:1rem;width:1.2rem;text-align:center;flex-shrink:0}', '.files-item-icon{width:1.2rem;height:1.2rem;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:#8b8ba8}',
'.files-item-icon svg{display:block;width:16px;height:16px}',
'.files-item-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', '.files-item-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
'.files-item-meta{font-size:0.7rem;color:#666;flex-shrink:0}', '.files-item-meta{font-size:0.7rem;color:#666;flex-shrink:0}',
'.files-empty{flex:1;display:flex;align-items:center;justify-content:center;color:#666;font-size:0.9rem}', '.files-empty{flex:1;display:flex;align-items:center;justify-content:center;color:#666;font-size:0.9rem}',
@ -63,14 +64,26 @@
return elem; return elem;
} }
function svgIcon(path) {
return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true"><path d="' + path + '" fill="currentColor"/></svg>';
}
function fileIcon(entry) { function fileIcon(entry) {
if (entry.type === 'folder') return '\uD83D\uDCC1'; if (entry.type === 'folder') {
return svgIcon('M3 5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v1H3V5Zm0 6h18v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7Z');
}
var ext = (entry.extension || '').toLowerCase(); var ext = (entry.extension || '').toLowerCase();
if (ext === 'md' || ext === 'markdown') return '\uD83D\uDCDD'; if (ext === 'md' || ext === 'markdown') {
if (ext === 'txt' || ext === 'log') return '\uD83D\uDCC4'; return svgIcon('M5 3h10l4 4v14H5V3Zm9 1.5V8h3.5L14 4.5ZM8 11h8v2H8v-2Zm0 4h8v2H8v-2Z');
}
if (ext === 'txt' || ext === 'log') {
return svgIcon('M6 2h9l5 5v15H6V2Zm8 1.5V8h4.5L14 3.5ZM8 12h8v2H8v-2Zm0 4h8v2H8v-2Z');
}
if (ext === 'json') return '{ }'; if (ext === 'json') return '{ }';
if (ext === 'yaml' || ext === 'yml' || ext === 'toml') return '\u2699\uFE0F'; if (ext === 'yaml' || ext === 'yml' || ext === 'toml') {
return '\uD83D\uDCC1'; return svgIcon('M19.14 13l.57-1.43 1.79-.5-1-2.29-1.64.73-.29-.28-.73-1.64 2.29-1-1-2.29-1.79.5-.57 1.43-2.17.17-.57-1.43-1.79-.5-1 2.29 1.64.73-.29.28-.73 1.64-2.29-1-1 2.29 1.79.5.57 1.43-.57 1.43-1.79.5 1 2.29 1.64-.73.29.28.73 1.64-2.29 1 1 2.29 1.79-.5.57-1.43 2.17-.17.57 1.43 1.79.5 1-2.29-1.64-.73.29-.28.73-1.64 2.29 1 1-2.29-1.79-.5-.57-1.43ZM12 9a3 3 0 1 1 0 6 3 3 0 0 1 0-6Z');
}
return svgIcon('M6 2h9l5 5v15H6V2Zm8 1.5V8h4.5L14 3.5Z');
} }
function formatSize(bytes) { function formatSize(bytes) {
@ -95,6 +108,7 @@
containerEl.innerHTML = ''; containerEl.innerHTML = '';
containerEl.className = 'files-root'; containerEl.className = 'files-root';
var workspaceRoot = cleanPath(props && (props.workspaceRootPath || (props.workspaceNode && props.workspaceNode.path)) || '');
var currentPath = ''; var currentPath = '';
var entries = []; var entries = [];
var disposed = false; var disposed = false;
@ -124,9 +138,28 @@
var createMode = ''; // 'folder' | 'file' | '' var createMode = ''; // 'folder' | 'file' | ''
function cleanPath(path) {
return String(path || '').split('/').filter(Boolean).join('/');
}
function scopedPath(localPath) {
localPath = cleanPath(localPath);
if (!workspaceRoot) return localPath;
return localPath ? workspaceRoot + '/' + localPath : workspaceRoot;
}
function localPath(fullPath) {
fullPath = cleanPath(fullPath);
if (!workspaceRoot) return fullPath;
if (fullPath === workspaceRoot) return '';
if (fullPath.indexOf(workspaceRoot + '/') === 0) return fullPath.slice(workspaceRoot.length + 1);
return fullPath;
}
function updateBreadcrumb() { function updateBreadcrumb() {
breadcrumb.innerHTML = ''; breadcrumb.innerHTML = '';
var rootItem = el('span', { className: 'files-breadcrumb-item', onClick: function () { navigateTo(''); } }, ['Root']); var rootLabel = props && props.workspaceNode && props.workspaceNode.title ? props.workspaceNode.title : 'Root';
var rootItem = el('span', { className: 'files-breadcrumb-item', onClick: function () { navigateTo(''); } }, [rootLabel]);
breadcrumb.appendChild(rootItem); breadcrumb.appendChild(rootItem);
if (currentPath) { if (currentPath) {
var parts = currentPath.split('/'); var parts = currentPath.split('/');
@ -151,13 +184,13 @@
sorted.forEach(function (entry) { sorted.forEach(function (entry) {
if (entry.isHidden || entry.isReserved) return; if (entry.isHidden || entry.isReserved) return;
var item = el('div', { className: 'files-item' }, [ var item = el('div', { className: 'files-item' }, [
el('span', { className: 'files-item-icon' }, [fileIcon(entry)]), el('span', { className: 'files-item-icon', innerHTML: fileIcon(entry) }),
el('span', { className: 'files-item-name', textContent: entry.name }), el('span', { className: 'files-item-name', textContent: entry.name }),
el('span', { className: 'files-item-meta', textContent: entry.type === 'folder' ? '' : formatSize(entry.size) }), el('span', { className: 'files-item-meta', textContent: entry.type === 'folder' ? '' : formatSize(entry.size) }),
]); ]);
if (entry.type === 'folder') { if (entry.type === 'folder') {
item.addEventListener('dblclick', function () { item.addEventListener('dblclick', function () {
navigateTo(entry.relativePath); navigateTo(localPath(entry.relativePath));
}); });
} else { } else {
item.addEventListener('dblclick', function () { item.addEventListener('dblclick', function () {
@ -177,7 +210,7 @@
function loadEntries() { function loadEntries() {
listContainer.innerHTML = ''; listContainer.innerHTML = '';
listContainer.appendChild(el('div', { className: 'files-loading' }, ['Loading...'])); listContainer.appendChild(el('div', { className: 'files-loading' }, ['Loading...']));
api.files.list(currentPath).then(function (result) { api.files.list(scopedPath(currentPath)).then(function (result) {
if (disposed) return; if (disposed) return;
entries = result || []; entries = result || [];
renderList(); renderList();
@ -195,7 +228,8 @@
function openFile(entry) { function openFile(entry) {
var ext = entry.extension ? '.' + entry.extension : ''; var ext = entry.extension ? '.' + entry.extension : '';
var isMd = ext === '.md' || ext === '.markdown'; var isMd = ext === '.md' || ext === '.markdown';
var isNotes = currentPath.split('/')[0] === 'Notes'; var entryLocalPath = localPath(entry.relativePath);
var isNotes = entryLocalPath.split('/')[0] === 'Notes';
var context = { sourcePluginId: 'verstak.files', sourceView: 'files' }; var context = { sourcePluginId: 'verstak.files', sourceView: 'files' };
if (isMd && isNotes) { if (isMd && isNotes) {
context.isInsideNotesFolder = true; context.isInsideNotesFolder = true;
@ -228,7 +262,8 @@
function confirmCreate() { function confirmCreate() {
var name = createInput.value.trim(); var name = createInput.value.trim();
if (!name) return; if (!name) return;
var path = currentPath ? currentPath + '/' + name : name; var localCreatePath = currentPath ? currentPath + '/' + name : name;
var path = scopedPath(localCreatePath);
var promise; var promise;
if (createMode === 'folder') { if (createMode === 'folder') {
promise = api.files.createFolder(path); promise = api.files.createFolder(path);

View File

@ -51,6 +51,10 @@ package_plugin() {
mkdir -p "$dist_dir/frontend/dist" mkdir -p "$dist_dir/frontend/dist"
cp -r "$plugin_dir/frontend/dist/." "$dist_dir/frontend/dist/" cp -r "$plugin_dir/frontend/dist/." "$dist_dir/frontend/dist/"
echo " └─ frontend/dist ($(find "$dist_dir/frontend/dist" -type f | wc -l) file(s))" echo " └─ frontend/dist ($(find "$dist_dir/frontend/dist" -type f | wc -l) file(s))"
elif [ -f "$plugin_dir/frontend/src/index.js" ]; then
mkdir -p "$dist_dir/frontend/dist"
cp "$plugin_dir/frontend/src/index.js" "$dist_dir/frontend/dist/index.js"
echo " └─ frontend/dist/index.js (from frontend/src/index.js)"
fi fi
# 3. backend binary # 3. backend binary

View File

@ -104,6 +104,9 @@ if command -v node &>/dev/null; then
entry=$(node -e "const m=require('$manifest');console.log(m.frontend&&m.frontend.entry||'')" 2>/dev/null) entry=$(node -e "const m=require('$manifest');console.log(m.frontend&&m.frontend.entry||'')" 2>/dev/null)
if [ -z "$entry" ]; then continue; fi if [ -z "$entry" ]; then continue; fi
bundle="$plugin_dir$entry" bundle="$plugin_dir$entry"
if [ ! -f "$bundle" ] && [ "$entry" = "frontend/dist/index.js" ] && [ -f "$plugin_dir/frontend/src/index.js" ]; then
bundle="$plugin_dir/frontend/src/index.js"
fi
if [ ! -f "$bundle" ]; then if [ ! -f "$bundle" ]; then
echo "$plugin_id: bundle not found at $entry" echo "$plugin_id: bundle not found at $entry"
BUNDLE_FAILED=1 BUNDLE_FAILED=1