fix: harden reviewer workflow and memory handling
This commit is contained in:
@@ -46,6 +46,56 @@ test("uses memory-specific selection copy without changing selected ids", async
|
||||
expect(onRespond).toHaveBeenCalledWith({ id: "u-memory", kind: "multiselect", choices: ["recommended"] });
|
||||
});
|
||||
|
||||
test("shows the exact content and provenance for every memory option", () => {
|
||||
render(
|
||||
<MultiselectWidget
|
||||
descriptor={{
|
||||
id: "u-memory-content",
|
||||
widget: "multiselect",
|
||||
options: [
|
||||
{
|
||||
id: "mem-42",
|
||||
label: "paziente attivo",
|
||||
detail: "flag_attivo = TRUE",
|
||||
rationale: "Confermato dal reviewer",
|
||||
meta: { question_context: "Conta i pazienti attivi" },
|
||||
},
|
||||
],
|
||||
}}
|
||||
onRespond={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText("flag_attivo = TRUE")).toBeInTheDocument();
|
||||
expect(screen.getByText(/Confermato dal reviewer/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Conta i pazienti attivi/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("renders memory detail as human-friendly Markdown", () => {
|
||||
render(
|
||||
<MultiselectWidget
|
||||
descriptor={{
|
||||
id: "u-memory-markdown",
|
||||
widget: "multiselect",
|
||||
selection_label: "memory da applicare",
|
||||
options: [
|
||||
{
|
||||
id: "mem-0042",
|
||||
label: "Paziente attivo",
|
||||
detail: "**Definizione**\n\n- `flag_attivo = TRUE`\n- record non annullato",
|
||||
},
|
||||
],
|
||||
}}
|
||||
onRespond={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText("Definizione").tagName).toBe("STRONG");
|
||||
expect(screen.getByText("flag_attivo = TRUE").tagName).toBe("CODE");
|
||||
expect(screen.getByText("record non annullato").closest("li")).not.toBeNull();
|
||||
expect(screen.queryByText("**Definizione**")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("select-all checks all options", async () => {
|
||||
const onRespond = vi.fn();
|
||||
render(
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import type { WidgetProps } from "./types";
|
||||
import { ReservedControls } from "./ReservedControls";
|
||||
|
||||
@@ -56,7 +58,24 @@ export function MultiselectWidget({ descriptor, onRespond }: WidgetProps) {
|
||||
checked={checked.has(o.id)}
|
||||
onChange={() => toggle(o.id)}
|
||||
/>
|
||||
<span>{o.label}</span>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block font-medium">{o.label}</span>
|
||||
{o.detail && (
|
||||
<div className="thot-prose mt-1 text-sm text-muted-foreground">
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>{o.detail}</ReactMarkdown>
|
||||
</div>
|
||||
)}
|
||||
{o.rationale && (
|
||||
<span className="mt-1 block text-xs text-foreground/80">
|
||||
Motivo: {o.rationale}
|
||||
</span>
|
||||
)}
|
||||
{typeof o.meta?.question_context === "string" && o.meta.question_context && (
|
||||
<span className="mt-1 block text-xs text-muted-foreground">
|
||||
Domanda di contesto: {o.meta.question_context}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -33,6 +33,13 @@ const descriptor: WidgetDescriptor = {
|
||||
reserved: ["back", "exit", "other"],
|
||||
};
|
||||
|
||||
test("starts include rows checked and exclude rows unchecked even for legacy payloads", () => {
|
||||
render(<SchemaLinkingGateWidget descriptor={descriptor} onRespond={vi.fn()} />);
|
||||
|
||||
expect(screen.getByRole("checkbox", { name: "dim_patient" })).toBeChecked();
|
||||
expect(screen.getByRole("checkbox", { name: "fact_sostituzione" })).not.toBeChecked();
|
||||
});
|
||||
|
||||
test("Confirm emits enacted tables with suggested columns (catalog order)", async () => {
|
||||
const onRespond = vi.fn();
|
||||
render(<SchemaLinkingGateWidget descriptor={descriptor} onRespond={onRespond} />);
|
||||
@@ -42,7 +49,7 @@ test("Confirm emits enacted tables with suggested columns (catalog order)", asyn
|
||||
kind: "schema-linking",
|
||||
tables: [
|
||||
{ id: "t-pat", enacted: true, columns: ["cod_paz"] },
|
||||
{ id: "x-sub", enacted: true },
|
||||
{ id: "x-sub", enacted: false },
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -60,7 +67,7 @@ test("selecting a column in the modal adds it to the response", async () => {
|
||||
kind: "schema-linking",
|
||||
tables: [
|
||||
{ id: "t-pat", enacted: true, columns: ["cod_paz", "nome"] },
|
||||
{ id: "x-sub", enacted: true },
|
||||
{ id: "x-sub", enacted: false },
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -75,7 +82,7 @@ test("declining a table's enact checkbox drops its columns", async () => {
|
||||
kind: "schema-linking",
|
||||
tables: [
|
||||
{ id: "t-pat", enacted: false },
|
||||
{ id: "x-sub", enacted: true },
|
||||
{ id: "x-sub", enacted: false },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ReservedControls } from "./ReservedControls";
|
||||
export function SchemaLinkingGateWidget({ descriptor, onRespond }: WidgetProps) {
|
||||
const tables: SchemaTable[] = descriptor.tables ?? [];
|
||||
const [enacted, setEnacted] = useState<Set<string>>(
|
||||
() => new Set(tables.filter((t) => t.recommended).map((t) => t.id))
|
||||
() => new Set(tables.filter((t) => t.kind === "promote" && t.recommended).map((t) => t.id))
|
||||
);
|
||||
const [selected, setSelected] = useState<Map<string, Set<string>>>(() => {
|
||||
const m = new Map<string, Set<string>>();
|
||||
|
||||
Reference in New Issue
Block a user