Commit Graph

1153 Commits

Author SHA1 Message Date
Philipinho 69e7bd73f2 feat(base): render table icon in sidebar for is_base=true pages
- Add isBase to SpaceTreeNode type
- Forward isBase from IPage in buildTree utility
- In the sidebar Node renderer, show IconTable when node.data.isBase
  is true and no custom emoji icon is set
2026-04-27 01:50:05 +01:00
Philipinho 19821d3aeb feat(base): page renderer dispatches to base view when page.isBase
- Add isBase to page repo baseFields so it is always selected
- Add isBase to sidebar pages query select list
- Add isBase to client IPage type
- In PageContent, render <BaseTable pageId={page.id} /> when page.isBase
  is true instead of the TipTap editor path
2026-04-27 01:49:54 +01:00
Philipinho 060bd1048f refactor(base): rename /base/:baseId param to :pageId 2026-04-27 01:44:37 +01:00
Philipinho f56af5e6b4 refactor(base): rename baseId to pageId in client components 2026-04-27 01:44:11 +01:00
Philipinho 3e9f26a8dd refactor(base): rename baseId to pageId in client atoms, hooks, types 2026-04-27 01:42:54 +01:00
Philipinho 4510543510 refactor(base): rename baseId to pageId in client services and queries 2026-04-27 01:41:17 +01:00
Philipinho 25dfb44774 refactor(base): rename baseId to pageId across WS, processors, tasks, formula, events
Renames baseId → pageId in:
- Domain event types (BaseEventBase) and all derived event types
- WS Zod schemas (wire-protocol field names now emit pageId)
- BaseWsService, BaseWsConsumers, BasePresenceService
- FormulaLockService, FormulaService
- BullMQ job interfaces (IBaseTypeConversionJob, IBaseCellGcJob, IBaseFormulaRecomputeJob)
- BaseQueueProcessor and all task functions
- Service emit-payload keys in base.service, base-property.service,
  base-row.service, base-view.service, base-csv-export.service
- Formula spec test fixtures
2026-04-27 01:38:11 +01:00
Philipinho 78d450a238 refactor(base): use PageAccessService for BaseViewController 2026-04-27 01:29:23 +01:00
Philipinho 2e7fe5bbb4 refactor(base): use PageAccessService for BaseRowController 2026-04-27 01:28:59 +01:00
Philipinho 43cf1665f5 refactor(base): use PageAccessService for BasePropertyController 2026-04-27 01:28:28 +01:00
Philipinho fd6a208235 refactor(base): use PageAccessService for BaseController permissions 2026-04-27 01:28:03 +01:00
Philipinho a53dabae70 refactor(base): rename baseId to pageId in DTOs, schemas, and services 2026-04-27 01:27:10 +01:00
Philipinho 54de3a7791 refactor(base): update task files to use renamed repo methods 2026-04-27 01:22:09 +01:00
Philipinho 16161d793b refactor(base): rename baseId to pageId in csv-export and page-resolver services 2026-04-27 01:21:07 +01:00
Philipinho 42f950e11d refactor(base): rename baseId to pageId in BaseViewService 2026-04-27 01:20:34 +01:00
Philipinho fdb250bbe8 refactor(base): rename baseId to pageId in BaseRowService 2026-04-27 01:19:49 +01:00
Philipinho 2b4a9b8a00 refactor(base): rename baseId methods to pageId in repos and BasePropertyService 2026-04-27 01:18:32 +01:00
Philipinho a2917bad6d feat(base): create() now allocates an is_base=true page via PageService 2026-04-27 01:16:48 +01:00
Philipinho ccdf2343f2 refactor(base): rename baseId to pageId in BaseViewRepo 2026-04-27 01:10:56 +01:00
Philipinho cbed118c11 refactor(base): rename baseId to pageId in BaseRowRepo 2026-04-27 01:10:29 +01:00
Philipinho 0f9dee4b28 refactor(base): rename baseId to pageId in BasePropertyRepo 2026-04-27 01:08:59 +01:00
Philipinho 0257f03003 refactor(base): rewrite BaseRepo over pages (is_base + base_schema_version) 2026-04-27 01:06:19 +01:00
Philipinho 731fa45672 chore(db): drop Base entity type aliases (table no longer exists) 2026-04-27 01:04:05 +01:00
Philipinho 2b05d1520b chore(db): regenerate Kysely types after bases-as-pages migration 2026-04-27 01:01:41 +01:00
Philipinho 24a70e48da fix(db): add pending_type columns to recreated base_properties table 2026-04-27 00:59:36 +01:00
Philipinho a847c2121c feat(db): add is_base flag to pages, drop bases table, recreate base_* with page_id 2026-04-27 00:53:44 +01:00
Philipinho 137c02a10f feat(base): sticky table header so columns stay visible while scrolling
Pins the header row to the top of the gridWrapper scroll viewport, with
the pinned-left corner cell stacking above pinned body cells at the
top-left intersection. The trailing add-column button gets the same
sticky treatment so it doesn't drift away from the row.

