Files
windmill/backend/migrations/20260614075900_dedup_folder_labels.up.sql
Ruben Fiszel eba70ce735 dedup folder labels to prevent each_key_duplicate crash (#9565)
Folder labels are exposed verbatim as `inherited_labels` (via the
`folder_labels` SQL function) and rendered in keyed `{#each}` blocks that
throw Svelte's `each_key_duplicate` on a repeated key, crashing the list
views. The UI dedups labels on entry, but API / CLI / git-sync writes do
not, so a folder.yaml with `labels: [foo, foo]` persists duplicates.

- Dedup on write in create_folder and update_folder (order-preserving).
- Make folder_labels() dedup on read so it is resilient regardless of how a
  row was populated, plus a one-time cleanup of already-persisted duplicates
  so direct folder.labels reads (folder list, editor) are safe too.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 10:18:05 +02:00

34 lines
1.3 KiB
PL/PgSQL

-- Folder labels are exposed verbatim as `inherited_labels` (via folder_labels) and
-- rendered in keyed `{#each}` blocks in the UI, which throw `each_key_duplicate` on a
-- repeated key. The write paths now dedup, but make the read resilient regardless of
-- how a row was populated, and clean up any duplicates already persisted.
-- Dedup while preserving first-seen order.
CREATE OR REPLACE FUNCTION folder_labels(w_id text, item_path text) RETURNS text[]
LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public AS $$
SELECT (
SELECT array_agg(l ORDER BY first_ord)
FROM (
SELECT u.l, min(u.ord) AS first_ord
FROM unnest(f.labels) WITH ORDINALITY AS u(l, ord)
GROUP BY u.l
) deduped
)
FROM folder f
WHERE f.workspace_id = w_id AND item_path LIKE 'f/%' AND f.name = split_part(item_path, '/', 2)
$$;
-- One-time cleanup of rows that already contain duplicate labels, so direct reads of
-- folder.labels (folder list, editor) are also safe.
UPDATE folder
SET labels = (
SELECT array_agg(l ORDER BY first_ord)
FROM (
SELECT u.l, min(u.ord) AS first_ord
FROM unnest(labels) WITH ORDINALITY AS u(l, ord)
GROUP BY u.l
) deduped
)
WHERE labels IS NOT NULL
AND cardinality(labels) <> (SELECT count(DISTINCT x) FROM unnest(labels) AS x);