From f1af1f909b387ae12a10f1b534bf6a529ea42505 Mon Sep 17 00:00:00 2001 From: User Date: Wed, 15 Jul 2026 15:15:56 +0200 Subject: [PATCH] style(frontend): tighten CTE plan vertical rhythm --- frontend/src/viewers/CtePlanViewer.test.tsx | 37 ++++++++-------- frontend/src/viewers/CtePlanViewer.tsx | 48 ++++++++++----------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/frontend/src/viewers/CtePlanViewer.test.tsx b/frontend/src/viewers/CtePlanViewer.test.tsx index 925513a7..aeab867d 100644 --- a/frontend/src/viewers/CtePlanViewer.test.tsx +++ b/frontend/src/viewers/CtePlanViewer.test.tsx @@ -68,19 +68,15 @@ test("renders strategy, question, and a chain strip with CTE names in order", () expect(screen.getAllByText("impianti_recenti").length).toBeGreaterThan(0); }); -test("uses compact vertical and responsive lateral CTE card padding", () => { +test("uses compact CTE section rhythm with moderate lateral padding", () => { const { container } = render(); - for (const header of container.querySelectorAll('[data-slot="card-header"]')) { - expect(header).toHaveClass("px-3", "py-2", "sm:px-4", "[&.border-b]:pb-2"); - expect(header).not.toHaveClass("p-4", "sm:p-5", "sm:[&.border-b]:pb-5"); + expect(header).toHaveClass("gap-2", "px-3", "py-2", "sm:px-4", "[&.border-b]:pb-2"); + expect(header).not.toHaveClass("gap-3", "p-4", "sm:p-5"); } for (const content of container.querySelectorAll('[data-slot="card-content"]')) { - expect(content).toHaveClass("px-3", "py-2", "sm:px-4"); - expect(content).not.toHaveClass("p-4", "sm:p-5"); - } - for (const card of container.querySelectorAll('[data-slot="card"]')) { - expect(card).toHaveClass("shadow-none"); + expect(content).toHaveClass("gap-3", "px-3", "py-2", "sm:px-4"); + expect(content).not.toHaveClass("gap-5", "p-4", "sm:p-5"); } }); @@ -142,7 +138,7 @@ test("groups filters in one bordered divided list with accessible padded rows", expect(list).toHaveClass("border", "divide-y"); for (const filter of filters) { expect(filter.parentElement).toBe(list); - expect(filter).toHaveClass("px-3", "py-2", "sm:px-4"); + expect(filter).toHaveClass("px-3", "py-1", "sm:px-4"); expect(filter).not.toHaveClass("p-3", "sm:p-4"); } lists.push(list!); @@ -161,22 +157,23 @@ test("renders rationale as a plain top-divided section", () => { expect(rationale).not.toHaveClass("border-l-2", "bg-primary/5", "rounded-lg"); }); -test("uses the same compact padding for table rows and rationale dividers", () => { +test("compacts table, filter, detail, and rationale rows", () => { render(); const card = getCteCard("pazienti_idonei"); - const tableName = within(card).getByText("pazienti"); - expect(tableName.parentElement).toHaveClass("px-3", "py-2", "sm:px-4"); - expect(tableName.parentElement).not.toHaveClass("p-3", "sm:p-4"); + const tableRow = within(card).getByText("pazienti").parentElement; + expect(tableRow).toHaveClass("px-3", "py-1", "sm:px-4"); - const filterRationale = within(card).getByText("Solo pazienti in follow-up").parentElement; - expect(filterRationale).toHaveClass("pt-2"); - expect(filterRationale).not.toHaveClass("pt-3"); + const filter = within(card).getByRole("group", { name: "Filter 1" }); + expect(filter).toHaveClass("space-y-2", "px-3", "py-1", "sm:px-4"); + expect(filter.firstElementChild).toHaveClass("gap-2"); + const filterDetails = within(card).getByText("Solo pazienti in follow-up").parentElement; + expect(filterDetails).toHaveClass("gap-y-1", "pt-1"); - const cteRationale = within(card) + const rationale = within(card) .getByText("Base della catena: riduce il volume prima dei join") .closest("section"); - expect(cteRationale).toHaveClass("border-t", "pt-2"); - expect(cteRationale).not.toHaveClass("pt-4"); + expect(rationale).toHaveClass("pt-1"); + expect(within(rationale!).getByText("Rationale")).toHaveClass("mb-1"); }); test("shows 'no dependencies' for a CTE with an empty depends_on", () => { diff --git a/frontend/src/viewers/CtePlanViewer.tsx b/frontend/src/viewers/CtePlanViewer.tsx index 4e95c051..53e5138e 100644 --- a/frontend/src/viewers/CtePlanViewer.tsx +++ b/frontend/src/viewers/CtePlanViewer.tsx @@ -16,34 +16,34 @@ function FilterRow({ filter, index }: { filter: CtePlanFilter; index: number })
-
+

Column

- + {filter.column}

Operator

- + {filter.op}

Value

- + {filter.value}
{(filter.description || filter.rationale) && ( -
+
{filter.description && ( <> Description -

+

{filter.description}

@@ -51,7 +51,7 @@ function FilterRow({ filter, index }: { filter: CtePlanFilter; index: number }) {filter.rationale && ( <> Rationale -

+

{filter.rationale}

@@ -67,25 +67,25 @@ function CteCard({ cte, total }: { cte: CtePlanCte; total: number }) { return ( - +
CTE {cte.index}/{total} -

+

{cte.name}

{cte.purpose && ( -

+

{cte.purpose}

)}
- -
+ +
-

Depends on

+

Depends on

{dependsOn.length ? (
{dependsOn.map((dependency) => ( @@ -99,7 +99,7 @@ function CteCard({ cte, total }: { cte: CtePlanCte; total: number }) { {cte.keys && cte.keys.length > 0 && (
-

Keys

+

Keys

{cte.keys.map((key) => ( {key} @@ -111,18 +111,18 @@ function CteCard({ cte, total }: { cte: CtePlanCte; total: number }) { {cte.tables && cte.tables.length > 0 && (
-

Tables

+

Tables

{cte.tables.map((table) => (
- + {table.name} {table.description && ( -

+

{table.description}

)} @@ -134,7 +134,7 @@ function CteCard({ cte, total }: { cte: CtePlanCte; total: number }) { {cte.filters && cte.filters.length > 0 && (
-

Filters

+

Filters

{cte.filters.map((f, i) => ( @@ -145,7 +145,7 @@ function CteCard({ cte, total }: { cte: CtePlanCte; total: number }) { {cte.output_columns && cte.output_columns.length > 0 && (
-

Output columns

+

Output columns

{cte.output_columns.map((column) => ( {column} @@ -155,9 +155,9 @@ function CteCard({ cte, total }: { cte: CtePlanCte; total: number }) { )} {cte.rationale && ( -
-

Rationale

-

+

+

Rationale

+

{cte.rationale}