@ai-matrx/records-ui 0.93.7 → 0.93.11

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.cjs CHANGED
@@ -70,7 +70,7 @@ __export(src_exports, {
70
70
  ConditionGroup: () => ConditionGroup,
71
71
  ConditionRow: () => ConditionRow,
72
72
  CustomFieldsSection: () => CustomFieldsSection,
73
- DEFAULT_FIELDS: () => import_core15.DEFAULT_FIELDS,
73
+ DEFAULT_FIELDS: () => import_core16.DEFAULT_FIELDS,
74
74
  DEFAULT_FOOTER: () => DEFAULT_FOOTER,
75
75
  DEFAULT_VIEW_NAME: () => DEFAULT_VIEW_NAME,
76
76
  DUE_STATE_LABEL: () => DUE_STATE_LABEL,
@@ -224,7 +224,7 @@ __export(src_exports, {
224
224
  WithheldValue: () => WithheldValue,
225
225
  actorBadge: () => actorBadge,
226
226
  actorWords: () => actorWords,
227
- addFields: () => import_core15.addFields,
227
+ addFields: () => import_core16.addFields,
228
228
  applyLook: () => applyLook,
229
229
  archiveConfirmSentence: () => archiveConfirmSentence,
230
230
  archivedRowLine: () => archivedRowLine,
@@ -259,7 +259,7 @@ __export(src_exports, {
259
259
  dashboardFromSummary: () => dashboardFromSummary,
260
260
  dateFormatFor: () => dateFormatFor,
261
261
  dateText: () => dateText,
262
- declareTable: () => import_core15.declareTable,
262
+ declareTable: () => import_core16.declareTable,
263
263
  declareView: () => declareView,
264
264
  defaultViewOf: () => defaultViewOf,
265
265
  designatedLayoutOf: () => designatedLayoutOf,
@@ -267,7 +267,7 @@ __export(src_exports, {
267
267
  ensureSystemTable: () => ensureSystemTable,
268
268
  entityReferenceSpec: () => entityReferenceSpec,
269
269
  envelopeFor: () => envelopeFor,
270
- fieldDeclarationFor: () => import_core15.fieldDeclarationFor,
270
+ fieldDeclarationFor: () => import_core16.fieldDeclarationFor,
271
271
  fieldIsEditable: () => fieldIsEditable,
272
272
  fieldName: () => fieldName,
273
273
  fieldToken: () => fieldToken,
@@ -357,7 +357,7 @@ __export(src_exports, {
357
357
  tableName: () => tableName,
358
358
  tableOpening: () => tableOpening,
359
359
  tableRightsAt: () => tableRightsAt,
360
- tokenFor: () => import_core15.tokenFor,
360
+ tokenFor: () => import_core16.tokenFor,
361
361
  unknownRailLine: () => unknownRailLine,
362
362
  unknownViewLine: () => unknownViewLine,
363
363
  useCanShare: () => useCanShare,
@@ -3107,7 +3107,7 @@ function OptionControl({ field: field2, value, onChange, disabled, id, autoOpen,
3107
3107
  if (refusal2)
3108
3108
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { id, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefusalLine, { error: refusal2 }) });
3109
3109
  if (!options) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { id, className: "text-xs text-muted-foreground", children: "Reading this field's choices\u2026" });
3110
- if (CHOICE_EDITOR_ADDS_WHAT_IS_TYPED && (0, import_records5.allowsOtherValues)(field2)) {
3110
+ if (CHOICE_EDITOR_ADDS_WHAT_IS_TYPED && ((0, import_records5.allowsOtherValues)(field2) || !autoOpen)) {
3111
3111
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3112
3112
  OpenChoicePicker,
3113
3113
  {
@@ -3118,6 +3118,7 @@ function OptionControl({ field: field2, value, onChange, disabled, id, autoOpen,
3118
3118
  disabled,
3119
3119
  id,
3120
3120
  addsChoices,
3121
+ allowOther: (0, import_records5.allowsOtherValues)(field2),
3121
3122
  onChoicesChanged: () => setReread((n) => n + 1)
3122
3123
  }
3123
3124
  );
@@ -3190,6 +3191,7 @@ function OpenChoicePicker({
3190
3191
  disabled,
3191
3192
  id,
3192
3193
  addsChoices,
3194
+ allowOther = true,
3193
3195
  onChoicesChanged
3194
3196
  }) {
3195
3197
  const client = (0, import_react18.useOptionalRecordsClient)();
@@ -3207,7 +3209,7 @@ function OpenChoicePicker({
3207
3209
  });
3208
3210
  const q = search.trim();
3209
3211
  const visible = options.filter((o) => q === "" || titleOf(o).toLowerCase().includes(q.toLowerCase()));
3210
- const decided = (0, import_records5.decideTypedChoice)({ words: q, options, allowOther: true, nudge: nudge ?? "ask" });
3212
+ const decided = (0, import_records5.decideTypedChoice)({ words: q, options, allowOther, nudge: nudge ?? "ask" });
3211
3213
  const choose = (word, addingIt = false) => {
3212
3214
  const pending = held.add.filter((w) => w.toLowerCase() !== word.toLowerCase());
3213
3215
  let next;
@@ -3292,7 +3294,10 @@ function OpenChoicePicker({
3292
3294
  empty: q === "" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "p-2 text-xs text-muted-foreground", children: "No choices yet \u2014 type one to add it." }) : null,
3293
3295
  add,
3294
3296
  foot,
3295
- footNote: addRefused ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefusalLine, { error: addRefused }) : null
3297
+ footNote: addRefused ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefusalLine, { error: addRefused }) : offList && decided.decision === "not_a_choice" ? (
3298
+ // never_add on a column that takes only its choices: said, never a silent nothing.
3299
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { "data-records-typed-refusal": "", className: "p-2 text-xs text-muted-foreground", children: notAChoiceSentence(field2, [q]) })
3300
+ ) : null
3296
3301
  }
3297
3302
  )
3298
3303
  )
@@ -4986,7 +4991,7 @@ var import_react64 = require("react");
4986
4991
  var import_react65 = require("@ai-matrx/records/react");
4987
4992
  var import_records17 = require("@ai-matrx/records");
4988
4993
  var import_data_table9 = require("@ai-matrx/design-system/data-table");
4989
- var import_core8 = require("@ai-matrx/records/core");
4994
+ var import_core9 = require("@ai-matrx/records/core");
4990
4995
 
4991
4996
  // src/archiveWords.ts
4992
4997
  function archiveConfirmSentence(what) {
@@ -5226,6 +5231,7 @@ var import_design_system25 = require("@ai-matrx/design-system");
5226
5231
  // src/FieldEditor.tsx
5227
5232
  var import_react36 = require("react");
5228
5233
  var import_react37 = require("@ai-matrx/records/react");
5234
+ var import_core4 = require("@ai-matrx/records/core");
5229
5235
  var import_design_system21 = require("@ai-matrx/design-system");
5230
5236
 
5231
5237
  // src/FormulaTextEditor.tsx
@@ -5497,6 +5503,22 @@ function choiceDisplayPatch(field2, rows) {
5497
5503
  const id = held?.id ?? (editorKindFor(field2) === "multi_select" ? "multi_choice" : "choice");
5498
5504
  return { id, options: { ...held?.options ?? {}, choices } };
5499
5505
  }
5506
+ function lookFollowsRenames(field2, look, renames) {
5507
+ if (renames.size === 0) return look;
5508
+ const base = look ?? displayFormatOf(field2);
5509
+ const choices = base && Array.isArray(base.options["choices"]) ? base.options["choices"] : null;
5510
+ if (!base || !choices) return look;
5511
+ let moved = false;
5512
+ const next = choices.map((c) => {
5513
+ const was = typeof c["value"] === "string" ? c["value"] : null;
5514
+ const now = was === null ? void 0 : [...renames].find(([old]) => choiceWord(old) === choiceWord(was))?.[1];
5515
+ if (now === void 0) return c;
5516
+ moved = true;
5517
+ return { ...c, value: now };
5518
+ });
5519
+ if (!moved) return look;
5520
+ return { id: base.id, options: { ...base.options, choices: next } };
5521
+ }
5500
5522
  function ChoiceColorsEditor({
5501
5523
  field: field2,
5502
5524
  rows,
@@ -5598,10 +5620,17 @@ function ChoiceListEditor({
5598
5620
  field: field2,
5599
5621
  rows,
5600
5622
  onRows,
5601
- onStart
5623
+ onStart,
5624
+ allowOther = false,
5625
+ rehome = {},
5626
+ onRehome
5602
5627
  }) {
5603
5628
  const client = (0, import_react35.useRecordsClient)();
5604
5629
  const [refused, setRefused] = (0, import_react34.useState)(null);
5630
+ const [usage, setUsage] = (0, import_react34.useState)(null);
5631
+ const [asking, setAsking] = (0, import_react34.useState)(null);
5632
+ const [moveTo, setMoveTo] = (0, import_react34.useState)("");
5633
+ const [removed, setRemoved] = (0, import_react34.useState)({});
5605
5634
  (0, import_react34.useEffect)(() => {
5606
5635
  if (rows !== null) return;
5607
5636
  let live = true;
@@ -5619,6 +5648,19 @@ function ChoiceListEditor({
5619
5648
  live = false;
5620
5649
  };
5621
5650
  }, [client, field2.id, rows, onRows, onStart]);
5651
+ (0, import_react34.useEffect)(() => {
5652
+ if (!onRehome) return;
5653
+ let live = true;
5654
+ void client.fieldChoiceUsage({ field_id: field2.id }).then(
5655
+ (got) => {
5656
+ if (live && got.ok) setUsage(got.data);
5657
+ },
5658
+ () => void 0
5659
+ );
5660
+ return () => {
5661
+ live = false;
5662
+ };
5663
+ }, [client, field2.id, onRehome]);
5622
5664
  if (refused) {
5623
5665
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("p", { className: "text-[11px] text-muted-foreground", "data-records-choice-list": "", children: [
5624
5666
  "The choices could not be read, so they are left as they are: ",
@@ -5635,6 +5677,37 @@ function ChoiceListEditor({
5635
5677
  onRows(next);
5636
5678
  };
5637
5679
  const named = (r, i) => r.words.trim() === "" ? `choice ${i + 1}` : `\u201C${r.words.trim()}\u201D`;
5680
+ const heldBy = (r) => r.id && onRehome ? usage?.[r.id]?.records ?? 0 : 0;
5681
+ const remove = (i) => {
5682
+ const r = rows[i];
5683
+ if (heldBy(r) > 0) {
5684
+ setAsking(r);
5685
+ setMoveTo("");
5686
+ return;
5687
+ }
5688
+ onRows(rows.filter((_, j) => j !== i));
5689
+ };
5690
+ const answer = (spec) => {
5691
+ if (!asking?.id || !onRehome) return;
5692
+ const index = rows.findIndex((r) => r.id === asking.id);
5693
+ setRemoved({ ...removed, [asking.id]: { row: asking, index: index < 0 ? rows.length : index } });
5694
+ onRows(rows.filter((r) => r.id !== asking.id));
5695
+ onRehome({ ...rehome, [asking.id]: spec });
5696
+ setAsking(null);
5697
+ };
5698
+ const putBack = (id) => {
5699
+ const was = removed[id];
5700
+ if (!was || !onRehome) return;
5701
+ const next = [...rows];
5702
+ next.splice(Math.min(was.index, next.length), 0, was.row);
5703
+ onRows(next);
5704
+ const { [id]: _gone, ...rest } = rehome;
5705
+ onRehome(rest);
5706
+ const { [id]: _was, ...keep } = removed;
5707
+ setRemoved(keep);
5708
+ };
5709
+ const targets = rows.filter((r) => r.id && r.id !== asking?.id && r.words.trim() !== "");
5710
+ const wordsOf = (id) => rows.find((r) => r.id === id)?.words.trim() ?? usage?.[id]?.words ?? "";
5638
5711
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col gap-1", "data-records-choice-list": "", children: [
5639
5712
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Label, { className: "text-xs", children: "The choices" }),
5640
5713
  rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-xs text-muted-foreground", "data-records-choice-list-empty": "", children: "No choices yet. Add the first one here, or type it into a cell and answer Add." }) : null,
@@ -5650,10 +5723,43 @@ function ChoiceListEditor({
5650
5723
  ),
5651
5724
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "ghost", className: "h-7 px-1.5 text-xs", "aria-label": `Move ${named(r, i)} up`, disabled: i === 0, onClick: () => move(i, -1), children: "\u2191" }),
5652
5725
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "ghost", className: "h-7 px-1.5 text-xs", "aria-label": `Move ${named(r, i)} down`, disabled: i === rows.length - 1, onClick: () => move(i, 1), children: "\u2193" }),
5653
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "ghost", className: "h-7 px-1.5 text-xs", "aria-label": `Remove ${named(r, i)}`, onClick: () => onRows(rows.filter((_, j) => j !== i)), children: "\xD7" })
5726
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "ghost", className: "h-7 px-1.5 text-xs", "aria-label": `Remove ${named(r, i)}`, onClick: () => remove(i), children: "\xD7" })
5654
5727
  ] }, r.row)) }),
5728
+ asking ? (
5729
+ // THE QUESTION, Notion-style: where do the records that hold it go?
5730
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
5731
+ "div",
5732
+ {
5733
+ role: "group",
5734
+ "aria-label": (0, import_records10.recordsUseSentence)(heldBy(asking), asking.words.trim()),
5735
+ "data-records-choice-removal-ask": "",
5736
+ className: "flex flex-col gap-1 rounded border bg-muted/40 p-2",
5737
+ children: [
5738
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-xs", children: (0, import_records10.recordsUseSentence)(heldBy(asking), asking.words.trim()) }),
5739
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
5740
+ targets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5741
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", className: "h-7 px-2 text-xs", disabled: moveTo === "", onClick: () => answer({ then: "move", to: moveTo }), children: "Move them to" }),
5742
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_design_system19.Select, { value: moveTo, onValueChange: setMoveTo, children: [
5743
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.SelectTrigger, { size: "sm", className: "h-7 w-36 text-xs", "aria-label": "Another choice", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.SelectValue, { placeholder: "Another choice" }) }),
5744
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.SelectContent, { children: targets.map((r) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.SelectItem, { value: r.id, children: r.words.trim() }, r.id)) })
5745
+ ] })
5746
+ ] }) : null,
5747
+ allowOther ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "outline", className: "h-7 px-2 text-xs", onClick: () => answer({ then: "keep" }), children: "Keep the words as other values" }) : null,
5748
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "outline", className: "h-7 px-2 text-xs", onClick: () => answer({ then: "clear" }), children: "Clear them" }),
5749
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "ghost", className: "h-7 px-2 text-xs", onClick: () => setAsking(null), children: "Cancel" })
5750
+ ] })
5751
+ ]
5752
+ }
5753
+ )
5754
+ ) : null,
5755
+ Object.entries(rehome).map(
5756
+ ([id, spec]) => removed[id] ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between gap-2 text-[11px] text-muted-foreground", "data-records-choice-rehome": "", children: [
5757
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: (0, import_records10.rehomeSentence)(usage?.[id]?.records ?? 0, removed[id].row.words.trim(), spec, spec.then === "move" ? wordsOf(spec.to) : void 0) }),
5758
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "ghost", className: "h-6 px-1.5 text-[11px]", onClick: () => putBack(id), children: "Put it back" })
5759
+ ] }, id) : null
5760
+ ),
5655
5761
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system19.Button, { type: "button", size: "sm", variant: "outline", className: "h-7 self-start text-xs", onClick: () => onRows([...rows, { id: null, words: "", row: nextRow() }]), children: "Add a choice" }),
5656
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Changing a choice\u2019s words changes them in every record that holds it. A removed choice is no longer offered; records that hold it keep it." })
5762
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Changing a choice\u2019s words changes them in every record that holds it. Removing a choice that records hold asks where those records go." })
5657
5763
  ] });
