Files
windmill/backend/migrations/20260724094737_runnables_sort_indexes.up.sql
Ruben Fiszel 71b7135cf2 feat: multiple homepage sort orders via an efficient merged runnables endpoint (#10297)
Adds recently-updated / oldest / name A-Z / name Z-A sort orders to the homepage (WIN-2236), produced server-side by a new merged, index-backed, keyset-paginated GET /w/{workspace}/runnables/list so a chosen order is globally correct across scripts + flows + apps and stays efficient on large workspaces.

- Backend: UNION ALL of script/flow/app ordered by index (Merge Append + LIMIT); keyset (sort_key, path, kind, tiebreak) cursor; per-branch LIMIT bounds correlated projections; starred-first pinning; RLS + scope-token filters in SQL. Archived view returns the latest row per path. Migration adds time + lowered-name indexes (built CONCURRENTLY).
- Frontend: server-side sort/kind/owner filters + hybrid search (instant client + on-demand server pagination); file-explorer tree with every folder and your user namespace as lazy-loaded top-level nodes (per-owner "Load more", nested subfolders, bounded "expand all", in-place re-sort without collapse or flicker); the client sorts by the server fetch ordinal to reproduce the endpoint's exact order; empty state distinguishes an empty workspace from too-narrow filters.

Reviewed clean by Claude and Pi (good to merge) and Codex (mergeable).
2026-07-24 23:16:10 +02:00

27 lines
1.3 KiB
SQL

-- Indexes backing the unified homepage runnables listing so the merged,
-- keyset-paginated query stays an index scan (Merge Append + LIMIT) even on big
-- workspaces, for both the time orders and the name orders.
--
-- `archived` is the second key so the default (archived = false) and the
-- "Only archived" views each seek their own slice and still get the sort key
-- ordered within it, instead of one view scanning past the other's rows. Apps
-- have no archived column and are excluded from the archived view.
-- Time orders.
CREATE INDEX IF NOT EXISTS index_script_on_workspace_created_at
ON script (workspace_id, archived, created_at DESC);
CREATE INDEX IF NOT EXISTS index_flow_on_workspace_edited_at
ON flow (workspace_id, archived, edited_at DESC);
-- Name orders sort on the lowered summary-or-path expression, so a matching
-- expression index makes that order presorted instead of a full sort per page.
CREATE INDEX IF NOT EXISTS index_script_on_workspace_name
ON script (workspace_id, archived, lower(COALESCE(NULLIF(summary, ''), path)));
CREATE INDEX IF NOT EXISTS index_flow_on_workspace_name
ON flow (workspace_id, archived, lower(COALESCE(NULLIF(summary, ''), path)));
CREATE INDEX IF NOT EXISTS index_app_on_workspace_name
ON app (workspace_id, lower(COALESCE(NULLIF(summary, ''), path)));