feat: add metadata catalog cleanup commands

This commit is contained in:
Codex
2026-08-28 00:37:43 +02:00
parent 79c4c925b5
commit 58ee9cffe4
19 changed files with 942 additions and 66 deletions
@@ -181,6 +181,59 @@ test.each(synchronizationScopes)(
},
);
test("selected database Actions confirms and deletes catalog tables for the full selection", async () => {
const user = userEvent.setup();
let cleanupBody: unknown;
const second = makeDatabase({
id: "44444444-4444-4444-8444-444444444444",
workspaceId: "radiology",
workspaceName: "Radiology",
databaseName: "radiology",
});
server.use(http.post("/api/catalog/databases/metadata-cleanup", async ({ request }) => {
cleanupBody = await request.json();
return HttpResponse.json({ tables: 8, columns: 42, relationships: 5 });
}));
renderPage({ rows: [makeDatabase(), second] });
const firstRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
const secondRow = await screen.findByRole("row", { name: /Radiology/ });
await user.click(within(firstRow).getByRole("checkbox"));
await user.click(within(secondRow).getByRole("checkbox"));
await user.click(screen.getByRole("button", { name: "Actions" }));
expect(await screen.findByRole("menuitem", { name: "Delete all tables" })).toBeEnabled();
expect(screen.getByRole("menuitem", { name: "Delete all relationships" })).toBeEnabled();
await user.click(screen.getByRole("menuitem", { name: "Delete all tables" }));
expect(screen.getByText("Delete all catalog tables for 2 databases?")).toBeVisible();
expect(screen.getByText(/database configurations and source databases are unchanged/i)).toBeVisible();
expect(cleanupBody).toBeUndefined();
await user.click(within(secondRow).getByRole("checkbox"));
expect(screen.queryByText(/Delete all catalog tables for/)).not.toBeInTheDocument();
expect(cleanupBody).toBeUndefined();
await user.click(within(secondRow).getByRole("checkbox"));
await user.click(screen.getByRole("button", { name: "Actions" }));
await user.click(await screen.findByRole("menuitem", { name: "Delete all tables" }));
await waitFor(() => expect(screen.getByRole("button", { name: "Delete catalog tables" })).toHaveFocus());
await user.keyboard("{Escape}");
await waitFor(() => expect(screen.getByRole("button", { name: "Actions" })).toHaveFocus());
await user.click(screen.getByRole("button", { name: "Actions" }));
await user.click(await screen.findByRole("menuitem", { name: "Delete all tables" }));
await user.click(screen.getByRole("button", { name: "Delete catalog tables" }));
await waitFor(() => expect(cleanupBody).toEqual({
databaseIds: [
"11111111-1111-4111-8111-111111111111",
"44444444-4444-4444-8444-444444444444",
],
target: "tables",
}));
await waitFor(() => expect(screen.queryByText("2 selected")).not.toBeInTheDocument());
await waitFor(() => expect(screen.getByRole("textbox", { name: "Search databases" })).toHaveFocus());
});
test("presents completed synchronization steps as success and skips unneeded confirmation", async () => {
const user = userEvent.setup();
const run = {
@@ -580,7 +633,7 @@ test("filters catalog tables as the operator types", async () => {
});
});
test("selected table exposes a direct Synchronize columns action and sends its id", async () => {
test("selected table Actions exposes cleanup commands and sends synchronization ids", async () => {
const user = userEvent.setup();
let startBody: unknown;
const run = makeSyncRun("columns", [patientsTable.id]);
@@ -601,10 +654,11 @@ test("selected table exposes a direct Synchronize columns action and sends its i
const tableRow = await screen.findByRole("row", { name: /patients/ });
await user.click(within(tableRow).getByRole("checkbox"));
const synchronizeColumns = screen.getByRole("button", { name: "Synchronize columns" });
expect(synchronizeColumns).toBeVisible();
await user.click(screen.getByRole("button", { name: "Actions" }));
const synchronizeColumns = await screen.findByRole("menuitem", { name: "Synchronize columns" });
expect(synchronizeColumns).toBeEnabled();
expect(screen.queryByRole("button", { name: "Actions" })).not.toBeInTheDocument();
expect(screen.getByRole("menuitem", { name: "Delete all columns" })).toBeEnabled();
expect(screen.getByRole("menuitem", { name: "Delete all relationships" })).toBeEnabled();
await user.click(synchronizeColumns);
await waitFor(() => expect(startBody).toEqual({
@@ -615,6 +669,54 @@ test("selected table exposes a direct Synchronize columns action and sends its i
await waitFor(() => expect(screen.queryByText("1 selected")).not.toBeInTheDocument());
});
test("selected table Actions confirms and deletes incoming and outgoing relationships", async () => {
const user = userEvent.setup();
let cleanupBody: unknown;
server.use(
http.get("/api/catalog/databases/:databaseId/tables", () => HttpResponse.json([patientsTable])),
http.post("/api/catalog/databases/:databaseId/tables/metadata-cleanup", async ({ request }) => {
cleanupBody = await request.json();
return HttpResponse.json({ tables: 0, columns: 0, relationships: 2 });
}),
);
const { client } = renderPage({
rows: [makeDatabase({ connectionStatus: "reachable", testedVersion: 3 })],
});
const unselectedColumnQuery = [
"catalog-columns",
patientsTable.databaseId,
"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
] as const;
client.setQueryData(unselectedColumnQuery, []);
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
await user.click(screen.getByRole("tab", { name: "Tables" }));
const tableRow = await screen.findByRole("row", { name: /patients/ });
await user.click(within(tableRow).getByRole("checkbox"));
await user.click(screen.getByRole("button", { name: "Actions" }));
await user.click(await screen.findByRole("menuitem", { name: "Delete all relationships" }));
expect(screen.getByText("Delete all relationships for 1 table?")).toBeVisible();
expect(screen.getByText(/incoming and outgoing relationships/i)).toBeVisible();
expect(cleanupBody).toBeUndefined();
await user.click(within(tableRow).getByRole("checkbox"));
expect(screen.queryByText("Delete all relationships for 1 table?")).not.toBeInTheDocument();
expect(cleanupBody).toBeUndefined();
await user.click(within(tableRow).getByRole("checkbox"));
await user.click(screen.getByRole("button", { name: "Actions" }));
await user.click(await screen.findByRole("menuitem", { name: "Delete all relationships" }));
await user.click(screen.getByRole("button", { name: "Delete relationships" }));
await waitFor(() => expect(cleanupBody).toEqual({
tableIds: [patientsTable.id],
target: "relationships",
}));
await waitFor(() => expect(screen.queryByText("1 selected")).not.toBeInTheDocument());
expect(client.getQueryState(unselectedColumnQuery)?.isInvalidated).toBe(true);
await waitFor(() => expect(screen.getByRole("textbox", { name: "Search tables" })).toHaveFocus());
});
test("navigates purely from a database to its tables and edits review metadata", async () => {
const user = userEvent.setup();
let patchBody: unknown;