5658
5764
  }
5659
5765
 
@@ -6190,6 +6296,9 @@ function FieldEditor({ tableId, field: field2, onSaved, onCancel, onRemoved, cla
6190
6296
  const [optionText, setOptionText] = (0, import_react36.useState)("");
6191
6297
  const [choiceList, setChoiceList] = (0, import_react36.useState)(null);
6192
6298
  const [choiceListStart, setChoiceListStart] = (0, import_react36.useState)(null);
6299
+ const [rehome, setRehome] = (0, import_react36.useState)({});
6300
+ const [rehomed, setRehomed] = (0, import_react36.useState)(null);
6301
+ const [rehomeRefused, setRehomeRefused] = (0, import_react36.useState)(null);
6193
6302
  const [unit, setUnit] = (0, import_react36.useState)(field2?.unit ?? "$");
6194
6303
  const [withTime, setWithTime] = (0, import_react36.useState)(String(field2?.config?.["kind"] ?? "date") === "datetime");
6195
6304
  const [via, setVia] = (0, import_react36.useState)(String(field2?.config?.["via"] ?? ""));
@@ -6232,7 +6341,14 @@ function FieldEditor({ tableId, field: field2, onSaved, onCancel, onRemoved, cla
6232
6341
  if (missing) return;
6233
6342
  if (editing && field2) {
6234
6343
  const chooses = type === "select" || type === "multi_select";
6235
- const look = chooses ? choiceRows ? choiceDisplayPatch(field2, choiceRows) : null : null;
6344
+ const renames = /* @__PURE__ */ new Map();
6345
+ if (chooses && choiceList && choiceListStart) {
6346
+ for (const was of choiceListStart) {
6347
+ const now = was.id ? choiceList.find((r) => r.id === was.id) : void 0;
6348
+ if (now && now.words.trim() !== "" && now.words.trim() !== was.words.trim()) renames.set(was.words.trim(), now.words.trim());
6349
+ }
6350
+ }
6351
+ const look = chooses ? lookFollowsRenames(field2, choiceRows ? choiceDisplayPatch(field2, choiceRows) : null, renames) : null;
6236
6352
  const shownAs = chooses ? void 0 : formatPatch(field2, showsAs);
6237
6353
  const patch = {
6238
6354
  // The column's look travels in the same settings patch (`display_format`), so a save is
@@ -6276,6 +6392,20 @@ function FieldEditor({ tableId, field: field2, onSaved, onCancel, onRemoved, cla
6276
6392
  // K2: a re-aimed formula goes WITH its type word, the arm `field_update` reads it in.
6277
6393
  ...type === "formula" && formulaWritten && formulaChanged && formulaText.trim() !== "" ? { type: "formula", formula_text: formulaText.trim() } : {}
6278
6394
  };
6395
+ if (Object.keys(rehome).length > 0 && Array.isArray(patch.options)) {
6396
+ setRehomeRefused(null);
6397
+ const done = await client.fieldUpdateRehomingChoices({ field_id: field2.id, patch, rehome });
6398
+ if (!done.ok) {
6399
+ setRehomeRefused(done.error);
6400
+ return;
6401
+ }
6402
+ (0, import_react37.tableShapeChanged)(tableId);
6403
+ for (const c of done.data.undo.cells_back) (0, import_core4.announceRecordChanged)(c.record_id);
6404
+ const n = done.data.rehomed.reduce((sum, r) => sum + r.records, 0);
6405
+ setRehome({});
6406
+ setRehomed({ said: `Saved. ${n} ${n === 1 ? "record was" : "records were"} changed with the choices.`, undo: done.data.undo });
6407
+ return;
6408
+ }
6279
6409
  const written2 = await mutation.update({ field_id: field2.id, patch });
6280
6410
  if (written2 !== null) onSaved?.();
6281
6411
  return;
@@ -6446,7 +6576,18 @@ function FieldEditor({ tableId, field: field2, onSaved, onCancel, onRemoved, cla
6446
6576
  relations,
6447
6577
  others,
6448
6578
  existingOptionsTable: Boolean(field2?.options_table_id ?? field2?.config?.["options_table_id"]),
6449
- choiceList: editing && field2 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ChoiceListEditor, { field: field2, rows: choiceList, onRows: setChoiceList, onStart: setChoiceListStart }) : null,
6579
+ choiceList: editing && field2 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6580
+ ChoiceListEditor,
6581
+ {
6582
+ field: field2,
6583
+ rows: choiceList,
6584
+ onRows: setChoiceList,
6585
+ onStart: setChoiceListStart,
6586
+ allowOther,
6587
+ rehome,
6588
+ onRehome: setRehome
6589
+ }
6590
+ ) : null,
6450
6591
  allowedTypes,
6451
6592
  setAllowedTypes
6452
6593
  }
@@ -6596,6 +6737,36 @@ function FieldEditor({ tableId, field: field2, onSaved, onCancel, onRemoved, cla
6596
6737
  error: refusal("internal", COLUMN_DID_NOT_LAND_SENTENCE, COLUMN_DID_NOT_LAND_REMEDY)
6597
6738
  }
6598
6739
  ) : null,
6740
+ rehomeRefused ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(RefusalNotice, { error: rehomeRefused }) : null,
6741
+ rehomed ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "data-records-choice-rehomed": "", className: "flex flex-wrap items-center gap-2 text-[11px]", children: [
6742
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: rehomed.said }),
6743
+ rehomed.undo ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6744
+ import_design_system21.Button,
6745
+ {
6746
+ type: "button",
6747
+ size: "sm",
6748
+ variant: "outline",
6749
+ className: "h-6 px-2 text-xs",
6750
+ onClick: () => {
6751
+ const undo = rehomed.undo;
6752
+ if (!undo || !field2) return;
6753
+ void client.fieldUpdateRehomingChoices({ field_id: field2.id, patch: { options: undo.options }, cells_back: undo.cells_back }).then((back) => {
6754
+ if (!back.ok) {
6755
+ setRehomeRefused(back.error);
6756
+ return;
6757
+ }
6758
+ (0, import_react37.tableShapeChanged)(tableId);
6759
+ for (const c of undo.cells_back) (0, import_core4.announceRecordChanged)(c.record_id);
6760
+ setChoiceList(null);
6761
+ setChoiceListStart(null);
6762
+ setRehomed({ said: "Undone. The choices and the records that held them are back as they were.", undo: null });
6763
+ });
6764
+ },
6765
+ children: "Undo"
6766
+ }
6767
+ ) : null,
6768
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_design_system21.Button, { type: "button", size: "sm", className: "h-6 px-2 text-xs", onClick: () => onSaved?.(), children: "Done" })
6769
+ ] }) : null,
6599
6770
  backfillError ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { "data-records-autonumber-backfill-refused": "", className: "flex flex-col gap-1", children: [
6600
6771
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-[11px]", children: "The column is made. The records already in the table were not numbered:" }),
6601
6772
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(RefusalNotice, { error: backfillError })
@@ -7780,7 +7951,7 @@ function SummarySheetControls({
7780
7951
  }
7781
7952
 
7782
7953
  // src/pasteValues.ts
7783
- var import_core4 = require("@ai-matrx/records/core");
7954
+ var import_core5 = require("@ai-matrx/records/core");
7784
7955
  var import_records14 = require("@ai-matrx/records");
7785
7956
  function wordForStoredChoice(options, value) {
7786
7957
  if (options === void 0 || typeof value !== "string" || value === "") return null;
@@ -7858,7 +8029,7 @@ function planPastedBlock(args) {
7858
8029
  });
7859
8030
  accepted[key] = judged.value;
7860
8031
  }
7861
- const predicted = (0, import_core4.predictValueRefusals)(args.fields, accepted);
8032
+ const predicted = (0, import_core5.predictValueRefusals)(args.fields, accepted);
7862
8033
  for (const refusal2 of predicted) {
7863
8034
  const key = refusal2.field_key;
7864
8035
  if (key === void 0) continue;
@@ -9840,7 +10011,7 @@ function GridLayoutMenu({
9840
10011
  // src/gridUndo.tsx
9841
10012
  var import_react56 = require("react");
9842
10013
  var import_react57 = require("@ai-matrx/records/react");
9843
- var import_core5 = require("@ai-matrx/records/core");
10014
+ var import_core6 = require("@ai-matrx/records/core");
9844
10015
  var import_design_system32 = require("@ai-matrx/design-system");
9845
10016
  var import_data_table8 = require("@ai-matrx/design-system/data-table");
9846
10017
  var import_jsx_runtime38 = require("react/jsx-runtime");
@@ -9908,7 +10079,7 @@ function useGridUndo(args) {
9908
10079
  }
9909
10080
  forget(step2.cells.map((c) => ({ rowId: c.rowId, key: c.key })));
9910
10081
  for (const id of /* @__PURE__ */ new Set([...step2.cells.map((c) => c.rowId), ...step2.created ?? [], ...step2.archived ?? []])) {
9911
- (0, import_core5.announceRecordChanged)(id);
10082
+ (0, import_core6.announceRecordChanged)(id);
9912
10083
  }
9913
10084
  setHeld(() => {
9914
10085
  let stack = taken.stack;
@@ -10053,7 +10224,7 @@ function undoKey(event) {
10053
10224
 
10054
10225
  // src/gridAssist.tsx
10055
10226
  var import_react59 = require("react");
10056
- var import_core6 = require("@ai-matrx/records/core");
10227
+ var import_core7 = require("@ai-matrx/records/core");
10057
10228
  var import_content_transfer = require("@ai-matrx/design-system/content-transfer");
10058
10229
 
10059
10230
  // src/gridAgentContext.ts
@@ -10332,7 +10503,7 @@ function useGridAssist(args) {
10332
10503
  if (!row) return;
10333
10504
  const document2 = row.document ?? {};
10334
10505
  const value = editing.valueFor(row, fieldOf2(key));
10335
- const pointer = typeof document2[key] === "string" ? (0, import_core6.wholeValueOf)(document2, key) : null;
10506
+ const pointer = typeof document2[key] === "string" ? (0, import_core7.wholeValueOf)(document2, key) : null;
10336
10507
  setWhole({ rowId, key, rowTitle: titleOf(row), value, pointer });
10337
10508
  },
10338
10509
  [rowOf, fieldOf2, titleOf, editing]
@@ -10425,7 +10596,7 @@ function useGridAssist(args) {
10425
10596
  // src/gridBulk.tsx
10426
10597
  var import_react60 = require("react");
10427
10598
  var import_react61 = require("@ai-matrx/records/react");
10428
- var import_core7 = require("@ai-matrx/records/core");
10599
+ var import_core8 = require("@ai-matrx/records/core");
10429
10600
  var import_design_system34 = require("@ai-matrx/design-system");
10430
10601
  var import_jsx_runtime41 = require("react/jsx-runtime");
10431
10602
  function countOf(n, one, many) {
@@ -10482,7 +10653,7 @@ function useGridBulk(args) {
10482
10653
  setRefusal(done.error);
10483
10654
  return null;
10484
10655
  }
10485
- for (const change of changes) if ("record_id" in change && change.record_id) (0, import_core7.announceRecordChanged)(change.record_id);
10656
+ for (const change of changes) if ("record_id" in change && change.record_id) (0, import_core8.announceRecordChanged)(change.record_id);
10486
10657
  return done.data;
10487
10658
  },
10488
10659
  [client, tableId]
@@ -11624,7 +11795,7 @@ function Grid({
11624
11795
  }))
11625
11796
  );
11626
11797
  editing.forget(cells);
11627
- for (const u of updates) (0, import_core8.announceRecordChanged)(u.row.recordId);
11798
+ for (const u of updates) (0, import_core9.announceRecordChanged)(u.row.recordId);
11628
11799
  const lines = updates.length + creates.length;
11629
11800
  undo.push({ label: `Pasted ${lines} ${lines === 1 ? "row" : "rows"}`, cells, created });
11630
11801
  const expected = [
@@ -12796,7 +12967,7 @@ function withHeaderMenus(columns, menuFor, filterFor) {
12796
12967
  // src/ExportMenu.tsx
12797
12968
  var import_react66 = require("react");
12798
12969
  var import_react67 = require("@ai-matrx/records/react");
12799
- var import_core9 = require("@ai-matrx/records/core");
12970
+ var import_core10 = require("@ai-matrx/records/core");
12800
12971
  var import_react68 = require("@ai-matrx/alchemy/react");
12801
12972
  var import_design_system37 = require("@ai-matrx/design-system");
12802
12973
  var import_jsx_runtime44 = require("react/jsx-runtime");
@@ -12815,7 +12986,7 @@ function toRows(fields, records, labels) {
12815
12986
  absent_reason: envelope?.absent ?? null,
12816
12987
  // A VALUE KEPT AS A FILE carries its pointer, so the export writes the whole text
12817
12988
  // (`withWholeValues`), never the first words passed off as the value.
12818
- source: (0, import_core9.wholeValueOf)(document2, field2.key)
12989
+ source: (0, import_core10.wholeValueOf)(document2, field2.key)
12819
12990
  };
12820
12991
  }
12821
12992
  return row;
@@ -12869,7 +13040,7 @@ function ExportMenu({ tableId, rows, label, className }) {
12869
13040
  );
12870
13041
  const lookup = (field2, id) => labels(field2, id) ?? learned.get(`${field2.id}:${id}`) ?? null;
12871
13042
  const read = host.readFileText;
12872
- return (0, import_core9.withWholeValues)(toRows(all, records, lookup), read ? (fileId) => read({ fileId }) : null);
13043
+ return (0, import_core10.withWholeValues)(toRows(all, records, lookup), read ? (fileId) => read({ fileId }) : null);
12873
13044
  };
12874
13045
  return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: (0, import_design_system37.cn)("flex items-center gap-1", className), children: [
12875
13046
  /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
@@ -12877,7 +13048,7 @@ function ExportMenu({ tableId, rows, label, className }) {
12877
13048
  {
12878
13049
  size: "sm",
12879
13050
  variant: "outline",
12880
- onClick: () => void exported().then((rows2) => download(`${name}.csv`, "text/csv;charset=utf-8", (0, import_core9.exportCsv)(fields.data ?? [], rows2))).catch(
13051
+ onClick: () => void exported().then((rows2) => download(`${name}.csv`, "text/csv;charset=utf-8", (0, import_core10.exportCsv)(fields.data ?? [], rows2))).catch(
12881
13052
  (thrown) => setFailure(refusalFromThrown(thrown, "The CSV could not be written.", "Try again in a moment."))
12882
13053
  ),
12883
13054
  children: "CSV"
@@ -12898,7 +13069,7 @@ function ExportMenu({ tableId, rows, label, className }) {
12898
13069
  );
12899
13070
  setFailure(null);
12900
13071
  try {
12901
- exported().then((rows2) => (0, import_core9.exportXlsx)(fields.data ?? [], rows2, name)).then(
13072
+ exported().then((rows2) => (0, import_core10.exportXlsx)(fields.data ?? [], rows2, name)).then(
12902
13073
  (bytes) => download(
12903
13074
  `${name}.xlsx`,
12904
13075
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
@@ -12919,7 +13090,7 @@ function ExportMenu({ tableId, rows, label, className }) {
12919
13090
  sourceId: `records:${tableId}`,
12920
13091
  size: "xs",
12921
13092
  json: () => records.map((r) => r.document),
12922
- human: () => (0, import_core9.exportCsv)(fields.data ?? [], toRows(fields.data ?? [], records, labels))
13093
+ human: () => (0, import_core10.exportCsv)(fields.data ?? [], toRows(fields.data ?? [], records, labels))
12923
13094
  }
12924
13095
  ),
12925
13096
  failure ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(RefusalLine, { error: failure }) : null
@@ -12929,11 +13100,11 @@ function ExportMenu({ tableId, rows, label, className }) {
12929
13100
  // src/ImportWizard.tsx
12930
13101
  var import_react69 = require("react");
12931
13102
  var import_react70 = require("@ai-matrx/records/react");
12932
- var import_core11 = require("@ai-matrx/records/core");
13103
+ var import_core12 = require("@ai-matrx/records/core");
12933
13104
  var import_design_system38 = require("@ai-matrx/design-system");
12934
13105
 
12935
13106
  // src/importRuleCheck.ts
12936
- var import_core10 = require("@ai-matrx/records/core");
13107
+ var import_core11 = require("@ai-matrx/records/core");
12937
13108
  function checkImportRules(fields, rows, mapping) {
12938
13109
  const byKey = new Map(fields.map((f) => [f.key, f]));
12939
13110
  const verdicts = [];
@@ -12951,7 +13122,7 @@ function checkImportRules(fields, rows, mapping) {
12951
13122
  let why = null;
12952
13123
  if ("refusal" in meant) why = meant.refusal;
12953
13124
  else {
12954
- const predicted = (0, import_core10.predictValueRefusals)([field2], { [key]: meant.value }).filter(
13125
+ const predicted = (0, import_core11.predictValueRefusals)([field2], { [key]: meant.value }).filter(
12955
13126
  (p) => p.field_key === void 0 || p.field_key === key
12956
13127
  );
12957
13128
  if (predicted.length > 0) why = predicted[0].message;
@@ -13079,7 +13250,7 @@ function ImportWizard({ tableId, onDone, onWrote, className }) {
13079
13250
  try {
13080
13251
  const xlsx = file.name.toLowerCase().endsWith(".xlsx");
13081
13252
  const bytes = await file.arrayBuffer();
13082
- const result = xlsx ? await (0, import_core11.importXlsx)(bytes) : (0, import_core11.importCsv)(new TextDecoder().decode(bytes));
13253
+ const result = xlsx ? await (0, import_core12.importXlsx)(bytes) : (0, import_core12.importCsv)(new TextDecoder().decode(bytes));
13083
13254
  setFormat(xlsx ? "xlsx" : "csv");
13084
13255
  setFileName(file.name);
13085
13256
  setFileBytes(file.size);
@@ -13706,6 +13877,7 @@ function CustomFieldsSection({
13706
13877
  const [newLabel, setNewLabel] = (0, import_react71.useState)("");
13707
13878
  const [newType, setNewType] = (0, import_react71.useState)("text");
13708
13879
  const [draft, setDraft] = (0, import_react71.useState)({});
13880
+ const [removing, setRemoving] = (0, import_react71.useState)(null);
13709
13881
  const fields = (0, import_react71.useMemo)(() => read.data?.fields ?? [], [read.data]);
13710
13882
  const mayAdd = rights.data?.may_declare === true;
13711
13883
  const live = (0, import_react71.useRef)({ fields, rights: rights.data, loading: rights.loading, reload: read.reload });
@@ -13865,7 +14037,46 @@ function CustomFieldsSection({
13865
14037
  const field2 = asField(f);
13866
14038
  const id = `cf-${recordId}-${f.key}`;
13867
14039
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex min-w-0 flex-col gap-1", children: [
13868
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(FieldLabel, { field: field2, htmlFor: id }),
14040
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
14041
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(FieldLabel, { field: field2, htmlFor: id }),
14042
+ mayAdd && removing !== f.id ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
14043
+ import_design_system39.Button,
14044
+ {
14045
+ size: "sm",
14046
+ variant: "ghost",
14047
+ className: "ml-auto h-6 px-2 text-xs text-muted-foreground",
14048
+ onClick: () => setRemoving(f.id),
14049
+ children: "Remove field"
14050
+ }
14051
+ ) : null
14052
+ ] }),
14053
+ removing === f.id ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
14054
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "text-destructive", children: [
14055
+ archiveConfirmSentence(`the field \u201C${f.label}\u201D`),
14056
+ " It is removed for everyone in this organization; its values stay in every record and come back with it."
14057
+ ] }),
14058
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
14059
+ import_design_system39.Button,
14060
+ {
14061
+ size: "sm",
14062
+ variant: "destructive",
14063
+ disabled: mutation.saving,
14064
+ onClick: async () => {
14065
+ const gone = await mutation.retire({ field_id: f.id });
14066
+ setRemoving(null);
14067
+ if (gone) {
14068
+ setDraft((d) => {
14069
+ const { [f.key]: _dropped, ...rest } = d;
14070
+ return rest;
14071
+ });
14072
+ read.reload();
14073
+ }
14074
+ },
14075
+ children: "Remove it"
14076
+ }
14077
+ ),
14078
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_design_system39.Button, { size: "sm", variant: "ghost", onClick: () => setRemoving(null), children: "Keep it" })
14079
+ ] }) : null,
13869
14080
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
13870
14081
  FieldControl,
13871
14082
  {
@@ -15518,10 +15729,10 @@ var import_design_system48 = require("@ai-matrx/design-system");
15518
15729
  // src/RecordForm.tsx
15519
15730
  var import_react86 = require("react");
15520
15731
  var import_react87 = require("@ai-matrx/records/react");
15521
- var import_core13 = require("@ai-matrx/records/core");
15732
+ var import_core14 = require("@ai-matrx/records/core");
15522
15733
 
15523
15734
  // src/writeOnTheWinningVersion.ts
15524
- var import_core12 = require("@ai-matrx/records/core");
15735
+ var import_core13 = require("@ai-matrx/records/core");
15525
15736
  function sameStoredValue(left, right) {
15526
15737
  if (left === right) return true;
15527
15738
  const empty = (v) => v === null || v === void 0 || v === "";
@@ -15543,7 +15754,7 @@ async function updateOnTheWinningVersion(client, recordId, patch, expectedVersio
15543
15754
  });
15544
15755
  const first = await send(expectedVersion);
15545
15756
  if (first.ok) return first;
15546
- const conflict = (0, import_core12.asWriteConflict)(first.error, recordId);
15757
+ const conflict = (0, import_core13.asWriteConflict)(first.error, recordId);
15547
15758
  if (!conflict) return first;
15548
15759
  const untouched = base === "always" || Object.keys(patch).every((key) => sameStoredValue(conflict.contested_fields[key], base[key]));
15549
15760
  if (!untouched) return first;
@@ -15780,7 +15991,7 @@ function RecordForm({
15780
15991
  return out;
15781
15992
  }, [draft]);
15782
15993
  const predicted = (0, import_react86.useMemo)(
15783
- () => fields.data ? (0, import_core13.predictWriteRefusals)({ fields: fields.data, document: document2, ...recordType ? { recordType } : {} }) : [],
15994
+ () => fields.data ? (0, import_core14.predictWriteRefusals)({ fields: fields.data, document: document2, ...recordType ? { recordType } : {} }) : [],
15784
15995
  [fields.data, document2, recordType]
15785
15996
  );
15786
15997
  if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(RefusalNotice, { error: fields.error, className });
@@ -15829,7 +16040,7 @@ function RecordForm({
15829
16040
  setEdit({
15830
16041
  saving: false,
15831
16042
  error: answered2.ok ? null : answered2.error,
15832
- conflict: answered2.ok ? null : (0, import_core13.asWriteConflict)(answered2.error, recordId)
16043
+ conflict: answered2.ok ? null : (0, import_core14.asWriteConflict)(answered2.error, recordId)
15833
16044
  });
15834
16045
  const moved = answered2.ok ? answered2.data : null;
15835
16046
  if (moved !== null) {
@@ -15935,7 +16146,7 @@ function FieldRow({
15935
16146
  }) {
15936
16147
  const id = `field-${field2.id}`;
15937
16148
  const storedWords = document2?.[field2.key];
15938
- const whole = typeof storedWords === "string" ? (0, import_core13.wholeValueOf)(document2, field2.key) : null;
16149
+ const whole = typeof storedWords === "string" ? (0, import_core14.wholeValueOf)(document2, field2.key) : null;
15939
16150
  return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: (0, import_design_system46.cn)("flex min-w-0 flex-col gap-1", whole && "sm:col-span-2"), children: [
15940
16151
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(FieldLabel, { field: field2, htmlFor: id, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(ProvenanceBadge, { document: document2, fieldKey: field2.key }) }),
15941
16152
  whole ? (
@@ -24437,7 +24648,7 @@ function SignBlock({ tableId, recordId, render, className }) {
24437
24648
  var import_react144 = require("react");
24438
24649
  var import_recharts = require("recharts");
24439
24650
  var import_records24 = require("@ai-matrx/records");
24440
- var import_core14 = require("@ai-matrx/records/core");
24651
+ var import_core15 = require("@ai-matrx/records/core");
24441
24652
  var import_design_system74 = require("@ai-matrx/design-system");
24442
24653
  var import_jsx_runtime82 = require("react/jsx-runtime");
24443
24654
  var priorKey = (key) => `prior__${key}`;
@@ -24494,7 +24705,7 @@ function pretty(n) {
24494
24705
  return Number.isInteger(n) ? n.toLocaleString() : n.toLocaleString(void 0, { maximumFractionDigits: 2 });
24495
24706
  }
24496
24707
  function asRefusal2(block) {
24497
- return (0, import_core14.mapPgError)(
24708
+ return (0, import_core15.mapPgError)(
24498
24709
  {
24499
24710
  message: block.refused ?? "",
24500
24711
  ...block.sqlstate ? { code: block.sqlstate } : {}
@@ -27168,7 +27379,7 @@ function recordsDataSource(client, fallbackSchema = "custom") {
27168
27379
  // src/TablesHome.tsx
27169
27380
  var import_react170 = require("react");
27170
27381
  var import_react171 = require("@ai-matrx/records/react");
27171
- var import_core16 = require("@ai-matrx/records/core");
27382
+ var import_core17 = require("@ai-matrx/records/core");
27172
27383
  var import_records30 = require("@ai-matrx/records");
27173
27384
  var import_design_system86 = require("@ai-matrx/design-system");
27174
27385
 
@@ -27263,7 +27474,7 @@ function ExampleTables({
27263
27474
  }
27264
27475
 
27265
27476
  // src/createTable.ts
27266
- var import_core15 = require("@ai-matrx/records/core");
27477
+ var import_core16 = require("@ai-matrx/records/core");
27267
27478
 
27268
27479
  // src/WhereItLives.tsx
27269
27480
  var import_react168 = require("react");
@@ -27542,7 +27753,7 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
27542
27753
  };
27543
27754
  }, [client]);
27544
27755
  const listed = facts.phase === "read" ? (0, import_records30.withTablePlacement)(
27545
- (0, import_core16.withTableFacts)(tables.data ?? [], facts.rows, me),
27756
+ (0, import_core17.withTableFacts)(tables.data ?? [], facts.rows, me),
27546
27757
  facts.rows
27547
27758
  ) : tables.data ?? [];
27548
27759
  const [showEverything, setShowEverything] = (0, import_react170.useState)(false);
@@ -27586,7 +27797,7 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
27586
27797
  if (!trimmed) return;
27587
27798
  setBusy(true);
27588
27799
  setError(null);
27589
- const result = await (0, import_core15.declareTable)(client, { name: trimmed, slug: (0, import_core15.tokenFor)(trimmed) });
27800
+ const result = await (0, import_core16.declareTable)(client, { name: trimmed, slug: (0, import_core16.tokenFor)(trimmed) });
27590
27801
  setBusy(false);
27591
27802
  if (!result.ok) {
27592
27803
  setError(result.error);