perf(files): page the Files browser and resolve files without listing the workspace

Merged
WA
1d ago
+5792-1456

Summary

Moves every workspace-file consumer off the full workspace list onto the paged, search and lookup reads from #9435, so a large workspace no longer downloads and re-downloads its whole file list.

Files browser

  • Virtualized infinite table (the Logs pattern): one page of the open folder at a time, loading more on scroll, server-side sort (name, size, created, updated, type, owner), filters (kind, size, uploader) and workspace-wide search, with folder sizes from the folder-stats read
  • Folders interleave with the paged files through the shared resource comparator, exactly as before; pinned files still lead their folder
  • The server prefetch seeds the first page the URL asks for (or the open file's record) instead of "the whole list or nothing"

Everything else that read the whole list

  • Single-file views (viewer, diff embed, mothership view, embedded file, share deep link) read the record by id, seeded from any cached read
  • Chips, tab names, table file cells, the image-dimension adapter and stale-key recovery use batched lookups, classified per value
  • Mentions, the @/plus menus, add-resource, Cmd+K and search/replace use one picker hook: recent files, or server search once typing settles
  • The workflow file-upload picker pages its folder-scoped list; the sidebar flyout loads a folder level when it opens
  • Writes patch only the reads they can't reorder; rename refetches lists and searches once it lands; content saves write the returned record through; unobserved lists are trimmed before invalidation

Server

  • Kind, size and uploader filters and Type/Owner sorts on the paged list; Type and kind come from one set of rules shared with the project file browser (tables in lib/workspace-files/browser.ts, SQL in lib/workspace-files/file-type-sql.ts), so both browsers classify files identically
  • Ranked search matching the palette: exact, prefix, substring or all words, typos via trigram similarity, word-start initials (run only when the indexed match comes up short), and files under matching folders
  • folder-stats takes several parents in one read
  • Resource.Table separates the load-more spinner from the sentinel gate (isFetching, defaulting to isLoadingMore, so other tables are unchanged)

The unpaged list response and the public v1 API are unchanged.

Type of Change

  • New feature
  • Other: performance

Testing

  • Integration (real Postgres, migrate- and push-provisioned; workspace-files, uploads/workspace, projects/files suites): kind/size/uploader filters and bucket edges, filtered paging, Type and Owner sorts against Postgres collation in both directions, folder-index plan, JS/SQL type and kind parity for every known extension (plus unknown ones), ranked search (typos, word order, initials, folder paths, scope), multi-parent folder stats
  • Unit: paging and cursor resume, re-sort placeholders (never another folder's rows), opening a file from the list without a request, deleted file reads as gone, rename optimism/rollback and post-rename order, content-save write-through, cache trimming and scoped patches, lookup batching and isolation, picker pending/settled states, stale saved filters, search placeholders scoped to the workspace, the table resuming paging after a background refetch
  • bun run lint, bun run check:audits (61), bun run type-check, check:test-patterns, check:migrations (no new migrations)
  • Not exercised in a browser yet: scrolling feel, drag-and-drop with virtualization, and the menus are covered by tests only

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)