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:hover{background:#1a1a2e}',
'.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-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}',
@ -63,14 +64,26 @@
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) {
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();
if (ext === 'md' || ext === 'markdown') return '\uD83D\uDCDD';
if (ext === 'txt' || ext === 'log') return '\uD83D\uDCC4';
if (ext === 'md' || ext === 'markdown') {
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 === 'yaml' || ext === 'yml' || ext === 'toml') return '\u2699\uFE0F';
return '\uD83D\uDCC1';
if (ext === 'yaml' || ext === 'yml' || ext === 'toml') {
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) {
@ -95,6 +108,7 @@
containerEl.innerHTML = '';
containerEl.className = 'files-root';
var workspaceRoot = cleanPath(props && (props.workspaceRootPath || (props.workspaceNode && props.workspaceNode.path)) || '');
var currentPath = '';
var entries = [];
var disposed = false;
@ -124,9 +138,28 @@
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() {
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);
if (currentPath) {
var parts = currentPath.split('/');
@ -151,13 +184,13 @@
sorted.forEach(function (entry) {
if (entry.isHidden || entry.isReserved) return;
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-meta', textContent: entry.type === 'folder' ? '' : formatSize(entry.size) }),
]);
if (entry.type === 'folder') {
item.addEventListener('dblclick', function () {
navigateTo(entry.relativePath);
navigateTo(localPath(entry.relativePath));
});
} else {
item.addEventListener('dblclick', function () {
@ -177,7 +210,7 @@
function loadEntries() {
listContainer.innerHTML = '';
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;
entries = result || [];
renderList();
@ -195,7 +228,8 @@
function openFile(entry) {
var ext = entry.extension ? '.' + entry.extension : '';
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' };
if (isMd && isNotes) {
context.isInsideNotesFolder = true;
@ -228,7 +262,8 @@
function confirmCreate() {
var name = createInput.value.trim();
if (!name) return;
var path = currentPath ? currentPath + '/' + name : name;
var localCreatePath = currentPath ? currentPath + '/' + name : name;
var path = scopedPath(localCreatePath);
var promise;
if (createMode === 'folder') {
promise = api.files.createFolder(path);

View File

@ -51,6 +51,10 @@ package_plugin() {
mkdir -p "$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))"
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
# 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)
if [ -z "$entry" ]; then continue; fi
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
echo "$plugin_id: bundle not found at $entry"
BUNDLE_FAILED=1