aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-28 09:10:23 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-28 09:10:23 +0200
commit4b7d52a28e9a02d55574b2f08b8030ba179caeff (patch)
treee6866d341c6906f604e40ef832ac193c2b5dd719
parent3c2316dea098c3e99ef40c0012b83f0e8b735c10 (diff)
downloadmeshbay-4b7d52a28e9a02d55574b2f08b8030ba179caeff.tar.gz
fix(files): make "Filter files" search the whole group
The filter only ever matched files whose folder was exactly the current path, so at the top of a group — where every row is a root, never a loose file — typing in the field did nothing at all. With text in the field the panel now searches every file in the group by name or containing folder, wherever it lives, and hides the folder rows (you are searching, not browsing). Each result shows its folder as a sub-line; clicking it clears the filter and opens that folder. Empty field restores the normal folder-by-folder view unchanged. Also hardened the sort comparators against an entry missing `name`/`type`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018gKJ85aZyvEwarXMFzFEwi
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/files-app.js25
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/style.css10
2 files changed, 29 insertions, 6 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
index 16ab9f6..c4b221e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js
@@ -139,12 +139,21 @@ function FilesPanel({
setSortKey(key);
}, [sortKey]);
+ // With text in the field the user is searching, not browsing: match every
+ // file in the whole group, wherever it lives, by name or by the folder it
+ // sits in — and hide the folder rows, there is nothing to walk into. The
+ // old code only ever filtered files whose folder was exactly `currentPath`,
+ // so at the top of a group — where the rows are roots, never loose files —
+ // typing did nothing at all.
+ const q = filter.trim().toLowerCase();
const dirs = new Set();
const filteredEntries = entries.filter(e => {
const ePath = e.path || '';
- if (ePath === currentPath) {
- return !filter || e.name.toLowerCase().includes(filter.toLowerCase());
+ if (q) {
+ return (e.name || '').toLowerCase().includes(q)
+ || ePath.toLowerCase().includes(q);
}
+ if (ePath === currentPath) return true;
if (!currentPath && ePath) {
dirs.add(ePath.split('/')[0]);
} else if (currentPath && ePath.startsWith(currentPath + '/')) {
@@ -156,16 +165,17 @@ function FilesPanel({
const sorted = [...filteredEntries].sort((a, b) => {
let cmp = 0;
- if (sortKey === 'name') cmp = a.name.localeCompare(b.name);
+ if (sortKey === 'name') cmp = (a.name || '').localeCompare(b.name || '');
else if (sortKey === 'size') cmp = a.size - b.size;
- else if (sortKey === 'type') cmp = a.type.localeCompare(b.type);
+ else if (sortKey === 'type') cmp = (a.type || '').localeCompare(b.type || '');
else if (sortKey === 'date') cmp = a.added_at - b.added_at;
return sortAsc ? cmp : -cmp;
});
// The node's own listing, so an empty folder is visible, plus anything implied
- // by a file path in case the two ever disagree.
- for (const d of nodeDirs) {
+ // by a file path in case the two ever disagree. Skipped while searching — the
+ // results are a flat list of matches, not a folder view.
+ if (!q) for (const d of nodeDirs) {
if (!currentPath && !d.includes('/')) dirs.add(d);
else if (currentPath && d.startsWith(currentPath + '/')) {
const rest = d.slice(currentPath.length + 1);
@@ -396,6 +406,9 @@ function FilesPanel({
? html`<a class="file-link" onClick=${() => onPreview(e)}>${e.name}</a>`
: e.name
}
+ ${q && e.path && html`
+ <a class="file-loc"
+ onClick=${() => { setFilter(''); setCurrentPath(e.path); }}>${e.path}</a>`}
</td>
<td class="file-size">${formatSize(e.size)}</td>
<td class="file-type td-type">${e.type}</td>
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css
index 61a5e3b..cd9882e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/style.css
+++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css
@@ -817,6 +817,16 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
word-break: break-word;
min-width: 0;
}
+/* Where a search result lives, under its name; click to open that folder
+ and clear the filter. */
+.file-loc {
+ display: block;
+ margin-top: 2px;
+ font-size: 0.78em;
+ color: var(--text-dim);
+ cursor: pointer;
+}
+.file-loc:hover { color: var(--accent); text-decoration: underline; }
.file-size { white-space: nowrap; color: var(--text-secondary); }
.file-type { color: var(--text-dim); }
.file-date { white-space: nowrap; color: var(--text-dim); }