Subtle bit: `position: sticky` confines an element to its containing
block. The previous subgrid `.headerRow` wrapper was 34px tall, so
sticky cells could only travel 34px before scrolling out with the
wrapper. Switching the wrapper to `display: contents` lets the cells
become direct grid children of `.grid` (full table height) so sticky
travel matches the scroll range. role="row" survives display:contents
in modern browsers.
2026-04-25 01:05:20 +01:00
Philipinho be79b7159c feat(base): warm row count query on base load, gated on user hydrate
Mounts useBaseRowsCountQuery alongside the rows query so the count is
fetched eagerly and the cache is warm by the time the toolbar consumes
it. Gating on `currentUser` (not just `base`) ensures the persisted
view-draft has hydrated from localStorage before the first count fires
— otherwise a post-refresh count races ahead of the user's saved
filter and ships without it.
2026-04-25 01:05:11 +01:00
Philipinho 18222d1142 fix(base): escalate fuzzy filter and search counts to capped-exact
Postgres has no per-expression stats for `cells->>'uuid' ILIKE '%…%'`,
`search_text ILIKE`, or `search_tsv @@`, so EXPLAIN Plan Rows falls
back to a default selectivity and is off by orders of magnitude — a
contains filter on a 10k-row base was reporting ~150 against thousands
of real matches. Auto-route any request whose filter tree contains a
contains/ncontains/startsWith/endsWith op or a search term to the
capped-exact path, even when the caller asked for an estimate.
2026-04-25 01:05:02 +01:00
Philipinho 72fc93dcc1 perf(base): batch page-cell resolution via microtask loader
Per-cell useResolvedPages([id]) calls each mounted with a unique
React Query key, so a grid with 20 page-typed cells fired 20 requests on
first paint. A shared loader now accumulates incoming ids within a
microtask, fires a single POST for the union, and fans the subset each
caller asked for back to them. Cells keep their own cache entry + null
handling; they just share the underlying network call.

Also renames /bases/pages/resolve → /bases/pages/expand — the old name
collided with other "resolve" semantics in the codebase.
2026-04-24 12:11:41 +01:00
Philipinho 89ee3714ac feat(base): add /bases/rows/count with estimate and capped-exact modes
Row-count display on a filtered view shouldn't force a full COUNT(*) on
every list fetch. New endpoint returns either an EXPLAIN-plan estimate
(default, ~1ms, no execution) or a LIMIT-capped exact count that short-
circuits to `{ capped: true }` once the match set passes EXACT_COUNT_CAP.
Clients call it in parallel with the rows query so the grid still paints
at its own pace.

- DTO + repo.countEstimate/countExact reusing the list predicate shape
- service picks the mode; controller mirrors the list Read ability check
- client hook keyed by filter/search/exact so a "show exact" toggle
  doesn't clobber the estimate cache
2026-04-24 12:11:29 +01:00
Philipinho b9d8bf948c fix(base): strip empty filter groups at the query boundary
The view-draft layer stores `{op: 'and', children: []}` as an explicit
"override baseline with no predicates" marker. That payload was leaking
into /bases/rows requests once local filter/sort drafts were enabled —
harmless server-side (buildWhere maps an empty group to TRUE) but it
destabilised the React Query key and cluttered request payloads. Normalise
empty groups to undefined at the hook level.
2026-04-24 12:11:02 +01:00
Philipinho f7ea6e8fd3 fix(base): hide soft-deleted properties from base info payload
The withProperties subquery hydrating /bases/info was missing a
`deleted_at IS NULL` filter, so after a delete the socket-echo
invalidation refetched and the just-deleted column rehydrated on the
originating client and never dropped on others.
2026-04-24 12:10:22 +01:00
Philipinho dcff8d3c53 fix(base): mirror filter-clear fix for sorts so deleting the last sort sticks 2026-04-24 03:04:51 +01:00
Philipinho 2db43788d5 feat(base): auto-suffix fallback property names to avoid collisions 2026-04-24 02:54:03 +01:00
Philipinho 3bfdae7990 feat(base): insert palette items at cursor and refocus editor 2026-04-24 02:47:12 +01:00
Philipinho 464bd701ba feat(base): enforce unique property names per base 2026-04-24 02:34:38 +01:00
Philipinho 8c0071ee23 fix(base-formula): point client exports at source so Vite can detect ESM named exports 2026-04-24 02:28:23 +01:00
Philipinho 3962ccdc29 feat(base): tighten formula editor spacing and pill styling 2026-04-24 02:25:33 +01:00
Philipinho 7a254a9412 feat(base): redesign formula editor popover with polished header, pills, and accordion 2026-04-24 02:15:08 +01:00
Philipinho 9808791db4 feat(base-formula): add add/subtract/multiply/divide/pow/sqrt/sum/mean/median functions 2026-04-24 02:10:23 +01:00
Philipinho f99450f04a fix formula 2026-04-24 01:33:14 +01:00
Philipinho 82705ce3bd fix(base-formula): resolve package via dist to keep server build output layout 2026-04-24 00:51:40 +01:00
Philipinho 3eb7c9b1d4 feat(base): render formula cells with error badge support 2026-04-24 00:35:57 +01:00
Philipinho 28fed815ba feat(base): add formula editor popover with live parse and palette 2026-04-24 00:35:26 +01:00
Philipinho 48d77a2b53 feat(base): add Formula entry to the property type picker 2026-04-24 00:33:38 +01:00
Philipinho 46f9292c05 feat(base): subscribe to formula WS events on client 2026-04-24 00:29:23 +01:00
Philipinho 230c4e35f0 feat(base): emit formula-related WS events 2026-04-24 00:27:52 +01:00
Philipinho e729e77bda chore(base): note formula bulk-write threshold hook for future bulk endpoint 2026-04-24 00:27:06 +01:00
Philipinho 89e2d0d62f feat(base): compile and cycle-check formulas on property save, enqueue recompute on dep changes 2026-04-24 00:25:50 +01:00