feat(frontend): suggested-first ordering + filter box in the schema-linking columns modal

Wide tables (e.g. 116 columns, 3 suggested) made curation a scroll hunt. Now the
modal lists suggested columns first (stable sort on the descriptor flag, so
toggling never reorders rows) and adds a filter box matching name + description,
with a "shown/total" count. Selection stays keyed by column name, so the response
column order is unchanged (catalog order). Applies to read-only (excluded) tables too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 23:29:21 +02:00
committed by Marco Pancotti
co-authored by Claude Opus 4.8
parent d942635085
commit 9fe1c9321b
2 changed files with 99 additions and 3 deletions
@@ -46,3 +46,62 @@ test("readOnly renders no checkboxes and no bold", () => {
expect(screen.getByText("cod_paz")).toBeInTheDocument();
expect(screen.getByText("cod_paz").className).not.toContain("font-bold");
});
const wide: SchemaTable = {
id: "t",
name: "t",
kind: "promote",
columns: [
{ name: "aaa", description: "alfa", suggested: false },
{ name: "zzz_key", description: "chiave", suggested: true },
{ name: "bbb", description: "Codice beta", suggested: false },
],
};
test("suggested columns are listed first, then catalog order (stable)", () => {
render(
<SchemaColumnsDialog
table={wide}
open
readOnly={false}
selected={new Set()}
onToggle={() => {}}
onClose={() => {}}
/>
);
const order = screen.getAllByRole("checkbox").map((cb) => cb.getAttribute("aria-label"));
expect(order).toEqual(["zzz_key", "aaa", "bbb"]);
});
test("filter narrows visible columns by name", async () => {
render(
<SchemaColumnsDialog
table={wide}
open
readOnly={false}
selected={new Set()}
onToggle={() => {}}
onClose={() => {}}
/>
);
await userEvent.type(screen.getByRole("textbox", { name: /filter/i }), "zzz");
const order = screen.getAllByRole("checkbox").map((cb) => cb.getAttribute("aria-label"));
expect(order).toEqual(["zzz_key"]);
expect(screen.queryByText("aaa")).toBeNull();
});
test("filter matches the description too", async () => {
render(
<SchemaColumnsDialog
table={wide}
open
readOnly={false}
selected={new Set()}
onToggle={() => {}}
onClose={() => {}}
/>
);
await userEvent.type(screen.getByRole("textbox", { name: /filter/i }), "codice");
const order = screen.getAllByRole("checkbox").map((cb) => cb.getAttribute("aria-label"));
expect(order).toEqual(["bbb"]);
});