@ai-matrx/records-ui 0.78.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -820,7 +820,7 @@ function RelationPicker({ field, value, onChange, disabled, id, className, allow
820
820
  )),
821
821
  disabled ? null : /* @__PURE__ */ jsxs2(Popover, { open, onOpenChange: setOpen, children: [
822
822
  /* @__PURE__ */ jsx3(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(Button2, { id, type: "button", size: "sm", variant: "outline", "aria-label": `Pick for ${fieldName(field)}`, children: picked.length === 0 ? "Pick" : "Change" }) }),
823
- /* @__PURE__ */ jsxs2(PopoverContent, { className: "w-64 p-1", align: "start", children: [
823
+ /* @__PURE__ */ jsxs2(PopoverContent, { sizing: "content", className: "p-1", align: "start", children: [
824
824
  /* @__PURE__ */ jsx3(
825
825
  BasicInput2,
826
826
  {
@@ -844,6 +844,7 @@ function RelationPicker({ field, value, onChange, disabled, id, className, allow
844
844
  {
845
845
  type: "button",
846
846
  onClick: () => toggle(row.id),
847
+ title: titleOf(row.id),
847
848
  className: cn2(
848
849
  "w-full truncate rounded px-2 py-1 text-left text-xs hover:bg-muted",
849
850
  picked.includes(row.id) ? "bg-accent text-accent-foreground" : ""
@@ -889,6 +890,7 @@ function RelationPicker({ field, value, onChange, disabled, id, className, allow
889
890
  type: "button",
890
891
  size: "sm",
891
892
  variant: "ghost",
893
+ title: search.trim() !== "" ? `Create \u201C${search.trim()}\u201D` : `New ${targetWord}`,
892
894
  className: "w-full justify-start text-xs",
893
895
  disabled: busy,
894
896
  onClick: () => {
@@ -898,7 +900,7 @@ function RelationPicker({ field, value, onChange, disabled, id, className, allow
898
900
  setCreating(true);
899
901
  }
900
902
  },
901
- children: search.trim() !== "" ? `Create \u201C${search.trim()}\u201D` : `New ${targetWord}`
903
+ children: /* @__PURE__ */ jsx3("span", { className: "block w-full truncate text-left", children: search.trim() !== "" ? `Create \u201C${search.trim()}\u201D` : `New ${targetWord}` })
902
904
  }
903
905
  ),
904
906
  createRefusal ? /* @__PURE__ */ jsx3("p", { className: "p-2 text-xs text-destructive", children: createRefusal }) : null
@@ -1159,10 +1161,17 @@ function RecordChip({
1159
1161
  onRemove,
1160
1162
  className
1161
1163
  }) {
1162
- return /* @__PURE__ */ jsxs3(Badge, { variant: "secondary", className: cn3("gap-1 text-[11px]", className), children: [
1163
- title,
1164
- onRemove ? /* @__PURE__ */ jsx4("button", { type: "button", onClick: onRemove, "aria-label": `Remove ${title}`, className: "opacity-60 hover:opacity-100", children: "\xD7" }) : null
1165
- ] });
1164
+ return (
1165
+ // A chip carries a RECORD'S OWN TITLE, which nobody here chose the length of —
1166
+ // "Marisol Okonkwo 418 Calle Puerto Vallarta, Camarillo" is an ordinary customer
1167
+ // name. So it caps at its container and ends in an ellipsis with the whole name in
1168
+ // its tooltip, rather than being cut mid-word by whatever box it landed in
1169
+ // (lane FIX-14, 2026-09-22).
1170
+ /* @__PURE__ */ jsxs3(Badge, { variant: "secondary", className: cn3("max-w-full gap-1 text-[11px]", className), title, children: [
1171
+ /* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate", children: title }),
1172
+ onRemove ? /* @__PURE__ */ jsx4("button", { type: "button", onClick: onRemove, "aria-label": `Remove ${title}`, className: "shrink-0 opacity-60 hover:opacity-100", children: "\xD7" }) : null
1173
+ ] })
1174
+ );
1166
1175
  }
1167
1176
 
1168
1177
  // src/PersonPicker.tsx
@@ -1308,7 +1317,7 @@ function PersonPicker({ field, value, onChange, disabled, id, className }) {
1308
1317
  children: picked.length === 0 ? "Pick a person" : "Change"
1309
1318
  }
1310
1319
  ) }),
1311
- /* @__PURE__ */ jsxs4(PopoverContent2, { className: "w-64 p-1", align: "start", children: [
1320
+ /* @__PURE__ */ jsxs4(PopoverContent2, { sizing: "content", className: "p-1", align: "start", children: [
1312
1321
  /* @__PURE__ */ jsx5(
1313
1322
  BasicInput4,
1314
1323
  {
@@ -2650,7 +2659,7 @@ var colorFromTheValue = (_fieldKey, value) => {
2650
2659
  };
2651
2660
 
2652
2661
  // src/Grid.tsx
2653
- import { Button as Button8, Skeleton as Skeleton2, cn as cn9 } from "@ai-matrx/design-system";
2662
+ import { Button as Button8, ConfirmDialog, Skeleton as Skeleton2, cn as cn9 } from "@ai-matrx/design-system";
2654
2663
 
2655
2664
  // src/Enrich.tsx
2656
2665
  import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo8, useState as useState8 } from "react";
@@ -3456,6 +3465,9 @@ function Grid({
3456
3465
  [client, host, refreshEnrich]
3457
3466
  );
3458
3467
  const [pastePlan, setPastePlan] = useState10(null);
3468
+ const [deleting, setDeleting] = useState10(null);
3469
+ const [deleteBusy, setDeleteBusy] = useState10(false);
3470
+ const [archived, setArchived] = useState10(null);
3459
3471
  const choiceOptions = useRef4(/* @__PURE__ */ new Map());
3460
3472
  const loadChoiceOptions = useCallback6(
3461
3473
  async (fieldList) => {
@@ -3743,6 +3755,21 @@ function Grid({
3743
3755
  /* @__PURE__ */ jsx13("div", { className: "ml-auto flex items-center gap-1", children: toolbarActions })
3744
3756
  ] }),
3745
3757
  records.error ? /* @__PURE__ */ jsx13(RefusalNotice, { error: records.error }) : null,
3758
+ archived ? /* @__PURE__ */ jsxs9(
3759
+ "p",
3760
+ {
3761
+ "data-records-archived-notice": "",
3762
+ role: "status",
3763
+ className: "flex items-center gap-2 rounded border border-border bg-muted/40 px-2 py-1 text-xs",
3764
+ children: [
3765
+ /* @__PURE__ */ jsxs9("span", { children: [
3766
+ archived,
3767
+ " is archived. Nothing was destroyed \u2014 it is in this table\u2019s Archived items, where Restore brings it back."
3768
+ ] }),
3769
+ /* @__PURE__ */ jsx13(Button8, { size: "sm", variant: "ghost", className: "ml-auto h-6", onClick: () => setArchived(null), children: "Dismiss" })
3770
+ ]
3771
+ }
3772
+ ) : null,
3746
3773
  editing.rowError ? /* @__PURE__ */ jsx13(
3747
3774
  RefusalNotice,
3748
3775
  {
@@ -3859,11 +3886,13 @@ function Grid({
3859
3886
  }
3860
3887
  ) : null,
3861
3888
  canWrite && mayWriteRow(row.id) ? /* @__PURE__ */ jsx13(
3862
- DeleteRecordButton,
3889
+ Button8,
3863
3890
  {
3864
- row,
3865
- retentionDays: table.data?.retention_days ?? null,
3866
- onDelete: () => editing.remove(row.id)
3891
+ size: "sm",
3892
+ variant: "ghost",
3893
+ title: "Delete this record",
3894
+ onClick: () => setDeleting(row),
3895
+ children: "Delete"
3867
3896
  }
3868
3897
  ) : null
3869
3898
  ] })
@@ -3906,7 +3935,32 @@ function Grid({
3906
3935
  onPage: setPage
3907
3936
  }
3908
3937
  )
3909
- ] })
3938
+ ] }),
3939
+ /* @__PURE__ */ jsx13(
3940
+ ConfirmDialog,
3941
+ {
3942
+ open: deleting !== null,
3943
+ onOpenChange: (next) => {
3944
+ if (!next && !deleteBusy) setDeleting(null);
3945
+ },
3946
+ variant: "destructive",
3947
+ title: `Delete ${deleting ? recordNameIn(table.data, deleting.document ?? {}) : "this record"}?`,
3948
+ description: table.data?.retention_days ? `It leaves the table and waits in Archived items. Nothing is destroyed: Restore brings it back, for ${table.data.retention_days} days.` : "It leaves the table and waits in Archived items. Nothing is destroyed: Restore brings it back.",
3949
+ confirmLabel: "Delete",
3950
+ cancelLabel: "Keep",
3951
+ busy: deleteBusy,
3952
+ onConfirm: async () => {
3953
+ const row = deleting;
3954
+ if (!row) return;
3955
+ const name = recordNameIn(table.data, row.document ?? {});
3956
+ setDeleteBusy(true);
3957
+ const failed = await editing.remove(row.id);
3958
+ setDeleteBusy(false);
3959
+ setDeleting(null);
3960
+ if (!failed) setArchived(name);
3961
+ }
3962
+ }
3963
+ )
3910
3964
  ] }) });
3911
3965
  }
3912
3966
  function columnLabel(fields, columnId) {
@@ -3926,42 +3980,6 @@ function AddFieldButton({ onClick }) {
3926
3980
  }
3927
3981
  );
3928
3982
  }
3929
- function DeleteRecordButton({
3930
- row,
3931
- retentionDays,
3932
- onDelete
3933
- }) {
3934
- const [asking, setAsking] = useState10(false);
3935
- if (!asking) {
3936
- return /* @__PURE__ */ jsx13(
3937
- Button8,
3938
- {
3939
- size: "sm",
3940
- variant: "ghost",
3941
- title: "Delete this record",
3942
- onClick: () => setAsking(true),
3943
- children: "Delete"
3944
- }
3945
- );
3946
- }
3947
- return /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-1 text-[11px]", children: [
3948
- /* @__PURE__ */ jsx13("span", { className: "text-muted-foreground", children: retentionDays ? `Removes it from the table. Restorable for ${retentionDays} days.` : "Removes it from the table. It can be restored from the record's history." }),
3949
- /* @__PURE__ */ jsx13(
3950
- Button8,
3951
- {
3952
- size: "sm",
3953
- variant: "destructive",
3954
- onClick: () => {
3955
- setAsking(false);
3956
- void onDelete();
3957
- },
3958
- children: "Delete"
3959
- }
3960
- ),
3961
- /* @__PURE__ */ jsx13(Button8, { size: "sm", variant: "ghost", onClick: () => setAsking(false), children: "Keep" }),
3962
- /* @__PURE__ */ jsx13("span", { className: "sr-only", children: row.id })
3963
- ] });
3964
- }
3965
3983
  function Pager({
3966
3984
  page,
3967
3985
  pageSize,
@@ -4234,7 +4252,7 @@ function FilePicker({
4234
4252
  }
4235
4253
 
4236
4254
  // src/ImportWizard.tsx
4237
- import { useCallback as useCallback8, useMemo as useMemo10, useState as useState13 } from "react";
4255
+ import { useCallback as useCallback8, useEffect as useEffect8, useMemo as useMemo10, useState as useState13 } from "react";
4238
4256
  import { useFields as useFields5, useRecordsClient as useRecordsClient6, useTable as useTable3 } from "@ai-matrx/records/react";
4239
4257
  import {
4240
4258
  importCsv,
@@ -4273,7 +4291,7 @@ async function sha256(bytes) {
4273
4291
  function typeWord(t) {
4274
4292
  return fieldTypeChoice(t)?.label ?? (t === "relation" ? "Points at another table" : t);
4275
4293
  }
4276
- function ImportWizard({ tableId, onDone, className }) {
4294
+ function ImportWizard({ tableId, onDone, onWrote, className }) {
4277
4295
  const client = useRecordsClient6();
4278
4296
  const table = useTable3(tableId);
4279
4297
  const fields = useFields5(tableId);
@@ -4299,6 +4317,46 @@ function ImportWizard({ tableId, onDone, className }) {
4299
4317
  const [columnsAdded, setColumnsAdded] = useState13(null);
4300
4318
  const [show, setShow] = useState13("all");
4301
4319
  const [ledger, setLedger] = useState13(null);
4320
+ const [runs, setRuns] = useState13(null);
4321
+ const [openRun, setOpenRun] = useState13(null);
4322
+ const [runRows, setRunRows] = useState13(null);
4323
+ const [runProblem, setRunProblem] = useState13(null);
4324
+ const loadRuns = useCallback8(async () => {
4325
+ const answered = await client.imports({ table_id: tableId, limit: 10 });
4326
+ if (answered.ok) setRuns(answered.data);
4327
+ }, [client, tableId]);
4328
+ useEffect8(() => {
4329
+ void loadRuns();
4330
+ }, [loadRuns]);
4331
+ const openRefusals = useCallback8(
4332
+ async (importId) => {
4333
+ setRunProblem(null);
4334
+ if (openRun === importId) {
4335
+ setOpenRun(null);
4336
+ setRunRows(null);
4337
+ return;
4338
+ }
4339
+ setOpenRun(importId);
4340
+ setRunRows(null);
4341
+ const answered = await client.importReport({
4342
+ import_id: importId,
4343
+ state: "refused",
4344
+ limit: 200
4345
+ });
4346
+ if (!answered.ok) {
4347
+ setRunProblem(answered.error.message);
4348
+ return;
4349
+ }
4350
+ setRunRows({
4351
+ import_id: answered.data.import_id,
4352
+ rows: answered.data.rows,
4353
+ kept: answered.data.kept,
4354
+ total: answered.data.total,
4355
+ note: answered.data.note
4356
+ });
4357
+ },
4358
+ [client, openRun]
4359
+ );
4302
4360
  const declared = fields.data ?? [];
4303
4361
  const take = useCallback8(
4304
4362
  async (file) => {
@@ -4432,8 +4490,9 @@ function ImportWizard({ tableId, onDone, className }) {
4432
4490
  final: true
4433
4491
  });
4434
4492
  setPhase("done");
4435
- onDone?.(finished.data.rows_written);
4436
- }, [client, dedupeKey, fileBytes, fileHash, fileName, format, mapping, onDuplicate, onDone, plan, rows, tableId, unmapped]);
4493
+ onWrote?.(finished.data.rows_written);
4494
+ void loadRuns();
4495
+ }, [client, dedupeKey, fileBytes, fileHash, fileName, format, loadRuns, mapping, onDuplicate, onWrote, plan, rows, tableId, unmapped]);
4437
4496
  const counts = useMemo10(() => {
4438
4497
  let landed = 0;
4439
4498
  let duplicate = 0;
@@ -4710,7 +4769,73 @@ function ImportWizard({ tableId, onDone, className }) {
4710
4769
  proposals.length > 0 ? /* @__PURE__ */ jsx16("ul", { className: "flex flex-col gap-0.5", children: proposals.map((p) => /* @__PURE__ */ jsxs12("li", { className: "text-muted-foreground", children: [
4711
4770
  /* @__PURE__ */ jsx16("span", { className: "font-medium text-foreground", children: p.column }),
4712
4771
  p.state === "waiting" ? " is waiting in the approvals inbox." : p.state === "accepted" ? " was added as a column." : p.state === "ignored" ? " was left out." : p.state === "refused" ? ` could not be added: ${p.reason ?? ""}` : ` \u2014 ${p.state}`
4713
- ] }, p.column)) }) : null
4772
+ ] }, p.column)) }) : null,
4773
+ phase === "done" ? /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", children: [
4774
+ /* @__PURE__ */ jsx16(Button11, { size: "sm", onClick: () => onDone?.(ledger?.written ?? 0), children: "Done" }),
4775
+ (ledger?.refused ?? 0) > 0 ? /* @__PURE__ */ jsxs12("span", { className: "text-muted-foreground", children: [
4776
+ "The ",
4777
+ ledger?.refused,
4778
+ " row",
4779
+ ledger?.refused === 1 ? "" : "s",
4780
+ " that ",
4781
+ ledger?.refused === 1 ? "was" : "were",
4782
+ " refused",
4783
+ " ",
4784
+ "are kept with this import \u2014 open them again from the list of imports below, with the store's reason and the line from your file on each."
4785
+ ] }) : null
4786
+ ] }) : null
4787
+ ] }) : null,
4788
+ runs && runs.length > 0 ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
4789
+ /* @__PURE__ */ jsx16(Separator2, {}),
4790
+ /* @__PURE__ */ jsx16("p", { className: "font-medium", children: "Imports into this table" }),
4791
+ /* @__PURE__ */ jsx16("ul", { className: "flex flex-col gap-1", children: runs.map((r) => /* @__PURE__ */ jsxs12("li", { className: "flex flex-col gap-1", children: [
4792
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", children: [
4793
+ /* @__PURE__ */ jsx16("span", { className: "font-medium", children: r.source_name ?? "a file" }),
4794
+ /* @__PURE__ */ jsxs12("span", { className: "text-muted-foreground", children: [
4795
+ new Date(r.opened_at).toLocaleString(),
4796
+ " \xB7 ",
4797
+ r.rows_written,
4798
+ " landed \xB7",
4799
+ " ",
4800
+ r.rows_duplicate,
4801
+ " already here \xB7 ",
4802
+ r.rows_refused,
4803
+ " refused, of ",
4804
+ r.rows_seen,
4805
+ " row",
4806
+ r.rows_seen === 1 ? "" : "s",
4807
+ " offered"
4808
+ ] }),
4809
+ r.rows_refused > 0 ? /* @__PURE__ */ jsx16(
4810
+ "button",
4811
+ {
4812
+ type: "button",
4813
+ className: "underline underline-offset-2",
4814
+ "aria-expanded": openRun === r.import_id,
4815
+ onClick: () => void openRefusals(r.import_id),
4816
+ children: openRun === r.import_id ? "hide the rows it refused" : `see the ${r.rows_refused} row${r.rows_refused === 1 ? "" : "s"} it refused`
4817
+ }
4818
+ ) : null
4819
+ ] }),
4820
+ openRun === r.import_id ? runProblem ? /* @__PURE__ */ jsx16("p", { className: "text-destructive", children: runProblem }) : runRows ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
4821
+ runRows.note ? /* @__PURE__ */ jsx16("p", { className: "text-muted-foreground", children: runRows.note }) : null,
4822
+ /* @__PURE__ */ jsx16("div", { className: "max-h-64 overflow-auto rounded border", children: /* @__PURE__ */ jsxs12("table", { className: "w-full", children: [
4823
+ /* @__PURE__ */ jsx16("thead", { className: "sticky top-0 bg-muted", children: /* @__PURE__ */ jsxs12("tr", { children: [
4824
+ /* @__PURE__ */ jsx16("th", { className: "px-2 py-1 text-left font-medium", children: "Line in your file" }),
4825
+ /* @__PURE__ */ jsx16("th", { className: "px-2 py-1 text-left font-medium", children: "What happened" }),
4826
+ /* @__PURE__ */ jsx16("th", { className: "px-2 py-1 text-left font-medium", children: "The row in your file" })
4827
+ ] }) }),
4828
+ /* @__PURE__ */ jsx16("tbody", { children: runRows.rows.map((row, i) => {
4829
+ const source = row.source ?? {};
4830
+ return /* @__PURE__ */ jsxs12("tr", { className: "border-t align-top", children: [
4831
+ /* @__PURE__ */ jsx16("td", { className: "px-2 py-1", children: String(row.row ?? "") }),
4832
+ /* @__PURE__ */ jsx16("td", { className: "px-2 py-1 text-destructive", children: String(row.reason ?? "") }),
4833
+ /* @__PURE__ */ jsx16("td", { className: "max-w-96 px-2 py-1 text-muted-foreground", children: Object.entries(source).map(([k, v]) => `${k}: ${String(v ?? "")}`).join(" \xB7 ") })
4834
+ ] }, `${r.import_id}-${String(row.row ?? i)}`);
4835
+ }) })
4836
+ ] }) })
4837
+ ] }) : /* @__PURE__ */ jsx16("p", { className: "text-muted-foreground", children: "Reading the rows this import refused\u2026" }) : null
4838
+ ] }, r.import_id)) })
4714
4839
  ] }) : null,
