| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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" }; |
|
|
| |
| |
| |
| |
| |
| |
| function List({ title, fields }: { title: string; fields: Plan["fields"] }) { |
| if (!fields.length) return null; |
| return ( |
| <div className="autox-preset-list"> |
| <p className="autox-preset-head"> |
| {title} <span className="autox-preset-n">{fields.length}</span> |
| </p> |
| <div className="autox-preset-chips"> |
| {fields.map((f) => ( |
| <span className="autox-preset-chip" key={f.key} title={`${f.key} Β· ${f.type}`}> |
| {f.label} |
| </span> |
| ))} |
| </div> |
| </div> |
| ); |
| } |
|
|
| export default function PresetPlan({ table }: { table: string }) { |
| const [load, setLoad] = useState<Load>({ phase: "idle" }); |
|
|
| useEffect(() => { |
| if (!table) { |
| setLoad({ phase: "idle" }); |
| return; |
| } |
| const ac = new AbortController(); |
| setLoad({ phase: "loading" }); |
| getPresetPlan(table, ac.signal) |
| .then((plan) => setLoad({ phase: "ready", plan })) |
| .catch((e) => { |
| if ((e as Error)?.name === "AbortError") return; |
| setLoad({ phase: "error" }); |
| }); |
| return () => ac.abort(); |
| }, [table]); |
|
|
| |
| |
| |
| |
| if (!table || load.phase === "idle") return null; |
|
|
| if (load.phase === "loading") { |
| return ( |
| <p className="auto-note" role="status"> |
| <span className="lp-spin" aria-label="Loading" /> |
| </p> |
| ); |
| } |
|
|
| |
| |
| |
| if (load.phase === "error") { |
| return <p className="auto-note">Could not read this database's columns just now.</p>; |
| } |
|
|
| const { plan } = load; |
| return ( |
| <div className="autox-preset"> |
| {/* |
| β THREE STATES, AND THE FIRST TWO ARE DIFFERENT FACTS. A database that does not exist yet |
| (R10's spawn-on-save moment β the action names a table nobody has made) is not the same as |
| one that exists and shares none of the columns, even though both render an empty "already |
| here" list. The server answers `exists` precisely so this line does not have to infer it |
| from a length. |
| */} |
| {!plan.exists ? ( |
| <p className="auto-hint"> |
| This database does not exist yet. Saving makes it, with these columns. |
| </p> |
| ) : null} |
| <List title="Already in this database" fields={plan.willUse} /> |
| <List title="Will be created" fields={plan.willCreate} /> |
| {/* Both lists empty on a table that DOES exist means the server offered no preset set at |
| all. Saying nothing here would leave the panel looking like it failed to load. */} |
| {plan.exists && !plan.willUse.length && !plan.willCreate.length ? ( |
| <p className="auto-note">This server offered no preset columns.</p> |
| ) : null} |
| </div> |
| ); |
| } |
|
|