diff --git a/src/components/giellie/approval-card.test.tsx b/src/components/giellie/approval-card.test.tsx
index 529ed67..8946233 100644
--- a/src/components/giellie/approval-card.test.tsx
+++ b/src/components/giellie/approval-card.test.tsx
@@ -94,3 +94,82 @@ describe("ApprovalCard", () => {
expect((screen.getByRole("button", { name: /reject/i }) as HTMLButtonElement).disabled).toBe(true);
});
});
+
+
+describe("the stock quantity tool renders a table", () => {
+ it("lists the sku, description and qty", () => {
+ render(
+ ,
+ );
+ expect(screen.getByText("ABC-123")).toBeTruthy();
+ expect(screen.getByText("Bolt M12")).toBeTruthy();
+ expect(screen.getByText("50")).toBeTruthy();
+ expect(screen.getByText(/new quantity on hand/i)).toBeTruthy();
+ expect(document.body.textContent).not.toMatch(/"lines"/);
+ });
+
+ it("says when the quantities are being added instead of set", () => {
+ render(
+ ,
+ );
+ expect(screen.getByText(/adding these quantities/i)).toBeTruthy();
+ });
+
+ it("leaves other tools as JSON", () => {
+ render(
+ ,
+ );
+ expect(document.body.textContent).toMatch(/"status"/);
+ });
+});
diff --git a/src/components/giellie/approval-card.tsx b/src/components/giellie/approval-card.tsx
index 7e7fcf8..300afce 100644
--- a/src/components/giellie/approval-card.tsx
+++ b/src/components/giellie/approval-card.tsx
@@ -1,9 +1,62 @@
"use client";
import { Check, Mail, X } from "lucide-react";
+import type { ReactNode } from "react";
import { Button } from "@/components/ui/button";
import type { PendingAction } from "@/lib/giellie-types";
+type StockQuantityLine = { sku?: string; description?: string; qty?: number };
+
+/**
+ * The stock quantity tool is the one tool whose input is a list the
+ * operator has to read line by line. JSON is not reviewable at that
+ * size, so it gets a table. Every other tool keeps raw JSON.
+ */
+export function renderToolInput(toolName: string, input: unknown): ReactNode {
+ if (toolName === "stock_items.set_quantities" && input && typeof input === "object") {
+ const payload = input as { mode?: unknown; lines?: unknown };
+ const mode = typeof payload.mode === "string" ? payload.mode : "";
+ const lines = Array.isArray(payload.lines) ? (payload.lines as StockQuantityLine[]) : [];
+ if (lines.length > 0) {
+ return (
+
+
+ {mode === "add"
+ ? "Adding these quantities to the current stock."
+ : "Setting these as the new quantity on hand."}
+
+
+
+
+
+ | SKU |
+ Description |
+ Qty |
+
+
+
+ {lines.map((line, i) => (
+
+ | {line.sku ?? "—"} |
+ {line.description ?? "—"} |
+ {line.qty ?? "—"} |
+
+ ))}
+
+
+
+
+ );
+ }
+ }
+ // Every other tool keeps its raw JSON exactly as it was.
+ return (
+
+ {JSON.stringify(input, null, 2)}
+
+ );
+}
+
interface Props {
pending: PendingAction;
busy: boolean;
@@ -39,9 +92,7 @@ export function ApprovalCard({ pending, busy, onDecide }: Props) {
)}
-
- {JSON.stringify(tu.input, null, 2)}
-
+ {renderToolInput(tu.name, tu.input)}
))}