4715
4840
  table.error ? /* @__PURE__ */ jsx16(RefusalNotice, { error: table.error }) : null
4716
4841
  ] });
@@ -4929,6 +5054,9 @@ var ROLLUP_OPERATIONS = ROLLUP_AGG_VALUES.map((value) => ({
4929
5054
  value,
4930
5055
  label: ROLLUP_AGG_LABEL[value]
4931
5056
  }));
5057
+ var FORMULA_SEPARATOR_LABEL = "Joined by";
5058
+ var EDITING_A_WORKED_OUT_COLUMN = "This column works out its answer from other columns. Which columns it uses, and what joins them, cannot be changed on this screen yet \u2014 remove it and add it again to change them.";
5059
+ var FORMULA_DEFAULT_SEPARATOR = " \u2014 ";
4932
5060
  var FORMULA_OPERATIONS = FORMULA_OP_VALUES.map((value) => ({
4933
5061
  value,
4934
5062
  label: FORMULA_OP_LABEL[value],
@@ -4965,8 +5093,9 @@ function FieldEditor({ tableId, field, onSaved, onCancel, onRemoved, className }
4965
5093
  const [of, setOf] = useState15(String(field?.config?.["of"] ?? ""));
4966
5094
  const [relationTarget, setRelationTarget] = useState15(String(field?.relation_target ?? ""));
4967
5095
  const [display, setDisplay] = useState15(field?.display ?? null);
4968
- const [formulaOp, setFormulaOp] = useState15("concat");
4969
- const [formulaFields, setFormulaFields] = useState15([]);
5096
+ const [formulaOp, setFormulaOp] = useState15(() => formulaOpOf(field));
5097
+ const [formulaFields, setFormulaFields] = useState15(() => formulaFieldIdsOf(field));
5098
+ const [formulaSeparator, setFormulaSeparator] = useState15(() => formulaSeparatorOf(field));
4970
5099
  const [askingToRemove, setAskingToRemove] = useState15(false);
4971
5100
  const [notLanded, setNotLanded] = useState15(false);
4972
5101
  const others = useMemo12(
@@ -5040,7 +5169,7 @@ function FieldEditor({ tableId, field, onSaved, onCancel, onRemoved, className }
5040
5169
  ...type === "datetime" ? { kind: withTime ? "datetime" : "date" } : {},
5041
5170
  ...type === "lookup" ? { via, pick } : {},
5042
5171
  ...type === "rollup" ? { via, agg, ...agg === "count" ? {} : { of } } : {},
5043
- ...type === "formula" ? { expr: formulaExpression(formulaOp, formulaFields) } : {}
5172
+ ...type === "formula" ? { expr: formulaExpression(formulaOp, formulaFields, formulaSeparator) } : {}
5044
5173
  };
5045
5174
  const written = await mutation.declare({ table_id: tableId, spec });
5046
5175
  if (written === null) return;
@@ -5098,6 +5227,7 @@ function FieldEditor({ tableId, field, onSaved, onCancel, onRemoved, className }
5098
5227
  /* @__PURE__ */ jsx18("p", { className: "text-[11px] text-muted-foreground", children: editing ? "What a column holds cannot be changed here \u2014 every value already saved would have to be converted. Add a new column and move the values across." : choice?.explanation ?? "" })
5099
5228
  ] })
5100
5229
  ] }),
