// --------------------------------------------------------------------------- // automation/PresetPlan.tsx — WAVE 25 item 4 (ruling R2b, contract C1): // WHICH COLUMNS THIS WILL USE, AND WHICH IT WILL CREATE. // // The owner's words: *"since this is a global fields all tenant use its really // just appending it and adding it to the custom database"* — so the Create // record action's configuration has to SHOW the two lists before anything is // spent, on whatever database that action names, including a hand-made one. // // ⛔ IT RENDERS THE SERVER'S ANSWER AND COMPUTES NOTHING (C1: "the client // renders this; it does not compute it"). Diffing the preset set against a // table's columns here would be a second implementation of `ut_ensure`'s merge // rule — and it would be wrong exactly when the two lists differ, which is the // only case this panel exists to answer. // // ⚠ ITS OWN FILE, AND THAT IS THE BUILDER'S LAW BEING KEPT RATHER THAN BENT. // `AutomationBuilder` renders SYNCHRONOUSLY from what it was handed (C14 leg 1 // — the ghost fix: a view that can be in two shapes shows you the wrong one). // This panel genuinely needs a fetch, so it owns one, keeps a FIXED-SHAPE // skeleton while it is in flight, and never changes the shape of anything above // it. Exactly the split the Board already makes. // --------------------------------------------------------------------------- import { useEffect, useState } from "react"; import { getPresetPlan } from "./automationApi"; import type { PresetPlan as Plan } from "./automationApi"; type Load = | { phase: "idle" } | { phase: "loading" } | { phase: "ready"; plan: Plan } | { phase: "error" }; /** * ⚠ ONE LINE PER LIST, NOT A TOUR (DESIGN.md 4 / R13). The panel says what will happen and shows * the column names; it does not explain what a preset is, why the set is shared across tenants, * or what enrichment does. Each of those has a home — the action's own `detail`, the field's grey * machine-owned mark, the run log — and repeating them here is the paragraph nobody reads. */ function List({ title, fields }: { title: string; fields: Plan["fields"] }) { if (!fields.length) return null; return (
{title} {fields.length}
); } // ⚠ HONEST, AND IT DOES NOT GUESS. A failed fetch is not "no columns will be created" — that // would be a specific, checkable claim about the user's database, invented to keep a panel // tidy ([[no-unverifiable-aggregates]]). It says the server did not answer. if (load.phase === "error") { return
Could not read this database's columns just now.
; } const { plan } = load; return (This database does not exist yet. Saving makes it, with these columns.
) : null}This server offered no preset columns.
) : null}