5230
+ editing && type === "formula" ? /* @__PURE__ */ jsx18("p", { className: "text-[11px] text-muted-foreground", children: EDITING_A_WORKED_OUT_COLUMN }) : null,
5101
5231
  !editing || type === "select" || type === "multi_select" || type === "relation" ? /* @__PURE__ */ jsx18(
5102
5232
  TypeQuestions,
5103
5233
  {
@@ -5126,6 +5256,8 @@ function FieldEditor({ tableId, field, onSaved, onCancel, onRemoved, className }
5126
5256
  setFormulaOp,
5127
5257
  formulaFields,
5128
5258
  setFormulaFields,
5259
+ formulaSeparator,
5260
+ setFormulaSeparator,
5129
5261
  relations,
5130
5262
  others,
5131
5263
  existingOptionsTable: Boolean(field?.options_table_id ?? field?.config?.["options_table_id"])
@@ -5310,10 +5442,30 @@ function startingType(field) {
5310
5442
  if (fieldTypeChoice(kind)) return kind;
5311
5443
  return "text";
5312
5444
  }
5313
- function formulaExpression(op, fieldIds) {
5445
+ function formulaExpression(op, fieldIds, separator) {
5314
5446
  const args = fieldIds.filter((id) => id !== "").map((id) => ({ field: id }));
5315
- if (args.length === 0) return { op, args: [{ const: "" }] };
5316
- return { op, args };
5447
+ const joined = op === "concat" && separator !== "" ? { separator } : {};
5448
+ if (args.length === 0) return { op, ...joined, args: [{ const: "" }] };
5449
+ return { op, ...joined, args };
5450
+ }
5451
+ function formulaExprOf(field) {
5452
+ const expr = field?.config?.["expr"];
5453
+ return expr !== null && typeof expr === "object" ? expr : null;
5454
+ }
5455
+ function formulaOpOf(field) {
5456
+ const op = formulaExprOf(field)?.["op"];
5457
+ return typeof op === "string" && op !== "" ? op : "concat";
5458
+ }
5459
+ function formulaFieldIdsOf(field) {
5460
+ const args = formulaExprOf(field)?.["args"];
5461
+ if (!Array.isArray(args)) return [];
5462
+ return args.map((a) => a !== null && typeof a === "object" ? a["field"] : void 0).filter((id) => typeof id === "string" && id !== "");
5463
+ }
5464
+ function formulaSeparatorOf(field) {
5465
+ const expr = formulaExprOf(field);
5466
+ if (expr === null) return FORMULA_DEFAULT_SEPARATOR;
5467
+ const sep = expr["separator"];
5468
+ return typeof sep === "string" ? sep : "";
5317
5469
  }
5318
5470
  function TypeQuestions(props) {
5319
5471
  const { type } = props;
@@ -5452,7 +5604,21 @@ function TypeQuestions(props) {
5452
5604
  );
5453
5605
  }) }),
5454
5606
  /* @__PURE__ */ jsx18("p", { className: "text-[11px] text-muted-foreground", children: "In the order you pick them. Columns are remembered by which column they are, so renaming one never breaks this." })
5455
- ] })
5607
+ ] }),
5608
+ props.formulaOp === "concat" ? /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1", children: [
5609
+ /* @__PURE__ */ jsx18(Label4, { className: "text-xs", children: FORMULA_SEPARATOR_LABEL }),
5610
+ /* @__PURE__ */ jsx18(
5611
+ BasicInput5,
5612
+ {
5613
+ value: props.formulaSeparator,
5614
+ "aria-label": FORMULA_SEPARATOR_LABEL,
5615
+ placeholder: "\u2014",
5616
+ className: "max-w-[10rem]",
5617
+ onChange: (e) => props.setFormulaSeparator(e.target.value)
5618
+ }
5619
+ ),
5620
+ /* @__PURE__ */ jsx18("p", { className: "text-[11px] text-muted-foreground", children: "What goes between the columns. Leave it empty to run them straight together." })
5621
+ ] }) : null
5456
5622
  ] });
5457
5623
  }
5458
5624
  return null;
@@ -5488,7 +5654,7 @@ function ValueOnTheOtherSide({
5488
5654
  }
5489
5655
 
5490
5656
  // src/StageRules.tsx
5491
- import { useCallback as useCallback9, useEffect as useEffect8, useMemo as useMemo13, useState as useState17 } from "react";
5657
+ import { useCallback as useCallback9, useEffect as useEffect9, useMemo as useMemo13, useState as useState17 } from "react";
5492
5658
  import { useFields as useFields7, useRecordsClient as useRecordsClient8, useTable as useTable5 } from "@ai-matrx/records/react";
5493
5659
  import { BasicInput as BasicInput7, BasicTextarea as BasicTextarea3, Button as Button15, Separator as Separator5, Skeleton as Skeleton3, cn as cn15 } from "@ai-matrx/design-system";
5494
5660
 
@@ -5847,7 +6013,7 @@ function StageRulesSection({ tableId, stage, className }) {
5847
6013
  if (mode.ok) setEnforcement(mode.data);
5848
6014
  setAsked(true);
5849
6015
  }, [client, tableId]);
5850
- useEffect8(() => {
6016
+ useEffect9(() => {
5851
6017
  void load();
5852
6018
  }, [load]);
5853
6019
  const stages = pipeline?.stages ?? [];
@@ -5858,7 +6024,7 @@ function StageRulesSection({ tableId, stage, className }) {
5858
6024
  () => (fields.data ?? []).map((f) => ({ id: String(f.id), key: f.key, label: fieldName(f), field: f })),
5859
6025
  [fields.data]
5860
6026
  );
5861
- useEffect8(() => {
6027
+ useEffect9(() => {
5862
6028
  if (!draft || !stageKey || !draft.demands || Object.keys(draft.demands).length === 0) {
5863
6029
  setPreview(null);
5864
6030
  setPreviewError(null);
@@ -6297,7 +6463,7 @@ import { useFields as useFields10, useRecord as useRecord2, useRecordsClient as
6297
6463
  import { AlchemyMenu as AlchemyMenu2 } from "@ai-matrx/alchemy/react";
6298
6464
 
6299
6465
  // src/RecordChat.tsx
6300
- import { useEffect as useEffect9, useMemo as useMemo14, useState as useState19 } from "react";
6466
+ import { useEffect as useEffect10, useMemo as useMemo14, useState as useState19 } from "react";
6301
6467
  import { useRecordsClient as useRecordsClient9 } from "@ai-matrx/records/react";
6302
6468
  import { Skeleton as Skeleton4, cn as cn17 } from "@ai-matrx/design-system";
6303
6469
  import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
@@ -6307,7 +6473,7 @@ function RecordChat({ tableId, recordId, className }) {
6307
6473
  const host = useRecordsUi();
6308
6474
  const [scope, setScope] = useState19(null);
6309
6475
  const [error, setError] = useState19(null);
6310
- useEffect9(() => {
6476
+ useEffect10(() => {
6311
6477
  let cancelled = false;
6312
6478
  setScope(null);
6313
6479
  setError(null);
@@ -6424,7 +6590,7 @@ function entriesFor(scope) {
6424
6590
  import { Button as Button19, Separator as Separator8, Skeleton as Skeleton5, cn as cn19 } from "@ai-matrx/design-system";
6425
6591
 
6426
6592
  // src/RecordForm.tsx
6427
- import { useEffect as useEffect11, useMemo as useMemo16, useState as useState21 } from "react";
6593
+ import { useEffect as useEffect12, useMemo as useMemo16, useState as useState21 } from "react";
6428
6594
  import {
6429
6595
  useFields as useFields9,
6430
6596
  useRecord,
@@ -6434,7 +6600,7 @@ import { predictWriteRefusals } from "@ai-matrx/records/core";
6434
6600
  import { Button as Button17, Separator as Separator7, cn as cn18 } from "@ai-matrx/design-system";
6435
6601
 
6436
6602
  // src/systemTable.ts
6437
- import { useEffect as useEffect10, useMemo as useMemo15, useState as useState20 } from "react";
6603
+ import { useEffect as useEffect11, useMemo as useMemo15, useState as useState20 } from "react";
6438
6604
  import { useRecordsClient as useRecordsClient10 } from "@ai-matrx/records/react";
6439
6605
  var inFlight = /* @__PURE__ */ new Map();
6440
6606
  async function ensureSystemTable(client, spec) {
@@ -6567,7 +6733,7 @@ function useSystemTable(spec) {
6567
6733
  const [state, setState] = useState20({ tableId: null, loading: true, error: null });
6568
6734
  const slug = spec.slug;
6569
6735
  const stable = useMemo15(() => spec, [slug]);
6570
- useEffect10(() => {
6736
+ useEffect11(() => {
6571
6737
  let cancelled = false;
6572
6738
  setState({ tableId: null, loading: true, error: null });
6573
6739
  void ensureSystemTable(client, stable).then((result) => {
@@ -6585,7 +6751,7 @@ function useSystemTable(spec) {
6585
6751
  function useRecordVersion(recordId) {
6586
6752
  const client = useRecordsClient10();
6587
6753
  const [version, setVersion] = useState20(null);
6588
- useEffect10(() => {
6754
+ useEffect11(() => {
6589
6755
  let cancelled = false;
6590
6756
  setVersion(null);
6591
6757
  if (!recordId) return;
@@ -6622,7 +6788,7 @@ function RecordForm({
6622
6788
  const [touched, setTouched] = useState21(false);
6623
6789
  const loaded = useRecordVersion(recordId ?? null);
6624
6790
  const loadedVersion = loaded.version;
6625
- useEffect11(() => {
6791
+ useEffect12(() => {
6626
6792
  const document3 = existing.data?.document;
6627
6793
  if (document3) setDraft({ ...document3 });
6628
6794
  }, [existing.data?.record_id, loadedVersion]);
@@ -7051,12 +7217,12 @@ function parseSorts(raw) {
7051
7217
  }
7052
7218
 
7053
7219
  // src/ViewSwitcher.tsx
7054
- import { useEffect as useEffect13, useMemo as useMemo18, useState as useState25 } from "react";
7220
+ import { useEffect as useEffect14, useMemo as useMemo18, useState as useState25 } from "react";
7055
7221
  import { useFields as useFields12, useRecords as useRecords5, useRecordsClient as useRecordsClient13 } from "@ai-matrx/records/react";
7056
7222
  import { Button as Button21, Skeleton as Skeleton7, cn as cn21 } from "@ai-matrx/design-system";
7057
7223
 
7058
7224
  // src/Pipeline.tsx
7059
- import { useCallback as useCallback10, useEffect as useEffect12, useMemo as useMemo17, useRef as useRef6, useState as useState24 } from "react";
7225
+ import { useCallback as useCallback10, useEffect as useEffect13, useMemo as useMemo17, useRef as useRef6, useState as useState24 } from "react";
7060
7226
  import {
7061
7227
  mayDrag,
7062
7228
  useFields as useFields11,
@@ -7105,7 +7271,7 @@ function PipelineBoard({
7105
7271
  const [dragging, setDragging] = useState24(null);
7106
7272
  const [over, setOver] = useState24(null);
7107
7273
  const alive = useRef6(true);
7108
- useEffect12(() => {
7274
+ useEffect13(() => {
7109
7275
  alive.current = true;
7110
7276
  return () => {
7111
7277
  alive.current = false;
@@ -7129,7 +7295,7 @@ function PipelineBoard({
7129
7295
  setWaiting(held.ok ? new Map((held.data ?? []).map((p) => [p.record_id, p])) : /* @__PURE__ */ new Map());
7130
7296
  setColumns(board.ok ? board.data ?? [] : []);
7131
7297
  }, [client, tableId, measure]);
7132
- useEffect12(() => {
7298
+ useEffect13(() => {
7133
7299
  void reload();
7134
7300
  }, [reload]);
7135
7301
  const stageKey = definition?.stage_field ?? null;
@@ -7161,8 +7327,8 @@ function PipelineBoard({
7161
7327
  const asked = await client.pipelineTransitionRefusal({ record_id: recordId, to });
7162
7328
  if (!alive.current) return;
7163
7329
  if (!asked.ok) {
7164
- setError(asked.error);
7165
- setPending({ kind: "none" });
7330
+ setPending({ kind: "clash", recordId, to, error: asked.error });
7331
+ onMoved?.();
7166
7332
  return;
7167
7333
  }
7168
7334
  const verdict = asked.data;
@@ -7175,8 +7341,8 @@ function PipelineBoard({
7175
7341
  const moved = await client.pipelineMove({ record_id: recordId, to });
7176
7342
  if (!alive.current) return;
7177
7343
  if (!moved.ok) {
7178
- setPending({ kind: "none" });
7179
- setError(moved.error);
7344
+ setPending({ kind: "clash", recordId, to, error: moved.error });
7345
+ onMoved?.();
7180
7346
  return;
7181
7347
  }
7182
7348
  const result = moved.data;
@@ -7197,21 +7363,22 @@ function PipelineBoard({
7197
7363
  const moved = await client.pipelineMove({ record_id: recordId, to });
7198
7364
  if (!alive.current) return;
7199
7365
  if (!moved.ok) {
7200
- setPending({ kind: "none" });
7201
- setError(moved.error);
7366
+ setPending({ kind: "clash", recordId, to, error: moved.error });
7367
+ onMoved?.();
7202
7368
  return;
7203
7369
  }
7204
7370
  setPending({ kind: "filed", recordId, to, result: moved.data });
7205
7371
  void reload();
7206
7372
  },
7207
- [client, reload]
7373
+ [client, onMoved, reload]
7208
7374
  );
7209
7375
  const moveWith = useCallback10(
7210
7376
  async (recordId, to, also) => {
7211
7377
  const moved = await client.pipelineMove({ record_id: recordId, to, also });
7212
7378
  if (!alive.current) return;
7213
7379
  if (!moved.ok) {
7214
- setError(moved.error);
7380
+ setPending({ kind: "clash", recordId, to, error: moved.error });
7381
+ onMoved?.();
7215
7382
  return;
7216
7383
  }
7217
7384
  setPending({ kind: "none" });
@@ -7339,6 +7506,16 @@ function Held({
7339
7506
  if (pending.kind === "asking") {
7340
7507
  return /* @__PURE__ */ jsx26("p", { className: "px-2 py-1 text-xs text-muted-foreground", children: "Asking\u2026" });
7341
7508
  }
7509
+ if (pending.kind === "clash") {
7510
+ return /* @__PURE__ */ jsx26(
7511
+ RefusalNotice,
7512
+ {
7513
+ className: "mt-1",
7514
+ error: pending.error,
7515
+ actions: /* @__PURE__ */ jsx26("div", { className: "mt-1", children: /* @__PURE__ */ jsx26(Button20, { size: "sm", variant: "ghost", className: "h-6", onClick: onCancel, children: "Close" }) })
7516
+ }
7517
+ );
7518
+ }
7342
7519
  if (pending.kind === "refused") {
7343
7520
  return /* @__PURE__ */ jsxs22("div", { className: "mt-1 rounded border border-destructive/50 bg-destructive/5 p-2 text-xs", children: [
7344
7521
  /* @__PURE__ */ jsx26("p", { children: pending.verdict.why }),
@@ -7476,7 +7653,7 @@ function useViewRecords(view, pageSize = 200, filter) {
7476
7653
  error: null
7477
7654
  });
7478
7655
  const ruleId = view.ruleId ?? null;
7479
- useEffect13(() => {
7656
+ useEffect14(() => {
7480
7657
  if (!ruleId) return;
7481
7658
  let cancelled = false;
7482
7659
  setRuled({ rows: [], loading: true, error: null });
@@ -7540,7 +7717,7 @@ function ViewSwitcher({
7540
7717
  }) {
7541
7718
  const [layout, setLayout] = useState25(view.layout);
7542
7719
  const [local, setLocal] = useState25({});
7543
- useEffect13(() => {
7720
+ useEffect14(() => {
7544
7721
  setLayout(view.layout);
7545
7722
  setLocal({});
7546
7723
  }, [view.layout, view.name, view.subject]);
@@ -7608,7 +7785,7 @@ function useStageField(tableId) {
7608
7785
  asked: false,
7609
7786
  key: null
7610
7787
  });
7611
- useEffect13(() => {
7788
+ useEffect14(() => {
7612
7789
  let cancelled = false;
7613
7790
  setStage({ asked: false, key: null });
7614
7791
  void client.tableStageField({ table_id: tableId }).then((r) => {
@@ -7877,7 +8054,7 @@ function Card2({
7877
8054
  }
7878
8055
 
7879
8056
  // src/ArchivedView.tsx
7880
- import { useCallback as useCallback11, useEffect as useEffect14, useState as useState26 } from "react";
8057
+ import { useCallback as useCallback11, useEffect as useEffect15, useState as useState26 } from "react";
7881
8058
  import {
7882
8059
  ARCHIVE_LANES,
7883
8060
  ARCHIVE_LANE_LABEL,
@@ -7915,7 +8092,7 @@ function ArchivedView({
7915
8092
  const [error, setError] = useState26(null);
7916
8093
  const [restoring, setRestoring] = useState26(null);
7917
8094
  const [refusal, setRefusal] = useState26(null);
7918
- useEffect14(() => {
8095
+ useEffect15(() => {
7919
8096
  if (laneFromHost) setLane(laneFromHost);
7920
8097
  }, [laneFromHost]);
7921
8098
  const read = useCallback11(async () => {
@@ -7930,7 +8107,7 @@ function ArchivedView({
7930
8107
  }
7931
8108
  setLoading(false);
7932
8109
  }, [client, tableId, lane, pageSize]);
7933
- useEffect14(() => {
8110
+ useEffect15(() => {
7934
8111
  void read();
7935
8112
  }, [read]);
7936
8113
  const pick = (next) => {
@@ -8012,7 +8189,7 @@ function ArchivedView({
8012
8189
  }
8013
8190
 
8014
8191
  // src/ArchivedDisclosure.tsx
8015
- import { useCallback as useCallback12, useEffect as useEffect15, useState as useState27 } from "react";
8192
+ import { useCallback as useCallback12, useEffect as useEffect16, useState as useState27 } from "react";
8016
8193
  import {
8017
8194
  emptyPortalArchiveLine,
8018
8195
  portalConfirmLine,
@@ -8081,7 +8258,7 @@ function ArchivedPortals({
8081
8258
  setError(answered.error);
8082
8259
  }
8083
8260
  }, [client]);
8084
- useEffect15(() => {
8261
+ useEffect16(() => {
8085
8262
  void read();
8086
8263
  }, [read, refreshToken]);
8087
8264
  const restore = async (portal) => {
@@ -8197,7 +8374,7 @@ function ArchivedPortals({
8197
8374
  }
8198
8375
 
8199
8376
  // src/ViewBar.tsx
8200
- import { useCallback as useCallback14, useEffect as useEffect16, useState as useState28 } from "react";
8377
+ import { useCallback as useCallback14, useEffect as useEffect17, useState as useState28 } from "react";
8201
8378
  import { useRecordsClient as useRecordsClient16 } from "@ai-matrx/records/react";
8202
8379
  import { Button as Button24, Input as Input2, Skeleton as Skeleton10, cn as cn24 } from "@ai-matrx/design-system";
8203
8380
 
@@ -8260,10 +8437,10 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, className }) {
8260
8437
  setError(null);
8261
8438
  setViews(mine);
8262
8439
  }, [client, viewTableId, tableId, seed]);
8263
- useEffect16(() => {
8440
+ useEffect17(() => {
8264
8441
  void load();
8265
8442
  }, [load]);
8266
- useEffect16(() => {
8443
+ useEffect17(() => {
8267
8444
  if (!views || views.length === 0) return;
8268
8445
  const chosen = views.find((v) => v.id === (activeViewId ?? active)) ?? views.find((v) => v.isDefault) ?? views[0];
8269
8446
  if (chosen.id !== active) setActive(chosen.id);
@@ -8439,12 +8616,12 @@ function ProposalRow({
8439
8616
  }
8440
8617
 
8441
8618
  // src/ActionInbox.tsx
8442
- import { useCallback as useCallback16, useEffect as useEffect18, useMemo as useMemo20, useRef as useRef8, useState as useState31 } from "react";
8619
+ import { useCallback as useCallback16, useEffect as useEffect19, useMemo as useMemo20, useRef as useRef8, useState as useState31 } from "react";
8443
8620
  import { useRecordsClient as useRecordsClient19 } from "@ai-matrx/records/react";
8444
8621
  import { Badge as Badge9, Button as Button27, Skeleton as Skeleton12, cn as cn27 } from "@ai-matrx/design-system";
8445
8622
 
8446
8623
  // src/ChecklistRunner.tsx
8447
- import { useCallback as useCallback15, useEffect as useEffect17, useMemo as useMemo19, useState as useState30 } from "react";
8624
+ import { useCallback as useCallback15, useEffect as useEffect18, useMemo as useMemo19, useState as useState30 } from "react";
8448
8625
  import { useRecordsClient as useRecordsClient18, useTable as useTable10 } from "@ai-matrx/records/react";
8449
8626
  import { Badge as Badge8, BasicInput as BasicInput9, BasicTextarea as BasicTextarea4, Button as Button26, Skeleton as Skeleton11, cn as cn26 } from "@ai-matrx/design-system";
8450
8627
  import { Fragment as Fragment13, jsx as jsx32, jsxs as jsxs28 } from "react/jsx-runtime";
@@ -8492,10 +8669,10 @@ function ChecklistRunner({
8492
8669
  (held) => held && answered.data.some((r) => r.run_id === held) ? held : answered.data[0]?.run_id ?? null
8493
8670
  );
8494
8671
  }, [client, includeClosed, recordId, runId, tableId]);
8495
- useEffect17(() => {
8672
+ useEffect18(() => {
8496
8673
  void loadRuns();
8497
8674
  }, [loadRuns]);
8498
- useEffect17(() => {
8675
+ useEffect18(() => {
8499
8676
  if (runId) setActiveId(runId);
8500
8677
  }, [runId]);
8501
8678
  const loadSteps = useCallback15(async () => {
@@ -8512,10 +8689,10 @@ function ChecklistRunner({
8512
8689
  setError(null);
8513
8690
  setSteps(answered.data);
8514
8691
  }, [client, activeId]);
8515
- useEffect17(() => {
8692
+ useEffect18(() => {
8516
8693
  void loadSteps();
8517
8694
  }, [loadSteps]);
8518
- useEffect17(() => {
8695
+ useEffect18(() => {
8519
8696
  if (!mayStart || !tableId) return;
8520
8697
  let cancelled = false;
8521
8698
  void client.checklistTemplates({ about_table_id: tableId, limit: 50 }).then((answered) => {
@@ -8741,7 +8918,7 @@ function useMyChecklistSteps(limit = 25) {
8741
8918
  setSteps(held);
8742
8919
  setLoading(false);
8743
8920
  }, [client, limit, me]);
8744
- useEffect17(() => {
8921
+ useEffect18(() => {
8745
8922
  void refresh();
8746
8923
  }, [refresh]);
8747
8924
  return { steps, loading, error, refresh };
@@ -8808,7 +8985,7 @@ function ChecklistsPanel({ tableId, onOpenRecord, className }) {
8808
8985
  if (!r.ok) setRuns([]);
8809
8986
  else setRuns(r.data);
8810
8987
  }, [client, tableId]);
8811
- useEffect17(() => {
8988
+ useEffect18(() => {
8812
8989
  void load();
8813
8990
  }, [load]);
8814
8991
  if (templates === null) return /* @__PURE__ */ jsx32(Skeleton11, { className: cn26("h-40 w-full", className) });
@@ -8954,7 +9131,7 @@ function ChecklistTemplateEditor({
8954
9131
  const [error, setError] = useState30(null);
8955
9132
  const [busy, setBusy] = useState30(false);
8956
9133
  const [loading, setLoading] = useState30(Boolean(templateId));
8957
- useEffect17(() => {
9134
+ useEffect18(() => {
8958
9135
  if (!templateId) return;
8959
9136
  let cancelled = false;
8960
9137
  void client.checklistTemplateShape({ template_id: templateId }).then((answered) => {
@@ -8991,7 +9168,7 @@ function ChecklistTemplateEditor({
8991
9168
  }),
8992
9169
  [aboutTableId, name, rows]
8993
9170
  );
8994
- useEffect17(() => {
9171
+ useEffect18(() => {
8995
9172
  if (spec.steps.length === 0 || spec.name.length === 0) {
8996
9173
  setRefusal(null);
8997
9174
  return;
@@ -9177,7 +9354,7 @@ function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className
9177
9354
  setError(null);
9178
9355
  setItems(result.data);
9179
9356
  }, [client, includeSettled]);
9180
- useEffect18(() => {
9357
+ useEffect19(() => {
9181
9358
  void load();
9182
9359
  }, [load]);
9183
9360
  const shown = useMemo20(() => {
@@ -9185,10 +9362,10 @@ function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className
9185
9362
  if (!tableId) return all;
9186
9363
  return all.filter((i) => i.kind !== "assignment" || i.subject_kind !== "record" || true);
9187
9364
  }, [items, tableId]);
9188
- useEffect18(() => {
9365
+ useEffect19(() => {
9189
9366
  if (cursor >= shown.length) setCursor(Math.max(0, shown.length - 1));
9190
9367
  }, [shown.length, cursor]);
9191
- useEffect18(() => {
9368
+ useEffect19(() => {
9192
9369
  const el = listRef.current?.querySelector(`[data-row="${cursor}"]`);
9193
9370
  el?.scrollIntoView({ block: "nearest" });
9194
9371
  }, [cursor, shown.length]);
@@ -9314,7 +9491,7 @@ function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className
9314
9491
  }
9315
9492
 
9316
9493
  // src/HistoryPanel.tsx
9317
- import { useCallback as useCallback17, useEffect as useEffect19, useRef as useRef9, useState as useState32 } from "react";
9494
+ import { useCallback as useCallback17, useEffect as useEffect20, useRef as useRef9, useState as useState32 } from "react";
9318
9495
  import {
9319
9496
  useFields as useFields14,
9320
9497
  useRecordsClient as useRecordsClient20,
@@ -9342,7 +9519,7 @@ function HistoryPanel({ tableId, recordId, onAskAboutField, className }) {
9342
9519
  setError(null);
9343
9520
  setEntries(answered.data);
9344
9521
  }, [client, recordId]);
9345
- useEffect19(() => {
9522
+ useEffect20(() => {
9346
9523
  void load();
9347
9524
  }, [load]);
9348
9525
  if (error) return /* @__PURE__ */ jsx34(RefusalNotice, { error, className });
@@ -9623,7 +9800,7 @@ function say(value, field) {
9623
9800
  }
9624
9801
 
9625
9802
  // src/CommentThread.tsx
9626
- import { useCallback as useCallback18, useEffect as useEffect20, useMemo as useMemo21, useRef as useRef10, useState as useState33 } from "react";
9803
+ import { useCallback as useCallback18, useEffect as useEffect21, useMemo as useMemo21, useRef as useRef10, useState as useState33 } from "react";
9627
9804
  import {
9628
9805
  useFields as useFields15,
9629
9806
  useRecordsClient as useRecordsClient21,
@@ -9660,10 +9837,10 @@ function CommentThread({ tableId, recordId, fieldKey, className }) {
9660
9837
  mayResolve: answered.data.may_resolve
9661
9838
  });
9662
9839
  }, [client, recordId, showResolved]);
9663
- useEffect20(() => {
9840
+ useEffect21(() => {
9664
9841
  void load();
9665
9842
  }, [load]);
9666
- useEffect20(() => {
9843
+ useEffect21(() => {
9667
9844
  let alive = true;
9668
9845
  if (!host.members) return;
9669
9846
  void host.members().then((roster) => {
@@ -9866,7 +10043,7 @@ function Line({
9866
10043
  }
9867
10044
 
9868
10045
  // src/FieldHistoryPanel.tsx
9869
- import { useCallback as useCallback19, useEffect as useEffect21, useState as useState34 } from "react";
10046
+ import { useCallback as useCallback19, useEffect as useEffect22, useState as useState34 } from "react";
9870
10047
  import {
9871
10048
  useFields as useFields16,
9872
10049
  useRecordsClient as useRecordsClient22,
@@ -9901,7 +10078,7 @@ function FieldHistoryPanel({
9901
10078
  setError(null);
9902
10079
  setRows(answered.data);
9903
10080
  }, [client, tableId, fieldKey, recordId]);
9904
- useEffect21(() => {
10081
+ useEffect22(() => {
9905
10082
  void load();
9906
10083
  }, [load]);
9907
10084
  const label = (fields.data ?? []).find((f) => f.key === fieldKey)?.label || humanize(fieldKey);
@@ -10094,7 +10271,7 @@ function submissionStamp(args) {
10094
10271
  }
10095
10272
 
10096
10273
  // src/PortalBuilder.tsx
10097
- import { useCallback as useCallback20, useEffect as useEffect22, useMemo as useMemo22, useState as useState35 } from "react";
10274
+ import { useCallback as useCallback20, useEffect as useEffect23, useMemo as useMemo22, useState as useState35 } from "react";
10098
10275
  import { useRecordsClient as useRecordsClient23, useTables as useTables3 } from "@ai-matrx/records/react";
10099
10276
  import { BasicInput as BasicInput10, Button as Button31, Checkbox as Checkbox5, Label as Label5, Separator as Separator9, Skeleton as Skeleton16, cn as cn31 } from "@ai-matrx/design-system";
10100
10277
  import { Fragment as Fragment15, jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
@@ -10127,7 +10304,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
10127
10304
  },
10128
10305
  [client, fieldsByTable]
10129
10306
  );
10130
- useEffect22(() => {
10307
+ useEffect23(() => {
10131
10308
  if (!portalId) return;
10132
10309
  void (async () => {
10133
10310
  const answered = await client.portalCard({ portal_id: portalId });
@@ -10141,7 +10318,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
10141
10318
  setClientTableId(answered.data.client_table_id);
10142
10319
  })();
10143
10320
  }, [client, portalId]);
10144
- useEffect22(() => {
10321
+ useEffect23(() => {
10145
10322
  if (!tableId) return;
10146
10323
  setExposures(
10147
10324
  (prev) => prev[tableId] ? prev : {
@@ -10389,7 +10566,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
10389
10566
  }
10390
10567
 
10391
10568
  // src/PortalsPanel.tsx
10392
- import { useCallback as useCallback21, useEffect as useEffect23, useMemo as useMemo23, useState as useState36 } from "react";
10569
+ import { useCallback as useCallback21, useEffect as useEffect24, useMemo as useMemo23, useState as useState36 } from "react";
10393
10570
  import { useRecordsClient as useRecordsClient24 } from "@ai-matrx/records/react";
10394
10571
  import {
10395
10572
  portalArchiveConsequence,
@@ -10481,7 +10658,7 @@ function PortalsPanel({ tableId, className }) {
10481
10658
  setPortals(answered.data);
10482
10659
  setExposures(mapped.ok ? mapped.data : []);
10483
10660
  }, [client]);
10484
- useEffect23(() => {
10661
+ useEffect24(() => {
10485
10662
  void load();
10486
10663
  }, [load]);
10487
10664
  if (portals === null) return /* @__PURE__ */ jsx39(Skeleton17, { className: cn33("h-32 w-full", className) });
@@ -10743,7 +10920,7 @@ function PortalDetail({
10743
10920
  setError(null);
10744
10921
  setCard(answered.data);
10745
10922
  }, [client, portalId]);
10746
- useEffect23(() => {
10923
+ useEffect24(() => {
10747
10924
  void load();
10748
10925
  }, [load]);
10749
10926
  const revoke = useCallback21(
@@ -10936,7 +11113,7 @@ function Preview({
10936
11113
  const [which, setWhich] = useState36(first?.table_id ?? null);
10937
11114
  const [rows, setRows] = useState36(null);
10938
11115
  const [error, setError] = useState36(null);
10939
- useEffect23(() => {
11116
+ useEffect24(() => {
10940
11117
  if (!which) return;
10941
11118
  let cancelled = false;
10942
11119
  setRows(null);
@@ -10982,7 +11159,7 @@ function Invite({ card, onInvited }) {
10982
11159
  const [busy, setBusy] = useState36(false);
10983
11160
  const [said, setSaid] = useState36(null);
10984
11161
  const [error, setError] = useState36(null);
10985
- useEffect23(() => {
11162
+ useEffect24(() => {
10986
11163
  let cancelled = false;
10987
11164
  void client.list({ table_id: card.client_table_id, limit: 200 }).then((answered) => {
10988
11165
  if (cancelled) return;
@@ -11084,7 +11261,7 @@ function Invite({ card, onInvited }) {
11084
11261
  }
11085
11262
 
11086
11263
  // src/DigestScheduler.tsx
11087
- import { useCallback as useCallback22, useEffect as useEffect24, useMemo as useMemo24, useState as useState37 } from "react";
11264
+ import { useCallback as useCallback22, useEffect as useEffect25, useMemo as useMemo24, useState as useState37 } from "react";
11088
11265
  import { useRecordsClient as useRecordsClient25 } from "@ai-matrx/records/react";
11089
11266
  import { BasicInput as BasicInput12, Button as Button34, Checkbox as Checkbox6, Label as Label6, Separator as Separator11, Skeleton as Skeleton18, cn as cn34 } from "@ai-matrx/design-system";
11090
11267
  import { Fragment as Fragment17, jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
@@ -11148,7 +11325,7 @@ function DigestScheduler({
11148
11325
  setMembers([]);
11149
11326
  }
11150
11327
  }, [client, tableId, host]);
11151
- useEffect24(() => {
11328
+ useEffect25(() => {
11152
11329
  void load();
11153
11330
  }, [load]);
11154
11331
  const schedule = useMemo24(() => {
@@ -11390,7 +11567,7 @@ function DigestScheduler({
11390
11567
  }
11391
11568
 
11392
11569
  // src/SubscriptionsPanel.tsx
11393
- import { useCallback as useCallback23, useEffect as useEffect25, useState as useState38 } from "react";
11570
+ import { useCallback as useCallback23, useEffect as useEffect26, useState as useState38 } from "react";
11394
11571
  import { useRecordsClient as useRecordsClient26 } from "@ai-matrx/records/react";
11395
11572
  import { Badge as Badge14, Button as Button35, Skeleton as Skeleton19, Switch as Switch2, cn as cn35 } from "@ai-matrx/design-system";
11396
11573
  import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
@@ -11419,7 +11596,7 @@ function SubscriptionsPanel({ tableId, className }) {
11419
11596
  setError(null);
11420
11597
  setRows(answered.data);
11421
11598
  }, [client, tableId]);
11422
- useEffect25(() => {
11599
+ useEffect26(() => {
11423
11600
  void load();
11424
11601
  }, [load]);
11425
11602
  const flip = useCallback23(
@@ -11571,17 +11748,17 @@ function SubscriptionsPanel({ tableId, className }) {
11571
11748
  }
11572
11749
 
11573
11750
  // src/FormBuilder.tsx
11574
- import { useCallback as useCallback25, useEffect as useEffect28, useMemo as useMemo26, useState as useState41 } from "react";
11751
+ import { useCallback as useCallback25, useEffect as useEffect29, useMemo as useMemo26, useState as useState41 } from "react";
11575
11752
  import { useFields as useFields18, useRecordsClient as useRecordsClient28, useTable as useTable14 } from "@ai-matrx/records/react";
11576
11753
 
11577
11754
  // src/publish-gate.ts
11578
- import { useEffect as useEffect26, useState as useState39 } from "react";
11755
+ import { useEffect as useEffect27, useState as useState39 } from "react";
11579
11756
  import { useRecordsClient as useRecordsClient27 } from "@ai-matrx/records/react";
11580
11757
  var PUBLISH_NEEDS_THE_STORE_ON = "This organization has its record store switched off, so publishing would hand you a link that opens nothing. An owner or an administrator turns it on under Database settings, on the unified data screen \u2014 everything you have already built here is kept and starts working the moment they do.";
11581
11758
  function usePublishGate() {
11582
11759
  const client = useRecordsClient27();
11583
11760
  const [storeOpen, setStoreOpen] = useState39(null);
11584
- useEffect26(() => {
11761
+ useEffect27(() => {
11585
11762
  let alive = true;
11586
11763
  void (async () => {
11587
11764
  const answered = await client.storeIsOpen();
@@ -11612,7 +11789,7 @@ import {
11612
11789
  } from "@ai-matrx/design-system";
11613
11790
 
11614
11791
  // src/FormRunner.tsx
11615
- import { useCallback as useCallback24, useEffect as useEffect27, useMemo as useMemo25, useRef as useRef11, useState as useState40 } from "react";
11792
+ import { useCallback as useCallback24, useEffect as useEffect28, useMemo as useMemo25, useRef as useRef11, useState as useState40 } from "react";
11616
11793
  import { useFields as useFields17, useOptionalRecordsClient as useOptionalRecordsClient4 } from "@ai-matrx/records/react";
11617
11794
  import { Button as Button36, Progress, Skeleton as Skeleton20, cn as cn36 } from "@ai-matrx/design-system";
11618
11795
  import { Fragment as Fragment18, jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
@@ -11706,7 +11883,7 @@ function FormStage({
11706
11883
  };
11707
11884
  });
11708
11885
  }, [fields, form.questions]);
11709
- useEffect27(() => {
11886
+ useEffect28(() => {
11710
11887
  let cancelled = false;
11711
11888
  const conditional = questions.filter((q) => q.showIf);
11712
11889
  if (conditional.length === 0 || !evaluate) return;
@@ -11777,7 +11954,7 @@ function FormStage({
11777
11954
  if (event.shiftKey) retreat();
11778
11955
  else advance();
11779
11956
  }
11780
- useEffect27(() => {
11957
+ useEffect28(() => {
11781
11958
  const input = stage.current?.querySelector(
11782
11959
  "input:not([tabindex='-1']), textarea, select, [role='combobox']"
11783
11960
  );
@@ -11972,10 +12149,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
11972
12149
  setError(null);
11973
12150
  setForms(mine);
11974
12151
  }, [client, tableId, seed, claimSeed]);
11975
- useEffect28(() => {
12152
+ useEffect29(() => {
11976
12153
  void load();
11977
12154
  }, [load]);
11978
- useEffect28(() => {
12155
+ useEffect29(() => {
11979
12156
  if (!forms || forms.length === 0) return;
11980
12157
  const chosen = forms.find((f) => f.id === (activeFormId ?? activeId)) ?? forms[0];
11981
12158
  if (chosen.id !== activeId) setActiveId(chosen.id);
@@ -12386,7 +12563,7 @@ function groupLabel(groups) {
12386
12563
 
12387
12564
  // src/chartFrame.tsx
12388
12565
  import {
12389
- useEffect as useEffect29,
12566
+ useEffect as useEffect30,
12390
12567
  useId as useId2,
12391
12568
  useRef as useRef12,
12392
12569
  useState as useState42
@@ -12396,7 +12573,7 @@ import { jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
12396
12573
  function useMeasuredWidth(fallback = 480) {
12397
12574
  const ref = useRef12(null);
12398
12575
  const [width, setWidth] = useState42(fallback);
12399
- useEffect29(() => {
12576
+ useEffect30(() => {
12400
12577
  const node = ref.current;
12401
12578
  if (!node) return;
12402
12579
  const apply = () => {
@@ -12520,7 +12697,7 @@ function isSignatureField(field) {
12520
12697
  }
12521
12698
 
12522
12699
  // src/DocTemplate.tsx
12523
- import { useCallback as useCallback26, useEffect as useEffect30, useState as useState43 } from "react";
12700
+ import { useCallback as useCallback26, useEffect as useEffect31, useState as useState43 } from "react";
12524
12701
  import { useFields as useFields19, useRecordsClient as useRecordsClient29, useTable as useTable15 } from "@ai-matrx/records/react";
12525
12702
  import { BasicInput as BasicInput14, BasicTextarea as BasicTextarea6, Button as Button38, Label as Label8, Skeleton as Skeleton22, cn as cn39 } from "@ai-matrx/design-system";
12526
12703
  import { jsx as jsx45, jsxs as jsxs41 } from "react/jsx-runtime";
@@ -12568,10 +12745,10 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
12568
12745
  setError(null);
12569
12746
  setTemplates(rows);
12570
12747
  }, [client, tableId, seed, fields.data]);
12571
- useEffect30(() => {
12748
+ useEffect31(() => {
12572
12749
  void load();
12573
12750
  }, [load]);
12574
- useEffect30(() => {
12751
+ useEffect31(() => {
12575
12752
  if (!templates || templates.length === 0) return;
12576
12753
  const chosen = templates.find((t) => t.id === (activeTemplateId ?? activeId)) ?? templates[0];
12577
12754
  if (chosen.id !== activeId) setActiveId(chosen.id);
@@ -12579,7 +12756,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
12579
12756
  setDraftBody(chosen.body);
12580
12757
  onActiveTemplate?.(chosen);
12581
12758
  }, [templates, activeTemplateId]);
12582
- useEffect30(() => {
12759
+ useEffect31(() => {
12583
12760
  let cancelled = false;
12584
12761
  if (draftBody.trim() === "") {
12585
12762
  setUnresolved([]);
@@ -12699,7 +12876,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
12699
12876
  }
12700
12877
 
12701
12878
  // src/DocRender.tsx
12702
- import { useCallback as useCallback27, useEffect as useEffect31, useRef as useRef13, useState as useState44 } from "react";
12879
+ import { useCallback as useCallback27, useEffect as useEffect32, useRef as useRef13, useState as useState44 } from "react";
12703
12880
  import { useRecordsClient as useRecordsClient30 } from "@ai-matrx/records/react";
12704
12881
  import { Button as Button39, Skeleton as Skeleton23, cn as cn40 } from "@ai-matrx/design-system";
12705
12882
  import { jsx as jsx46, jsxs as jsxs42 } from "react/jsx-runtime";
@@ -12728,7 +12905,7 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
12728
12905
  setPreview(body.data);
12729
12906
  setRenders(held.data.filter((r) => r.template_id === templateId));
12730
12907
  }, [client, templateId, recordId]);
12731
- useEffect31(() => {
12908
+ useEffect32(() => {
12732
12909
  void load();
12733
12910
  }, [load]);
12734
12911
  async function freeze() {
@@ -12812,7 +12989,7 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
12812
12989
  }
12813
12990
 
12814
12991
  // src/SignBlock.tsx
12815
- import { useCallback as useCallback28, useEffect as useEffect32, useState as useState45 } from "react";
12992
+ import { useCallback as useCallback28, useEffect as useEffect33, useState as useState45 } from "react";
12816
12993
  import { useFields as useFields20, useRecordsClient as useRecordsClient31 } from "@ai-matrx/records/react";
12817
12994
  import { BasicInput as BasicInput15, Button as Button40, Skeleton as Skeleton24, cn as cn41 } from "@ai-matrx/design-system";
12818
12995
  import { useTable as useTable16 } from "@ai-matrx/records/react";
@@ -12842,7 +13019,7 @@ function SignBlock({ tableId, recordId, render, className }) {
12842
13019
  }
12843
13020
  setVerdicts(answers);
12844
13021
  }, [client, recordId]);
12845
- useEffect32(() => {
13022
+ useEffect33(() => {
12846
13023
  void load();
12847
13024
  }, [load]);
12848
13025
  async function sign(field) {
@@ -12949,7 +13126,7 @@ function SignBlock({ tableId, recordId, render, className }) {
12949
13126
  }
12950
13127
 
12951
13128
  // src/NotifyRuleEditor.tsx
12952
- import { useCallback as useCallback29, useEffect as useEffect33, useState as useState46 } from "react";
13129
+ import { useCallback as useCallback29, useEffect as useEffect34, useState as useState46 } from "react";
12953
13130
  import { useRecordsClient as useRecordsClient32, useTable as useTable17 } from "@ai-matrx/records/react";
12954
13131
  import { Button as Button41, Skeleton as Skeleton25, cn as cn42 } from "@ai-matrx/design-system";
12955
13132
  import { jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
@@ -12985,7 +13162,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
12985
13162
  if (host.savedViews) setViews(await host.savedViews());
12986
13163
  else setViews(null);
12987
13164
  }, [client, host, tableId]);
12988
- useEffect33(() => {
13165
+ useEffect34(() => {
12989
13166
  void load();
12990
13167
  }, [load]);
12991
13168
  const write = useCallback29(
@@ -13013,7 +13190,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
13013
13190
  },
13014
13191
  [client, tableId]
13015
13192
  );
13016
- useEffect33(() => {
13193
+ useEffect34(() => {
13017
13194
  if (!subscriptions || !seed || seed.length === 0) return;
13018
13195
  const missing = seed.filter((s) => !subscriptions.some((held) => held.name === s.name));
13019
13196
  if (missing.length === 0) return;
@@ -13469,7 +13646,7 @@ function Drawing({
13469
13646
  }
13470
13647
 
13471
13648
  // src/DashboardCanvas.tsx
13472
- import { useCallback as useCallback30, useEffect as useEffect34, useMemo as useMemo28, useState as useState47 } from "react";
13649
+ import { useCallback as useCallback30, useEffect as useEffect35, useMemo as useMemo28, useState as useState47 } from "react";
13473
13650
  import { useFields as useFields21, useRecordsClient as useRecordsClient33, useTable as useTable18 } from "@ai-matrx/records/react";
13474
13651
  import {
13475
13652
  BasicInput as BasicInput16,
@@ -13506,17 +13683,17 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
13506
13683
  setError(null);
13507
13684
  setBoards(answered.data.map(dashboardFromSummary));
13508
13685
  }, [client, tableId]);
13509
- useEffect34(() => {
13686
+ useEffect35(() => {
13510
13687
  void load();
13511
13688
  }, [load]);
13512
- useEffect34(() => {
13689
+ useEffect35(() => {
13513
13690
  if (!boards || boards.length === 0) return;
13514
13691
  const chosen = boards.find((d) => d.id === (activeDashboardId ?? activeId)) ?? boards[0];
13515
13692
  if (chosen.id !== activeId) setActiveId(chosen.id);
13516
13693
  }, [boards, activeDashboardId]);
13517
13694
  const board = useMemo28(() => boards?.find((d) => d.id === activeId) ?? null, [boards, activeId]);
13518
13695
  const filterKey = JSON.stringify(filter ?? {});
13519
- useEffect34(() => {
13696
+ useEffect35(() => {
13520
13697
  if (!activeId) {
13521
13698
  setRun(null);
13522
13699
  return;
@@ -13812,7 +13989,7 @@ function GroupingPicker({
13812
13989
  }
13813
13990
 
13814
13991
  // src/FormsPanel.tsx
13815
- import { useCallback as useCallback31, useEffect as useEffect35, useState as useState48 } from "react";
13992
+ import { useCallback as useCallback31, useEffect as useEffect36, useState as useState48 } from "react";
13816
13993
  import { useRecordsClient as useRecordsClient34, useTable as useTable19 } from "@ai-matrx/records/react";
13817
13994
  import { publicFormPath as publicFormPath2 } from "@ai-matrx/records";
13818
13995
  import { Badge as Badge15, Button as Button43, Skeleton as Skeleton27, cn as cn45 } from "@ai-matrx/design-system";
@@ -13844,7 +14021,7 @@ function FormsPanel({ tableId, className }) {
13844
14021
  setError(null);
13845
14022
  setForms(answered.data);
13846
14023
  }, [client, tableId]);
13847
- useEffect35(() => {
14024
+ useEffect36(() => {
13848
14025
  void load();
13849
14026
  }, [load]);
13850
14027
  const toggle = useCallback31(
@@ -13961,7 +14138,7 @@ function FormsPanel({ tableId, className }) {
13961
14138
  }
13962
14139
 
13963
14140
  // src/BookingBuilder.tsx
13964
- import { useCallback as useCallback32, useEffect as useEffect36, useMemo as useMemo29, useState as useState49 } from "react";
14141
+ import { useCallback as useCallback32, useEffect as useEffect37, useMemo as useMemo29, useState as useState49 } from "react";
13965
14142
  import { useFields as useFields22, useRecordsClient as useRecordsClient35, useTable as useTable20 } from "@ai-matrx/records/react";
13966
14143
  import {
13967
14144
  bookingPath
@@ -14036,18 +14213,18 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
14036
14213
  setLoaded(true);
14037
14214
  if (mine) setFormId(mine.form_id);
14038
14215
  }, [client, tableId, bookingId]);
14039
- useEffect36(() => {
14216
+ useEffect37(() => {
14040
14217
  void load();
14041
14218
  }, [load]);
14042
- useEffect36(() => {
14219
+ useEffect37(() => {
14043
14220
  if (title !== "" || !table.data) return;
14044
14221
  setTitle(existing?.title ?? `Book a ${minutes}-minute ${table.data.name} appointment`);
14045
14222
  }, [table.data, existing]);
14046
- useEffect36(() => {
14223
+ useEffect37(() => {
14047
14224
  if (!existing) return;
14048
14225
  setMinutes(existing.slot_minutes);
14049
14226
  }, [existing]);
14050
- useEffect36(() => {
14227
+ useEffect37(() => {
14051
14228
  if (!offer) return;
14052
14229
  setWindows(draftWindows(offer));
14053
14230
  setMinutes(offer.slot_minutes);
@@ -14309,7 +14486,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
14309
14486
  }
14310
14487
 
14311
14488
  // src/BookingSlots.tsx
14312
- import { useCallback as useCallback33, useEffect as useEffect37, useMemo as useMemo30, useState as useState50 } from "react";
14489
+ import { useCallback as useCallback33, useEffect as useEffect38, useMemo as useMemo30, useState as useState50 } from "react";
14313
14490
  import { useRecordsClient as useRecordsClient36, useMyLevels as useMyLevels2 } from "@ai-matrx/records/react";
14314
14491
  import { bookingPath as bookingPath2 } from "@ai-matrx/records";
14315
14492
  import { Badge as Badge16, Button as Button45, Skeleton as Skeleton29, cn as cn47 } from "@ai-matrx/design-system";
@@ -14340,7 +14517,7 @@ function BookingSlots({ tableId, className }) {
14340
14517
  setError(null);
14341
14518
  setPages(answered.data);
14342
14519
  }, [client, tableId]);
14343
- useEffect37(() => {
14520
+ useEffect38(() => {
14344
14521
  void load();
14345
14522
  }, [load]);
14346
14523
  const subjectIds = useMemo30(
@@ -14509,12 +14686,12 @@ function nextInWords(page) {
14509
14686
  }
14510
14687
 
14511
14688
  // src/CaptureSheet.tsx
14512
- import { useCallback as useCallback35, useEffect as useEffect39, useRef as useRef15, useState as useState52 } from "react";
14689
+ import { useCallback as useCallback35, useEffect as useEffect40, useRef as useRef15, useState as useState52 } from "react";
14513
14690
  import { useFields as useFields23, useRecordsClient as useRecordsClient38, useTable as useTable21 } from "@ai-matrx/records/react";
14514
14691
  import { Button as Button47, Input as Input4, Skeleton as Skeleton31, Textarea as Textarea3, cn as cn49 } from "@ai-matrx/design-system";
14515
14692
 
14516
14693
  // src/CaptureRun.tsx
14517
- import { useCallback as useCallback34, useEffect as useEffect38, useMemo as useMemo31, useRef as useRef14, useState as useState51 } from "react";
14694
+ import { useCallback as useCallback34, useEffect as useEffect39, useMemo as useMemo31, useRef as useRef14, useState as useState51 } from "react";
14518
14695
  import {
14519
14696
  coerceTypedAnswer as coerceTypedAnswer2,
14520
14697
  coercionLabel,
@@ -14573,7 +14750,7 @@ function CaptureRun({ sheetId, face: given, className }) {
14573
14750
  const [lastSynced, setLastSynced] = useState51(null);
14574
14751
  const [sending, setSending] = useState51(false);
14575
14752
  const queueRef = useRef14(null);
14576
- useEffect38(() => {
14753
+ useEffect39(() => {
14577
14754
  const q2 = openCaptureQueue({
14578
14755
  onChange: (c, all) => {
14579
14756
  setCounts(c);
@@ -14611,7 +14788,7 @@ function CaptureRun({ sheetId, face: given, className }) {
14611
14788
  void q2.sync().then(() => void q2.lastSyncedAt().then(setLastSynced));
14612
14789
  return () => q2.dispose();
14613
14790
  }, [client, host]);
14614
- useEffect38(() => {
14791
+ useEffect39(() => {
14615
14792
  if (given !== void 0) return;
14616
14793
  let cancelled = false;
14617
14794
  void client.captureOpen({ sheet_id: sheetId }).then((res) => {
@@ -14943,7 +15120,7 @@ function AdHocCaptureSheet({
14943
15120
  },
14944
15121
  [host]
14945
15122
  );
14946
- useEffect39(() => {
15123
+ useEffect40(() => {
14947
15124
  let cancelled = false;
14948
15125
  void (async () => {
14949
15126
  const held = host.captureQueue ? await host.captureQueue.load() : [];
@@ -15122,7 +15299,7 @@ function AdHocCaptureSheet({
15122
15299
  }
15123
15300
 
15124
15301
  // src/PortalShell.tsx
15125
- import { useCallback as useCallback36, useEffect as useEffect40, useState as useState53 } from "react";
15302
+ import { useCallback as useCallback36, useEffect as useEffect41, useState as useState53 } from "react";
15126
15303
  import { useRecordsClient as useRecordsClient39 } from "@ai-matrx/records/react";
15127
15304
  import { Button as Button48, Skeleton as Skeleton32, cn as cn50 } from "@ai-matrx/design-system";
15128
15305
  import { jsx as jsx56, jsxs as jsxs52 } from "react/jsx-runtime";
@@ -15148,7 +15325,7 @@ function PortalShell({ tableId, form, resourceType = "record", className }) {
15148
15325
  }
15149
15326
  setReach(reached.data.map((row) => row.resource_id));
15150
15327
  }, [client, resourceType]);
15151
- useEffect40(() => {
15328
+ useEffect41(() => {
15152
15329
  void load();
15153
15330
  }, [load]);
15154
15331
  if (error) {
@@ -15208,7 +15385,7 @@ function PortalShell({ tableId, form, resourceType = "record", className }) {
15208
15385
  function PortalRow({ tableId, recordId }) {
15209
15386
  const client = useRecordsClient39();
15210
15387
  const [title, setTitle] = useState53(null);
15211
- useEffect40(() => {
15388
+ useEffect41(() => {
15212
15389
  let cancelled = false;
15213
15390
  void client.recordRead({ record_id: recordId }).then((answered) => {
15214
15391
  if (cancelled) return;
@@ -15228,7 +15405,7 @@ function PortalRow({ tableId, recordId }) {
15228
15405
  }
15229
15406
 
15230
15407
  // src/PublicViewPage.tsx
15231
- import { useCallback as useCallback37, useEffect as useEffect41, useState as useState54 } from "react";
15408
+ import { useCallback as useCallback37, useEffect as useEffect42, useState as useState54 } from "react";
15232
15409
  import { useRecordsClient as useRecordsClient40 } from "@ai-matrx/records/react";
15233
15410
  import { Skeleton as Skeleton33, cn as cn51 } from "@ai-matrx/design-system";
15234
15411
  import { jsx as jsx57, jsxs as jsxs53 } from "react/jsx-runtime";
@@ -15272,7 +15449,7 @@ function PublicViewPage({ slug, className }) {
15272
15449
  }
15273
15450
  setRows([{ id: found.resource_id, document: read.data.document, level: "viewer", hidden: read.data.hidden }]);
15274
15451
  }, [client, slug]);
15275
- useEffect41(() => {
15452
+ useEffect42(() => {
15276
15453
  void load();
15277
15454
  }, [load]);
15278
15455
  if (error) return /* @__PURE__ */ jsx57(RefusalNotice, { error, className });
@@ -15309,7 +15486,7 @@ function PublicRow({ row, fields }) {
15309
15486
  }
15310
15487
 
15311
15488
  // src/EmbedFrame.tsx
15312
- import { useCallback as useCallback38, useEffect as useEffect42, useState as useState55 } from "react";
15489
+ import { useCallback as useCallback38, useEffect as useEffect43, useState as useState55 } from "react";
15313
15490
  import { useRecordsClient as useRecordsClient41 } from "@ai-matrx/records/react";
15314
15491
  import { Button as Button49, Input as Input5, Skeleton as Skeleton34, Textarea as Textarea4, cn as cn52 } from "@ai-matrx/design-system";
15315
15492
  import { useTable as useTable22 } from "@ai-matrx/records/react";
@@ -15422,7 +15599,7 @@ function useEmbedHandshake(args) {
15422
15599
  const [loading, setLoading] = useState55(true);
15423
15600
  const origin = args.origin ?? (typeof location === "undefined" ? "" : location.origin);
15424
15601
  const { secret, requiredMode } = args;
15425
- useEffect42(() => {
15602
+ useEffect43(() => {
15426
15603
  let cancelled = false;
15427
15604
  setLoading(true);
15428
15605
  setError(null);
@@ -15477,7 +15654,7 @@ function recordsDataSource(client, fallbackSchema = "custom") {
15477
15654
  }
15478
15655
 
15479
15656
  // src/TablesHome.tsx
15480
- import { useCallback as useCallback39, useEffect as useEffect43, useState as useState56 } from "react";
15657
+ import { useCallback as useCallback39, useEffect as useEffect44, useState as useState56 } from "react";
15481
15658
  import { useRecordsClient as useRecordsClient42, useTables as useTables4 } from "@ai-matrx/records/react";
15482
15659
  import { BasicInput as BasicInput18, Button as Button50, Skeleton as Skeleton35, cn as cn53 } from "@ai-matrx/design-system";
15483
15660
 
@@ -15622,7 +15799,7 @@ function TablesHome({ onOpenTable, className }) {
15622
15799
  const [error, setError] = useState56(null);
15623
15800
  const [importInto, setImportInto] = useState56(null);
15624
15801
  const [boards, setBoards] = useState56(null);
15625
- useEffect43(() => {
15802
+ useEffect44(() => {
15626
15803
  let cancelled = false;
15627
15804
  void client.dashboards({}).then((result) => {
15628
15805
  if (cancelled) return;
@@ -15756,7 +15933,7 @@ function TablesHome({ onOpenTable, className }) {
15756
15933
  }
15757
15934
 
15758
15935
  // src/TablePage.tsx
15759
- import { useCallback as useCallback40, useEffect as useEffect44, useState as useState57 } from "react";
15936
+ import { useCallback as useCallback40, useEffect as useEffect45, useState as useState57 } from "react";
15760
15937
  import { useFields as useFields24, useRecordsClient as useRecordsClient43, useTable as useTable23 } from "@ai-matrx/records/react";
15761
15938
  import { Button as Button51, Separator as Separator12, Skeleton as Skeleton36, cn as cn54 } from "@ai-matrx/design-system";
15762
15939
  import { Fragment as Fragment28, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
@@ -15867,12 +16044,12 @@ function TablePage({
15867
16044
  }
15868
16045
  };
15869
16046
  const show = (next) => press({ rail: next });
15870
- useEffect44(() => {
16047
+ useEffect45(() => {
15871
16048
  if (!activeRecordId) return;
15872
16049
  setOpenRecord(activeRecordId);
15873
16050
  setSurface((now) => ({ ...now, rail: "record" }));
15874
16051
  }, [activeRecordId]);
15875
- useEffect44(() => {
16052
+ useEffect45(() => {
15876
16053
  const named = pageViewFromParam(activeView);
15877
16054
  if (named === null) return;
15878
16055
  const isLayout = named !== "dashboards" && named !== "archived";