@ai-matrx/records-ui 0.113.31 → 0.113.33

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
@@ -81,12 +81,12 @@ function whatYouMayDo(level, known = true) {
81
81
  var NOT_ANSWERED_YET = whatYouMayDo(null, false);
82
82
  var KERNEL_REASON = "This is one of the tables the platform ships, so its columns are not changed from a screen. Make your own table to change columns.";
83
83
  function whatYouMayDoWithTable(table, level, known) {
84
- const base = whatYouMayDo(level, known);
85
- if (!table?.is_kernel) return base;
84
+ const base2 = whatYouMayDo(level, known);
85
+ if (!table?.is_kernel) return base2;
86
86
  return {
87
- ...base,
87
+ ...base2,
88
88
  structure: false,
89
- why: (what) => what === "structure" ? KERNEL_REASON : base.why(what)
89
+ why: (what) => what === "structure" ? KERNEL_REASON : base2.why(what)
90
90
  };
91
91
  }
92
92
 
@@ -215,8 +215,8 @@ var UNREAD_RECORD_LABEL = "Couldn't load this name";
215
215
  function realPlural(table) {
216
216
  const plural4 = (table.label_plural ?? "").trim();
217
217
  if (plural4 === "") return null;
218
- for (const base of [table.name, table.label_singular]) {
219
- const b = (base ?? "").trim();
218
+ for (const base2 of [table.name, table.label_singular]) {
219
+ const b = (base2 ?? "").trim();
220
220
  if (b !== "" && plural4 === `${b}s`) return null;
221
221
  }
222
222
  return plural4;
@@ -516,7 +516,7 @@ async function rowActionFromAgent(input, fields, check) {
516
516
  const name = input["name"];
517
517
  if (typeof name !== "string" || !name.trim()) throw new Error(`editing_row_action.name must be the button's label \u2014 received ${describeValue(name)}.`);
518
518
  const kind = input["kind"];
519
- const base = {
519
+ const base2 = {
520
520
  name: name.trim(),
521
521
  kind: kind === "agent" ? "agent" : "update",
522
522
  confirm: input["confirm"] === true,
@@ -526,14 +526,14 @@ async function rowActionFromAgent(input, fields, check) {
526
526
  if (kind === "agent") {
527
527
  const prompt = input["prompt"];
528
528
  if (typeof prompt !== "string" || !prompt.trim()) throw new Error(`An agent action needs \`prompt\`: what the agent does with the row \u2014 received ${describeValue(prompt)}.`);
529
- return { ...base, prompt: prompt.trim() };
529
+ return { ...base2, prompt: prompt.trim() };
530
530
  }
531
531
  if (kind !== "update") throw new Error(`editing_row_action.kind must be "update" or "agent" \u2014 received ${describeValue(kind)}.`);
532
532
  const steps = input["steps"];
533
533
  if (!Array.isArray(steps) || steps.length === 0) throw new Error(`An update action needs \`steps\`: a non-empty array \u2014 received ${describeValue(steps)}.`);
534
534
  const made = [];
535
535
  for (let i = 0; i < steps.length; i += 1) made.push(await stepFromAgent(steps[i], i, fields, check));
536
- return { ...base, steps: made };
536
+ return { ...base2, steps: made };
537
537
  }
538
538
  function actionForAgent(action3, fields) {
539
539
  const key = (id) => fields.find((f) => f.id === id)?.key ?? id;
@@ -949,6 +949,9 @@ function fieldTypeLabel(field2) {
949
949
  }
950
950
 
951
951
  // src/gridPage.ts
952
+ import { holdsNumbers } from "@ai-matrx/records/first-page";
953
+ import { holdsNumbers as holdsNumbers2, pageSortFor, sortAsFor } from "@ai-matrx/records/first-page";
954
+ import { containsPattern } from "@ai-matrx/records/data";
952
955
  function sortRefusal(f) {
953
956
  if (!computedOnRead(f)) return null;
954
957
  return `${fieldName(f)} is worked out each time it is read, so the store keeps no value to sort the whole table by. Sort by a column it is worked out from.`;
@@ -961,26 +964,6 @@ function computedOnRead(f) {
961
964
  const kind = String(editorKindFor(f));
962
965
  return (f.type === "formula" || kind === "formula" || kind === "lookup" || kind === "rollup") && String(f.compute_on ?? "read") === "read";
963
966
  }
964
- function holdsNumbers(field2) {
965
- const kind = String(editorKindFor(field2));
966
- if (kind === "number" || kind === "currency" || kind === "percent") return true;
967
- return String((field2.config ?? {})["system"] ?? "") === "autonumber";
968
- }
969
- function sortAsFor(field2) {
970
- const kind = String(editorKindFor(field2));
971
- if (holdsNumbers(field2)) return "number";
972
- if (kind === "datetime") return "date";
973
- return "text";
974
- }
975
- function pageSortFor(fields, sort) {
976
- if (!sort) return [];
977
- const field2 = fields.find((f) => f.key === sort.id);
978
- if (!field2) return [];
979
- return [{ field: field2.key, direction: sort.direction === "desc" ? "desc" : "asc", as: sortAsFor(field2) }];
980
- }
981
- function containsPattern(text) {
982
- return `(?i)${text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`;
983
- }
984
967
  var BLANK_VALUE = "__empty__";
985
968
  var field = (f) => ({ field: f.id });
986
969
  var constant = (value) => ({ const: value });
@@ -1076,12 +1059,12 @@ function dayWindow(day, holdsDays) {
1076
1059
  const ymd = (t) => `${t.getUTCFullYear()}-${String(t.getUTCMonth() + 1).padStart(2, "0")}-${String(t.getUTCDate()).padStart(2, "0")}`;
1077
1060
  return { from: ymd(new Date(Date.UTC(y, (m ?? 1) - 1, d ?? 1))), to: ymd(new Date(Date.UTC(y, (m ?? 1) - 1, (d ?? 1) + 1))) };
1078
1061
  }
1079
- function storeQuestion(fields, base, columnFilters, now = /* @__PURE__ */ new Date()) {
1062
+ function storeQuestion(fields, base2, columnFilters, now = /* @__PURE__ */ new Date()) {
1080
1063
  const refused = [];
1081
1064
  const flat = {};
1082
1065
  const rules = [];
1083
- if (base && isRuleFilter(base)) rules.push(base);
1084
- else if (base) Object.assign(flat, base);
1066
+ if (base2 && isRuleFilter(base2)) rules.push(base2);
1067
+ else if (base2) Object.assign(flat, base2);
1085
1068
  for (const [key, value] of Object.entries(columnFilters)) {
1086
1069
  if (!value) continue;
1087
1070
  const f = fields.find((candidate) => candidate.key === key);
@@ -1622,32 +1605,7 @@ function useLabelWait(field2) {
1622
1605
  }
1623
1606
 
1624
1607
  // src/gridLook.ts
1625
- function defaultSortOf(table, fields) {
1626
- const raw = table?.default_sort ?? null;
1627
- const first = Array.isArray(raw) ? raw[0] : raw;
1628
- let name = null;
1629
- let direction = "asc";
1630
- if (typeof first === "string") {
1631
- const trimmed = first.trim();
1632
- if (trimmed === "") return null;
1633
- if (trimmed.startsWith("-")) {
1634
- name = trimmed.slice(1).trim();
1635
- direction = "desc";
1636
- } else {
1637
- const [head, tail] = trimmed.split(/\s+/);
1638
- name = head ?? null;
1639
- if (tail && tail.toLowerCase() === "desc") direction = "desc";
1640
- }
1641
- } else if (first && typeof first === "object") {
1642
- const entry = first;
1643
- const named = entry["field"] ?? entry["key"] ?? entry["id"];
1644
- name = typeof named === "string" ? named : null;
1645
- if (String(entry["direction"] ?? "").toLowerCase() === "desc") direction = "desc";
1646
- }
1647
- if (!name) return null;
1648
- const field2 = fields.find((f) => f.key === name) ?? fields.find((f) => f.id === name);
1649
- return field2 ? { id: field2.key, direction } : null;
1650
- }
1608
+ import { defaultSortOf } from "@ai-matrx/records/first-page";
1651
1609
  var ROW_HEIGHT_PX = {
1652
1610
  compact: 28,
1653
1611
  normal: void 0,
@@ -2005,7 +1963,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
2005
1963
  const [to, setTo] = useState4(null);
2006
1964
  const [preview, setPreview] = useState4(null);
2007
1965
  const [asking, setAsking] = useState4(false);
2008
- const [refusal4, setRefusal] = useState4(null);
1966
+ const [refusal3, setRefusal] = useState4(null);
2009
1967
  const [busy, setBusy] = useState4(false);
2010
1968
  const [said2, setSaid] = useState4(null);
2011
1969
  const name = fieldName(field2);
@@ -2103,7 +2061,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
2103
2061
  preview.keptAside > 0 ? `; ${preview.keptAside} ${preview.keptAside === 1 ? "value does" : "values do"} not fit and will be kept aside with ${preview.keptAside === 1 ? "its record" : "their records"}, with the reason \u2014 nothing is deleted` + (preview.examples.length > 0 ? ` (for example ${preview.examples.map((e) => `\u201C${e}\u201D`).join(", ")})` : "") : "",
2104
2062
  preview.partial ? ". Counted over the first 1,000 different values." : "."
2105
2063
  ] }) : null,
2106
- refusal4 ? /* @__PURE__ */ jsx6(RefusalNotice, { error: refusal4 }) : null,
2064
+ refusal3 ? /* @__PURE__ */ jsx6(RefusalNotice, { error: refusal3 }) : null,
2107
2065
  said2 ? /* @__PURE__ */ jsx6("p", { role: "status", className: "text-[11px] text-muted-foreground", "data-records-retype-done": "", children: said2 }) : null
2108
2066
  ] });
2109
2067
  }
@@ -2879,10 +2837,10 @@ function TableDetails({
2879
2837
  if (slots.details.current === slot) slots.details.current = null;
2880
2838
  };
2881
2839
  }, [slots]);
2882
- const write = async (patch, base) => {
2840
+ const write = async (patch, base2) => {
2883
2841
  setBusy(true);
2884
2842
  setRefused(null);
2885
- const written = await (0, writeOnTheWinningVersion_exports.updateOnTheWinningVersion)(client, tableId, patch, await (0, recordVersions_exports.readTableVersionNow)(client, tableId), base);
2843
+ const written = await (0, writeOnTheWinningVersion_exports.updateOnTheWinningVersion)(client, tableId, patch, await (0, recordVersions_exports.readTableVersionNow)(client, tableId), base2);
2886
2844
  setBusy(false);
2887
2845
  if (!written.ok) {
2888
2846
  setRefused(refusalSentence(written.error));
@@ -3981,13 +3939,13 @@ function styleFromDecorations(decorations, fields) {
3981
3939
  return style;
3982
3940
  }
3983
3941
  function resolveTableStyle(decorations, fields, viewStyle) {
3984
- const base = styleFromDecorations(decorations, fields);
3985
- if (!viewStyle) return base;
3986
- const colorBy = viewStyle.colorBy ?? base.colorBy;
3987
- const rules = viewStyle.rules ?? base.rules;
3988
- const rows = viewStyle.rows ?? base.rows;
3989
- const columns = viewStyle.columns ?? base.columns;
3990
- const cells = viewStyle.cells ?? base.cells;
3942
+ const base2 = styleFromDecorations(decorations, fields);
3943
+ if (!viewStyle) return base2;
3944
+ const colorBy = viewStyle.colorBy ?? base2.colorBy;
3945
+ const rules = viewStyle.rules ?? base2.rules;
3946
+ const rows = viewStyle.rows ?? base2.rows;
3947
+ const columns = viewStyle.columns ?? base2.columns;
3948
+ const cells = viewStyle.cells ?? base2.cells;
3991
3949
  return {
3992
3950
  version: 1,
3993
3951
  ...colorBy !== void 0 ? { colorBy } : {},
@@ -4406,7 +4364,7 @@ function RelationPicker({ field: field2, value, onChange, disabled, id, classNam
4406
4364
  const client = useOptionalRecordsClient3();
4407
4365
  const [rows, setRows] = useState12(null);
4408
4366
  const [words2, setWords] = useState12({});
4409
- const [refusal4, setRefusal] = useState12(null);
4367
+ const [refusal3, setRefusal] = useState12(null);
4410
4368
  const [search, setSearch] = useState12("");
4411
4369
  const [open, setOpenState] = useState12(autoOpen === true);
4412
4370
  const onCloseRef = useRef7(onClose);
@@ -4590,8 +4548,8 @@ function RelationPicker({ field: field2, value, onChange, disabled, id, classNam
4590
4548
  })),
4591
4549
  onPick: toggle,
4592
4550
  notice: /* @__PURE__ */ jsxs13(Fragment4, { children: [
4593
- refusal4 ? /* @__PURE__ */ jsx15(RefusalLine, { error: refusal4, className: "p-2" }) : null,
4594
- !rows && !refusal4 ? /* @__PURE__ */ jsx15("p", { className: "p-2 text-xs text-muted-foreground", children: "Reading\u2026" }) : null,
4551
+ refusal3 ? /* @__PURE__ */ jsx15(RefusalLine, { error: refusal3, className: "p-2" }) : null,
4552
+ !rows && !refusal3 ? /* @__PURE__ */ jsx15("p", { className: "p-2 text-xs text-muted-foreground", children: "Reading\u2026" }) : null,
4595
4553
  full ? /* @__PURE__ */ jsxs13("p", { className: "p-2 text-xs text-muted-foreground", children: [
4596
4554
  fieldName(field2),
4597
4555
  " can point at ",
@@ -5029,500 +4987,35 @@ import { Badge as Badge5, cn as cn19 } from "@ai-matrx/design-system";
5029
4987
  import { createContext as createContext4, useContext as useContext4 } from "react";
5030
4988
 
5031
4989
  // src/firstPage.ts
5032
- import { asRecordsDataSource, createRecordsClient, recordingDataSource } from "@ai-matrx/records/core";
5033
- import { isUuidShape as isUuidShape3 } from "@ai-matrx/kit/uuid";
5034
-
5035
- // src/groupReads.ts
5036
- function groupedPageSort(fields, groupKey, sort) {
5037
- if (!groupKey) return sort;
5038
- const field2 = fields.find((f) => f.key === groupKey);
5039
- if (!field2) return sort;
5040
- return [{ field: groupKey, direction: "asc", as: sortAsFor(field2) }, ...sort.filter((s) => s.field !== groupKey)];
5041
- }
5042
- function chosenEntries(chosen) {
5043
- return JSON.parse(JSON.stringify(Object.entries(chosen).sort())).filter(([, op2]) => op2 in MEASURE_LABEL);
5044
- }
5045
- function groupFactMeasures(chosen) {
5046
- return [{ op: "count" }, ...chosenEntries(chosen).filter(([, op2]) => op2 !== "count").map(([key, op2]) => ({ op: op2, key }))];
5047
- }
5048
- var REVERSE_CELL_CHIPS = 3;
4990
+ import { bindFirstPageCodec } from "@ai-matrx/records/first-page";
5049
4991
 
5050
4992
  // src/viewKeys.ts
5051
- var STORE_KEEPS_TIMELINE = true;
5052
- var ALL = ["grid", "kanban", "calendar", "gallery", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list"];
5053
- var HIDES = ["grid", "gallery", "kanban", "calendar", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list"];
5054
- var GRIDS = ["grid"];
5055
- var VIEW_KEYS = [
5056
- { path: "layout", shape: "kind", layouts: ALL, writer: "caller" },
5057
- { path: "filters", shape: "filter", layouts: ALL, writer: "caller" },
5058
- { path: "where", shape: "rule", layouts: ALL, writer: "caller" },
5059
- { path: "group_field", shape: "field", layouts: ["kanban", ...STORE_KEEPS_TIMELINE ? ["timeline"] : []], writer: "caller" },
5060
- { path: "swimlane_field", shape: "field:lane", layouts: ["kanban"], writer: "caller" },
5061
- { path: "collapsed_columns", shape: "values", layouts: ["kanban"], writer: "caller" },
5062
- { path: "measure", shape: "field:number", layouts: ["kanban"], writer: "caller" },
5063
- { path: "date_field", shape: "field:date", layouts: ["calendar"], writer: "caller" },
5064
- ...STORE_KEEPS_TIMELINE ? [
5065
- { path: "start_field", shape: "field:date", layouts: ["timeline"], writer: "caller" },
5066
- { path: "end_field", shape: "field:date", layouts: ["calendar", "timeline"], writer: "caller" }
5067
- ] : [],
5068
- { path: "image_field", shape: "field", layouts: ["gallery"], writer: "caller" },
5069
- { path: "sorts", shape: "sorts", layouts: ALL, writer: "caller" },
5070
- { path: "rule_id", shape: "uuid", layouts: ALL, writer: "caller" },
5071
- { path: "is_default", shape: "boolean", layouts: ALL, writer: "caller" },
5072
- { path: "presentation", shape: "presentation", layouts: ALL, writer: "caller" },
5073
- { path: "presentation.style", shape: "style", layouts: ALL, writer: "caller" },
5074
- { path: "presentation.formats", shape: "object", layouts: GRIDS, writer: "caller" },
5075
- { path: "presentation.frozen", shape: "fields", layouts: GRIDS, writer: "caller" },
5076
- { path: "presentation.grouping", shape: "grouping", layouts: ["grid", "gallery", "list"], writer: "caller" },
5077
- { path: "presentation.widths", shape: "widths", layouts: GRIDS, writer: "caller" },
5078
- { path: "presentation.rowHeight", shape: "row_height", layouts: GRIDS, writer: "caller" },
5079
- { path: "presentation.hiddenFields", shape: "fields", layouts: HIDES, writer: "caller" },
5080
- { path: "presentation.cardHidden", shape: "fields", layouts: ["kanban", "calendar", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list", "gallery"], writer: "caller" },
5081
- { path: "presentation.columnOrder", shape: "fields", layouts: GRIDS, writer: "caller" },
5082
- { path: "presentation.gallerySize", shape: "gallery_size", layouts: ["gallery"], writer: "caller" },
5083
- { path: "presentation.wrap", shape: "boolean", layouts: GRIDS, writer: "caller" },
5084
- { path: "presentation.wrapColumns", shape: "fields", layouts: GRIDS, writer: "caller" },
5085
- { path: "presentation.fit", shape: "fit", layouts: GRIDS, writer: "caller" },
5086
- { path: "presentation.freezeFirst", shape: "boolean", layouts: GRIDS, writer: "caller" },
5087
- { path: "presentation.footer", shape: "footer", layouts: GRIDS, writer: "caller" },
5088
- { path: "presentation.summaries", shape: "summaries", layouts: GRIDS, writer: "caller" },
5089
- { path: "grid", shape: "grid", layouts: GRIDS, writer: "caller" },
5090
- { path: "hidden_fields", shape: "input", layouts: HIDES, writer: "input" },
5091
- { path: "table_id", shape: "server", layouts: ALL, writer: "server" },
5092
- { path: "order", shape: "server", layouts: GRIDS, writer: "server" },
5093
- { path: "moved_from", shape: "server", layouts: ALL, writer: "server" }
5094
- ];
5095
- var STORE_KEPT_LAYOUTS = ["grid", "kanban", "calendar", "gallery", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list"];
5096
- function storeKeepsLayout(layout) {
5097
- return STORE_KEPT_LAYOUTS.includes(layout);
5098
- }
5099
- function viewKeysFor(layout) {
5100
- return VIEW_KEYS.filter((k) => k.layouts.includes(layout)).map((k) => k.path);
5101
- }
5102
- var KINDS = STORE_KEPT_LAYOUTS;
5103
- function viewSettings(definition, rowFilters) {
5104
- const data = definition ?? {};
5105
- const text = (key) => {
5106
- const v = data[key];
5107
- return typeof v === "string" && v !== "" ? v : null;
5108
- };
5109
- const layout = String(data["layout"] ?? "grid");
5110
- const flat = rowFilters ?? (isObject2(data["filters"]) ? data["filters"] : null);
5111
- const moved = data["moved_from"];
5112
- return {
5113
- layout: KINDS.includes(layout) ? layout : "grid",
5114
- filters: flat && Object.keys(flat).length > 0 ? flat : null,
5115
- where: isRule(data["where"]) ? data["where"] : null,
5116
- groupField: text("group_field"),
5117
- swimlaneField: text("swimlane_field"),
5118
- collapsedColumns: Array.isArray(data["collapsed_columns"]) ? data["collapsed_columns"].filter((v) => ["string", "number", "boolean"].includes(typeof v)).map(String) : [],
5119
- measure: text("measure"),
5120
- dateField: text("date_field"),
5121
- startField: text("start_field"),
5122
- endField: text("end_field"),
5123
- imageField: text("image_field"),
5124
- sorts: parseSorts(data["sorts"]),
5125
- ruleId: text("rule_id"),
5126
- isDefault: data["is_default"] === true || data["is_default"] === "true",
5127
- presentation: parseGridPresentation(data["presentation"]),
5128
- movedFrom: isObject2(moved) ? moved : null
5129
- };
5130
- }
5131
- function viewSettingsFor(settings, layout) {
5132
- const reads = new Set(viewKeysFor(layout));
5133
- const out = { layout: settings.layout };
5134
- const take = (key, path) => {
5135
- if (reads.has(path)) out[key] = settings[key];
5136
- };
5137
- take("filters", "filters");
5138
- take("where", "where");
5139
- take("groupField", "group_field");
5140
- take("swimlaneField", "swimlane_field");
5141
- take("collapsedColumns", "collapsed_columns");
5142
- take("measure", "measure");
5143
- take("dateField", "date_field");
5144
- take("startField", "start_field");
5145
- take("endField", "end_field");
5146
- take("imageField", "image_field");
5147
- take("sorts", "sorts");
5148
- take("ruleId", "rule_id");
5149
- take("isDefault", "is_default");
5150
- const p = settings.presentation;
5151
- const look = {};
5152
- for (const [key, value] of Object.entries(p)) {
5153
- if (reads.has(`presentation.${key}`)) look[key] = value;
5154
- }
5155
- out.presentation = look;
5156
- return out;
5157
- }
5158
- function viewSettingsPatch(patch) {
5159
- const out = {};
5160
- const field2 = (key, path) => {
5161
- if (patch[key] !== void 0) out[path] = patch[key] || null;
5162
- };
5163
- if (patch.layout !== void 0 && storeKeepsLayout(patch.layout)) out["layout"] = patch.layout;
5164
- field2("groupField", "group_field");
5165
- field2("swimlaneField", "swimlane_field");
5166
- field2("measure", "measure");
5167
- field2("dateField", "date_field");
5168
- if (STORE_KEEPS_TIMELINE) {
5169
- field2("startField", "start_field");
5170
- field2("endField", "end_field");
5171
- }
5172
- field2("imageField", "image_field");
5173
- field2("ruleId", "rule_id");
5174
- if (patch.collapsedColumns !== void 0) out["collapsed_columns"] = patch.collapsedColumns ?? [];
5175
- if (patch.sorts !== void 0) out["sorts"] = patch.sorts ?? [];
5176
- if (patch.where !== void 0) out["where"] = patch.where ?? null;
5177
- if (patch.isDefault !== void 0) out["is_default"] = patch.isDefault === true;
5178
- if (patch.presentation !== void 0) {
5179
- out["presentation"] = !patch.presentation || presentationIsEmpty(patch.presentation) ? null : JSON.parse(presentationDocument(patch.presentation));
5180
- }
5181
- return out;
5182
- }
5183
- function isObject2(raw) {
5184
- return Boolean(raw) && typeof raw === "object" && !Array.isArray(raw);
5185
- }
5186
- function isRule(raw) {
5187
- if (!isObject2(raw)) return false;
5188
- const node = raw;
5189
- return typeof node.op === "string" && Array.isArray(node.args);
5190
- }
5191
- function parseSorts(raw) {
5192
- let list = raw;
5193
- if (typeof raw === "string") {
5194
- try {
5195
- list = raw.trim() === "" ? [] : JSON.parse(raw);
5196
- } catch {
5197
- return [];
5198
- }
5199
- }
5200
- if (!Array.isArray(list)) return [];
5201
- return list.filter((s) => isObject2(s) && typeof s.field === "string").map((s) => ({ field: s.field, direction: s.direction === "desc" ? "desc" : "asc" }));
5202
- }
5203
-
5204
- // src/views.ts
5205
- var VIEW_LAYOUTS = ["grid", "kanban", "calendar", "gallery", "timeline", "list"];
5206
- var LAYOUT_LABEL = {
5207
- grid: "Grid",
5208
- kanban: "Kanban",
5209
- calendar: "Calendar",
5210
- gallery: "Gallery",
5211
- timeline: "Timeline",
5212
- list: "List"
5213
- };
5214
- function wordsList(words2) {
5215
- const clean = words2.map((w) => w.trim()).filter((w) => w !== "");
5216
- if (clean.length <= 1) return clean.join("");
5217
- return `${clean.slice(0, -1).join(", ")} and ${clean[clean.length - 1]}`;
5218
- }
5219
- var VIEW_NEEDS = {
5220
- grid: null,
5221
- // A list reads nothing a table can lack: rows, titled, grouped only when the person chooses.
5222
- list: null,
5223
- kanban: {
5224
- kind: "choice",
5225
- viewKey: "groupField",
5226
- blocking: true,
5227
- starter: { label: "Status", type: "select", options: ["To do", "In progress", "Done"] },
5228
- pick: "Pick the choice column the board's columns come from.",
5229
- missing: "This table has no choice column to make the board's columns from.",
5230
- does: (label) => `Make it work adds a ${label} column with the choices below and groups the board by it.`,
5231
- ask: (label, options) => `Add a choice column called ${label} to this table${options.length > 0 ? ` with the choices ${wordsList(options)}` : ""}, then group the Kanban board by it.`
5232
- },
5233
- calendar: {
5234
- kind: "date",
5235
- viewKey: "dateField",
5236
- blocking: true,
5237
- starter: { label: "Date", type: "datetime" },
5238
- pick: "Pick the date column the calendar places records by.",
5239
- missing: "This table has no date column to place records on.",
5240
- does: (label) => `Make it work adds a ${label} column and lays the calendar out by it.`,
5241
- ask: (label) => `Add a date column called ${label} to this table, then lay the Calendar out by it.`
5242
- },
5243
- gallery: {
5244
- kind: "file",
5245
- viewKey: "imageField",
5246
- blocking: false,
5247
- starter: { label: "Photo", type: "attachment" },
5248
- pick: "Pick the file column each card shows as its picture.",
5249
- missing: "The cards have no picture because this table has no file column.",
5250
- does: (label) => `Make it work adds a ${label} column and shows it on each card.`,
5251
- ask: (label) => `Add a file column called ${label} to this table, then show it as the picture on each Gallery card.`
5252
- },
5253
- timeline: {
5254
- kind: "date",
5255
- viewKey: "dateField",
5256
- blocking: true,
5257
- starter: { label: "Start", type: "datetime" },
5258
- pick: "Pick the date column each bar starts on.",
5259
- missing: "This table has no date column to place records on.",
5260
- does: (label) => `Make it work adds a ${label} column and lays the timeline out by it.`,
5261
- ask: (label) => `Add a date column called ${label} to this table, then lay the Timeline out by it.`
5262
- }
5263
- };
5264
- function freeColumnName(wanted, taken) {
5265
- const held = new Set(taken.map((t) => t.trim().toLowerCase()));
5266
- const base = wanted.trim() === "" ? "Column" : wanted.trim();
5267
- if (!held.has(base.toLowerCase())) return base;
5268
- for (let n = 2; n < 100; n += 1) {
5269
- const next = `${base} ${n}`;
5270
- if (!held.has(next.toLowerCase())) return next;
5271
- }
5272
- return base;
5273
- }
5274
- function viewOrderOf(definition) {
5275
- const raw = definition?.["order"];
5276
- return raw === "manual" ? "manual" : raw === "sorted" ? "sorted" : null;
5277
- }
5278
- function defaultViewOf(views) {
5279
- return views.find((v) => v.isDefault);
5280
- }
5281
- var LAYOUT_FIELD_KIND = {
5282
- grid: null,
5283
- kanban: "choice",
5284
- calendar: "date",
5285
- gallery: "file",
5286
- timeline: "date",
5287
- list: null
5288
- };
5289
- var PAGE_VIEWS = [...VIEW_LAYOUTS, "dashboards", "archived"];
5290
- var PAGE_VIEW_LABEL = {
5291
- ...LAYOUT_LABEL,
5292
- dashboards: "Dashboards",
5293
- archived: "Archived"
5294
- };
5295
- var PAGE_VIEW_SPELLINGS = {
5296
- grid: "grid",
5297
- table: "grid",
5298
- rows: "grid",
5299
- list: "list",
5300
- kanban: "kanban",
5301
- board: "kanban",
5302
- pipeline: "kanban",
5303
- calendar: "calendar",
5304
- month: "calendar",
5305
- schedule: "calendar",
5306
- gallery: "gallery",
5307
- cards: "gallery",
5308
- timeline: "timeline",
5309
- gantt: "timeline",
5310
- dashboards: "dashboards",
5311
- dashboard: "dashboards",
5312
- charts: "dashboards",
5313
- archived: "archived",
5314
- archive: "archived",
5315
- // The grid's row action says "Delete" and the store soft-deletes, so the word
5316
- // a person types is as likely to be the one the button used as the one this
5317
- // view is called. Both land in the same place; neither dies.
5318
- deleted: "archived",
5319
- trash: "archived",
5320
- removed: "archived"
5321
- };
5322
- function pageViewFromParam(raw) {
5323
- if (typeof raw !== "string") return null;
5324
- const token2 = raw.trim().toLowerCase();
5325
- if (token2 === "") return null;
5326
- return PAGE_VIEW_SPELLINGS[token2] ?? null;
5327
- }
5328
- function unknownViewLine(raw) {
5329
- return `The link asked for a view called \u201C${raw}\u201D, which this table has no view for, so you are looking at ${PAGE_VIEW_LABEL.grid}. The views this table has are ${PAGE_VIEWS.map((v) => PAGE_VIEW_LABEL[v]).join(", ")} \u2014 pick one above and the address follows it.`;
5330
- }
5331
- function viewDocument(spec) {
5332
- const out = {
5333
- // A layout the store does not keep yet is not sent: the view is saved as a grid (`STORE_KEPT_LAYOUTS`).
5334
- layout: storeKeepsLayout(spec.layout) ? spec.layout : "grid",
5335
- sorts: spec.sorts ?? [],
5336
- is_default: spec.isDefault === true
5337
- };
5338
- if (spec.groupField) out["group_field"] = spec.groupField;
5339
- if (spec.swimlaneField) out["swimlane_field"] = spec.swimlaneField;
5340
- if (spec.collapsedColumns && spec.collapsedColumns.length > 0) out["collapsed_columns"] = spec.collapsedColumns;
5341
- if (spec.measure) out["measure"] = spec.measure;
5342
- if (spec.dateField) out["date_field"] = spec.dateField;
5343
- if (STORE_KEEPS_TIMELINE && spec.startField) out["start_field"] = spec.startField;
5344
- if (STORE_KEEPS_TIMELINE && spec.endField) out["end_field"] = spec.endField;
5345
- if (spec.imageField) out["image_field"] = spec.imageField;
5346
- if (spec.ruleId) out["rule_id"] = spec.ruleId;
5347
- if (spec.where) out["where"] = spec.where;
5348
- if (spec.presentation && !presentationIsEmpty(spec.presentation)) {
5349
- out["presentation"] = JSON.parse(presentationDocument(spec.presentation));
5350
- }
5351
- return out;
5352
- }
5353
- function viewFromRow(row) {
5354
- const data = row.definition ?? {};
5355
- const k = viewSettings(data, row.filters && Object.keys(row.filters).length > 0 ? row.filters : null);
5356
- const tableFromDefinition = typeof data["table_id"] === "string" && data["table_id"] !== "" ? data["table_id"] : null;
5357
- return {
5358
- id: row.view_id,
5359
- name: row.name || "Untitled view",
5360
- subject: row.table_id ?? tableFromDefinition ?? "",
5361
- layout: k.layout,
5362
- groupField: k.groupField,
5363
- swimlaneField: k.swimlaneField,
5364
- collapsedColumns: k.collapsedColumns,
5365
- measure: k.measure,
5366
- dateField: k.dateField,
5367
- startField: k.startField,
5368
- endField: k.endField,
5369
- imageField: k.imageField,
5370
- sorts: k.sorts,
5371
- order: viewOrderOf(data),
5372
- ruleId: k.ruleId,
5373
- ...k.filters ? { filters: k.filters } : {},
5374
- where: k.where,
5375
- // The older table's own default view, carried in by the mover, IS this table's default —
5376
- // the mover wrote the row's column, which `custom.views` does not return. Read as anything
5377
- // else, the page would seed a second "All records" beside it and open on that.
5378
- isDefault: k.isDefault || k.movedFrom?.["kind"] === "default_view",
5379
- presentation: k.presentation,
5380
- movedFrom: k.movedFrom
5381
- };
5382
- }
5383
- async function declareView(client, spec) {
5384
- return client.viewDeclare({
5385
- table_id: spec.subject,
5386
- spec: {
5387
- name: spec.name,
5388
- ...spec.filters ? { filters: spec.filters } : {},
5389
- definition: viewDocument(spec)
5390
- }
5391
- });
5392
- }
5393
- async function saveViewPatch(client, tableId, viewId, patch) {
5394
- const definition = viewPatchDocument(patch);
5395
- const renamed = patch.name !== void 0 && patch.name.trim() !== "";
5396
- const refiltered = patch.filters !== void 0;
5397
- return client.viewDeclare({
5398
- table_id: tableId,
5399
- spec: {
5400
- view_id: viewId,
5401
- ...renamed ? { name: patch.name.trim() } : {},
5402
- ...refiltered ? { filters: patch.filters ?? null } : {},
5403
- definition
5404
- }
5405
- });
5406
- }
5407
- function viewPatchDocument(patch) {
5408
- const { name: _name, subject: _subject, filters: _filters, ...keys } = patch;
5409
- return viewSettingsPatch(keys);
5410
- }
5411
- function viewPatchFor(view, patch) {
5412
- if (!view.isDefault) return patch;
5413
- const { layout: _layout, isDefault: _isDefault, ...kept } = patch;
5414
- return kept;
5415
- }
5416
- async function designateView(client, tableId, viewId, layout) {
5417
- return client.viewDesignate({ table_id: tableId, view_id: viewId, layout });
5418
- }
5419
-
5420
- // src/viewLook.ts
5421
- var LOOK_KEYS = [
5422
- "layout",
5423
- "groupField",
5424
- "swimlaneField",
5425
- "collapsedColumns",
5426
- "measure",
5427
- "dateField",
5428
- "startField",
5429
- "endField",
5430
- "imageField",
5431
- "sorts",
5432
- "where",
5433
- "presentation"
5434
- ];
5435
- function lookPart(patch) {
5436
- const out = {};
5437
- for (const key of LOOK_KEYS) {
5438
- if (patch[key] !== void 0) out[key] = patch[key];
5439
- }
5440
- return out;
5441
- }
5442
- function lookDocument(look) {
5443
- return viewSettingsPatch(look);
5444
- }
5445
- function lookFromDocument(doc) {
5446
- const data = doc ?? {};
5447
- const read = viewSettings(data);
5448
- const out = {};
5449
- const has = (key) => Object.prototype.hasOwnProperty.call(data, key);
5450
- if (has("layout") && VIEW_LAYOUTS.includes(String(data["layout"]))) {
5451
- out.layout = data["layout"];
5452
- }
5453
- if (has("group_field")) out.groupField = read.groupField;
5454
- if (has("swimlane_field")) out.swimlaneField = read.swimlaneField;
5455
- if (has("collapsed_columns")) out.collapsedColumns = read.collapsedColumns;
5456
- if (has("measure")) out.measure = read.measure;
5457
- if (has("date_field")) out.dateField = read.dateField;
5458
- if (has("start_field")) out.startField = read.startField;
5459
- if (has("end_field")) out.endField = read.endField;
5460
- if (has("image_field")) out.imageField = read.imageField;
5461
- if (has("sorts")) out.sorts = read.sorts;
5462
- if (has("where")) out.where = read.where;
5463
- if (has("presentation")) out.presentation = parseGridPresentation(data["presentation"]);
5464
- return out;
5465
- }
5466
- function applyLook(view, look) {
5467
- if (!look) return view;
5468
- return { ...view, ...look };
5469
- }
5470
- function lookDiffers(view, look) {
5471
- if (!look) return false;
5472
- const shown4 = applyLook(view, look);
5473
- return LOOK_KEYS.some(
5474
- (key) => look[key] !== void 0 && JSON.stringify(shown4[key] ?? null) !== JSON.stringify(view[key] ?? null)
5475
- );
5476
- }
5477
- function saveToViewPlan(view, look) {
5478
- const patch = viewPatchFor(view, look);
5479
- const left = {};
5480
- if (look.layout !== void 0 && patch.layout === void 0 && look.layout !== view.layout) left.layout = look.layout;
5481
- return { patch, left: Object.keys(left).length > 0 ? left : null };
5482
- }
5483
- async function readLooks(client, tableId) {
5484
- const answered = await client.viewLookRead({ table_id: tableId });
5485
- if (!answered.ok) return answered;
5486
- const out = {};
5487
- for (const [viewId, row] of Object.entries(answered.data ?? {})) {
5488
- out[viewId] = lookFromDocument(row?.look ?? null);
5489
- }
5490
- return { ok: true, data: out };
5491
- }
5492
- async function keepLook(client, tableId, viewId, look) {
5493
- const doc = look ? lookDocument(look) : null;
5494
- return client.viewLookSet({ table_id: tableId, view_id: viewId, look: doc && Object.keys(doc).length > 0 ? doc : null });
5495
- }
5496
- var LOOK_WORDS = {
5497
- /** The reason, for a tooltip or a screen reader — never a line on the page (interface-text). */
5498
- yours: "You changed how this view looks. Only you see it.",
5499
- /** The visible label for the same fact. */
5500
- yoursLabel: "Only you see this",
5501
- saveToView: "Save to view",
5502
- saveAsNew: "Save as new view",
5503
- reset: "Reset to view",
5504
- /** The one button your look's doors fold into when the toolbar row has no room for three. */
5505
- folded: "Your look",
5506
- newName: "Name for the new view"
4993
+ import * as base from "@ai-matrx/records/views";
4994
+ import {
4995
+ STORE_KEEPS_TIMELINE,
4996
+ STORE_KEPT_LAYOUTS,
4997
+ VIEW_KEYS,
4998
+ storeKeepsLayout,
4999
+ viewKeysFor,
5000
+ viewSettingsFor
5001
+ } from "@ai-matrx/records/views";
5002
+ var gridPresentationCodec = {
5003
+ parse: parseGridPresentation,
5004
+ isEmpty: presentationIsEmpty,
5005
+ toDocument: (presentation) => JSON.parse(presentationDocument(presentation))
5507
5006
  };
5508
-
5509
- // src/entityQuery.ts
5510
- function entityTableQuery(options = {}) {
5511
- const search = (options.search ?? "").trim();
5512
- return { ...options.pageSize ? { pageSize: options.pageSize } : {}, ...search ? { search } : {} };
5513
- }
5514
- function entityChartQuestion(input) {
5515
- const m = input.measure ?? { op: "count" };
5516
- return {
5517
- ...input.by ? { by: [input.by] } : {},
5518
- show: [m.op === "count" ? "count" : { op: m.op, of: m.of }],
5519
- ...input.where ? { where: input.where } : {},
5520
- ...input.organization ? { organization: input.organization } : {}
5521
- };
5522
- }
5007
+ var boundViews = base.bindViewCodec(gridPresentationCodec);
5008
+ var { viewSettings, viewSettingsPatch } = boundViews;
5523
5009
 
5524
5010
  // src/firstPage.ts
5525
- var EMBEDDED_PAGE_SIZE = 50;
5011
+ import {
5012
+ EMBEDDED_PAGE_SIZE,
5013
+ TABLE_PAGE_SIZE,
5014
+ firstGridPageArgs,
5015
+ serverRowsOf,
5016
+ viewFilterOf
5017
+ } from "@ai-matrx/records/first-page";
5018
+ var { firstGridPageRequest, askTablePageSeed } = bindFirstPageCodec(gridPresentationCodec);
5526
5019
 
5527
5020
  // src/embeddedLook.tsx
5528
5021
  var EMBEDDED_LOOK = { blankEmpty: true, choiceDot: true, plainRelation: true };
@@ -6777,7 +6270,7 @@ function RetiredValues({
6777
6270
  }) {
6778
6271
  const client = useRecordsClient7();
6779
6272
  const [busy, setBusy] = useState20(null);
6780
- const [refusal4, setRefusal] = useState20(null);
6273
+ const [refusal3, setRefusal] = useState20(null);
6781
6274
  const [said2, setSaid] = useState20(null);
6782
6275
  const [missing, setMissing] = useState20(null);
6783
6276
  const kept = retiredValuesOf(document2);
@@ -6826,7 +6319,7 @@ function RetiredValues({
6826
6319
  mayWrite ? /* @__PURE__ */ jsx26(Button11, { size: "sm", variant: "outline", className: "h-6 px-2 text-xs", disabled: busy !== null, onClick: () => void restore(entry, index), "data-records-retired-restore": "", children: busy === id ? "Restoring\u2026" : "Restore" }) : null
6827
6320
  ] }),
6828
6321
  entry.reason ? /* @__PURE__ */ jsx26("p", { className: "text-[11px] text-muted-foreground", children: entry.reason }) : null,
6829
- refusal4?.key === id ? /* @__PURE__ */ jsx26(RefusalNotice, { error: refusal4.error }) : null,
6322
+ refusal3?.key === id ? /* @__PURE__ */ jsx26(RefusalNotice, { error: refusal3.error }) : null,
6830
6323
  missing === id ? /* @__PURE__ */ jsxs23("p", { className: "text-[11px] text-muted-foreground", children: [
6831
6324
  "No earlier version of ",
6832
6325
  name,
@@ -7681,7 +7174,7 @@ function ruleWords(rules) {
7681
7174
  function rulesChanged(was, now) {
7682
7175
  return ruleWords(was) !== ruleWords(now);
7683
7176
  }
7684
- function holdsNumbers2(field2) {
7177
+ function holdsNumbers3(field2) {
7685
7178
  return field2.type === "range";
7686
7179
  }
7687
7180
  function groupValue(value, numbers) {
@@ -7692,7 +7185,7 @@ function groupValue(value, numbers) {
7692
7185
  function FieldRulePreview({ field: field2, tableId, rules }) {
7693
7186
  const client = useRecordsClient9();
7694
7187
  const [preview, setPreview] = useState23(null);
7695
- const [refusal4, setRefusal] = useState23(null);
7188
+ const [refusal3, setRefusal] = useState23(null);
7696
7189
  const key = useMemo11(() => ruleWords(rules), [rules]);
7697
7190
  const latest = useRef13(rules);
7698
7191
  latest.current = rules;
@@ -7708,7 +7201,7 @@ function FieldRulePreview({ field: field2, tableId, rules }) {
7708
7201
  setRefusal(answer.error);
7709
7202
  return;
7710
7203
  }
7711
- const numbers = holdsNumbers2(field2);
7204
+ const numbers = holdsNumbers3(field2);
7712
7205
  const groups = answer.data.map((row) => ({ value: groupValue(row.groups[field2.key] ?? null, numbers), count: row.row_count }));
7713
7206
  setPreview(previewRuleChange(latest.current, groups, answer.data.length >= PREVIEW_GROUPS2));
7714
7207
  });
@@ -7718,7 +7211,7 @@ function FieldRulePreview({ field: field2, tableId, rules }) {
7718
7211
  clearTimeout(timer);
7719
7212
  };
7720
7213
  }, [client, tableId, field2.key, key]);
7721
- if (refusal4) return /* @__PURE__ */ jsx31(RefusalNotice, { error: refusal4 });
7214
+ if (refusal3) return /* @__PURE__ */ jsx31(RefusalNotice, { error: refusal3 });
7722
7215
  if (!preview) {
7723
7216
  return /* @__PURE__ */ jsxs27("p", { className: "text-[11px] text-muted-foreground", "data-records-rule-preview": "counting", children: [
7724
7217
  "Counting ",
@@ -7779,9 +7272,9 @@ function choiceDisplayPatch(field2, rows) {
7779
7272
  }
7780
7273
  function lookFollowsRenames(field2, look, renames) {
7781
7274
  if (renames.size === 0) return look;
7782
- const base = look ?? displayFormatOf(field2);
7783
- const choices = base && Array.isArray(base.options["choices"]) ? base.options["choices"] : null;
7784
- if (!base || !choices) return look;
7275
+ const base2 = look ?? displayFormatOf(field2);
7276
+ const choices = base2 && Array.isArray(base2.options["choices"]) ? base2.options["choices"] : null;
7277
+ if (!base2 || !choices) return look;
7785
7278
  let moved = false;
7786
7279
  const next = choices.map((c) => {
7787
7280
  const was = typeof c["value"] === "string" ? c["value"] : null;
@@ -7791,11 +7284,11 @@ function lookFollowsRenames(field2, look, renames) {
7791
7284
  return { ...c, value: now };
7792
7285
  });
7793
7286
  if (!moved) return look;
7794
- return { id: base.id, options: { ...base.options, choices: next } };
7287
+ return { id: base2.id, options: { ...base2.options, choices: next } };
7795
7288
  }
7796
7289
  function choiceLookFromList(field2, start, rows) {
7797
- const base = startingChoiceColors(field2, start.map((r) => r.words.trim()).filter((w) => w !== ""));
7798
- const colorRows = base.map((row) => {
7290
+ const base2 = startingChoiceColors(field2, start.map((r) => r.words.trim()).filter((w) => w !== ""));
7291
+ const colorRows = base2.map((row) => {
7799
7292
  const was = start.find((r) => choiceWord(r.words) === choiceWord(row.value));
7800
7293
  const now = was?.id ? rows.find((r) => r.id === was.id) : void 0;
7801
7294
  return now ? { value: row.value, color: now.color ?? null } : row;
@@ -8248,9 +7741,9 @@ function storageOf(field2) {
8248
7741
  }
8249
7742
  }
8250
7743
  function formatMenu(field2) {
8251
- const base = storageOf(field2);
8252
- if (base === null) return { groups: [], otherKinds: [] };
8253
- if (base === "formula") {
7744
+ const base2 = storageOf(field2);
7745
+ if (base2 === null) return { groups: [], otherKinds: [] };
7746
+ if (base2 === "formula") {
8254
7747
  const groups2 = [];
8255
7748
  for (const def of FIELD_FORMAT_LIST) {
8256
7749
  if (neverALook(def) || KIND_WORD[def.id] || def.id === "boolean") continue;
@@ -8260,7 +7753,7 @@ function formatMenu(field2) {
8260
7753
  }
8261
7754
  return { groups: groups2, otherKinds: [] };
8262
7755
  }
8263
- const groups = groupedFormatsForBase(base).map((g) => ({ group: g.group, formats: g.formats.filter((d) => !neverALook(d) && !KIND_WORD[d.id]) })).filter((g) => g.formats.length > 0);
7756
+ const groups = groupedFormatsForBase(base2).map((g) => ({ group: g.group, formats: g.formats.filter((d) => !neverALook(d) && !KIND_WORD[d.id]) })).filter((g) => g.formats.length > 0);
8264
7757
  const own3 = new Set(groups.flatMap((g) => g.formats.map((d) => d.id)));
8265
7758
  const otherKinds = [];
8266
7759
  for (const def of FIELD_FORMAT_LIST) {
@@ -10832,7 +10325,7 @@ function FieldControl({ field: field2, value, onChange, disabled, id, autoOpen,
10832
10325
  }
10833
10326
  function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
10834
10327
  const [text, setText] = useState32(() => openingText(field2, value));
10835
- const [refusal4, setRefusal] = useState32(null);
10328
+ const [refusal3, setRefusal] = useState32(null);
10836
10329
  const [why, setWhy] = useState32(void 0);
10837
10330
  const sent = useRef18(value);
10838
10331
  useEffect22(() => {
@@ -10863,11 +10356,11 @@ function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
10863
10356
  value: text,
10864
10357
  disabled,
10865
10358
  autoComplete: "off",
10866
- "aria-invalid": refusal4 ? true : void 0,
10359
+ "aria-invalid": refusal3 ? true : void 0,
10867
10360
  placeholder: helper ? typedDatePlaceholder(helper) : void 0,
10868
10361
  onChange: (e) => retype(e.target.value),
10869
10362
  onBlur: () => {
10870
- if (!refusal4) return;
10363
+ if (!refusal3) return;
10871
10364
  setText(openingText(field2, sent.current));
10872
10365
  setRefusal(null);
10873
10366
  }
@@ -10875,7 +10368,7 @@ function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
10875
10368
  ),
10876
10369
  helper && !disabled ? /* @__PURE__ */ jsx42(TypedDateHelper, { kind: helper, text, onText: retype, label: fieldName(field2) }) : null
10877
10370
  ] }),
10878
- refusal4 ? /* @__PURE__ */ jsx42(FloatingRefusal, { text: refusal4, why }) : null
10371
+ refusal3 ? /* @__PURE__ */ jsx42(FloatingRefusal, { text: refusal3, why }) : null
10879
10372
  ] });
10880
10373
  }
10881
10374
  function typedDatePlaceholder(helper) {
@@ -10979,7 +10472,7 @@ function inTheStoresOrder(options) {
10979
10472
  function OptionControl({ field: field2, value, onChange, disabled, id, autoOpen, onClose, onCancel, addsChoices, initialSearch, asForm, onChosen }) {
10980
10473
  const client = useOptionalRecordsClient10();
10981
10474
  const [options, setOptions] = useState32(null);
10982
- const [refusal4, setRefusal] = useState32(null);
10475
+ const [refusal3, setRefusal] = useState32(null);
10983
10476
  const [reread, setReread] = useState32(0);
10984
10477
  useEffect22(() => {
10985
10478
  if (!client) return;
@@ -11011,8 +10504,8 @@ function OptionControl({ field: field2, value, onChange, disabled, id, autoOpen,
11011
10504
  /* @__PURE__ */ jsx42("p", { className: "text-xs text-muted-foreground", children: "This is normally picked from a list. A page answered without an account cannot read that list, so type your answer and whoever receives it will match it up." })
11012
10505
  ] });
11013
10506
  }
11014
- if (refusal4)
11015
- return /* @__PURE__ */ jsx42("div", { id, children: /* @__PURE__ */ jsx42(RefusalLine, { error: refusal4 }) });
10507
+ if (refusal3)
10508
+ return /* @__PURE__ */ jsx42("div", { id, children: /* @__PURE__ */ jsx42(RefusalLine, { error: refusal3 }) });
11016
10509
  if (!options) return /* @__PURE__ */ jsx42("p", { id, className: "text-xs text-muted-foreground", children: "Reading this field's choices\u2026" });
11017
10510
  if (asForm && options.length > 0) {
11018
10511
  const titled = (option) => recordName(option.data, null, "Unnamed choice");
@@ -11751,7 +11244,7 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11751
11244
  startedFrom.current = null;
11752
11245
  }, []);
11753
11246
  const writeCellNow = useCallback10(
11754
- async (rowId, key, value, base, resent = false) => {
11247
+ async (rowId, key, value, base2, resent = false) => {
11755
11248
  const id = cellKey(rowId, key);
11756
11249
  const adding = isChoiceAddition(value) ? value : null;
11757
11250
  const shown4 = adding ? adding.value : value;
@@ -11768,7 +11261,7 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11768
11261
  let version = await versionOf(source, versions.current, versionReads.current, rowId);
11769
11262
  const drawnNow = await source.seen(rowId);
11770
11263
  const storedNow = rowsNow.current.find((r) => r.id === rowId)?.document?.[key];
11771
- if (drawnNow !== null && (version === null || drawnNow > version) && sameValue(storedNow, base)) {
11264
+ if (drawnNow !== null && (version === null || drawnNow > version) && sameValue(storedNow, base2)) {
11772
11265
  version = drawnNow;
11773
11266
  rememberVersion(versions.current, rowId, drawnNow);
11774
11267
  }
@@ -11797,13 +11290,13 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11797
11290
  if (written.ok) {
11798
11291
  rememberVersion(versions.current, rowId, written.data);
11799
11292
  source.wrote(rowId, written.data);
11800
- settling.current.set(id, base);
11801
- writtenRef.current?.({ rowId, key, before: base, after: shown4, version: written.data });
11293
+ settling.current.set(id, base2);
11294
+ writtenRef.current?.({ rowId, key, before: base2, after: shown4, version: written.data });
11802
11295
  afterWrite();
11803
11296
  return;
11804
11297
  }
11805
11298
  if (isUnsentWrite(written.error)) {
11806
- setRefusals((held) => ({ ...held, [id]: { error: written.error, conflict: null, attempted: value, unsent: true, base } }));
11299
+ setRefusals((held) => ({ ...held, [id]: { error: written.error, conflict: null, attempted: value, unsent: true, base: base2 } }));
11807
11300
  return;
11808
11301
  }
11809
11302
  setOptimistic((held) => {
@@ -11815,8 +11308,8 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11815
11308
  if (written.error.code === "stale_write") {
11816
11309
  if (conflict) rememberVersion(versions.current, rowId, conflict.current_version);
11817
11310
  else versions.current.delete(rowId);
11818
- if (conflict && !resent && sameValue(conflict.contested_fields[key], base)) {
11819
- await writeCellNow(rowId, key, value, base, true);
11311
+ if (conflict && !resent && sameValue(conflict.contested_fields[key], base2)) {
11312
+ await writeCellNow(rowId, key, value, base2, true);
11820
11313
  return;
11821
11314
  }
11822
11315
  }
@@ -11833,9 +11326,9 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11833
11326
  [client, reload, afterWrite, source]
11834
11327
  );
11835
11328
  const writeCell = useCallback10(
11836
- (rowId, key, value, base) => {
11329
+ (rowId, key, value, base2) => {
11837
11330
  const behind = queues.current.get(rowId) ?? Promise.resolve();
11838
- const next = behind.then(() => writeCellNow(rowId, key, value, base));
11331
+ const next = behind.then(() => writeCellNow(rowId, key, value, base2));
11839
11332
  queues.current.set(
11840
11333
  rowId,
11841
11334
  next.then(
@@ -12188,7 +11681,7 @@ function GridCell({
12188
11681
  };
12189
11682
  const value = editing ? editing.valueFor(row, field2) : row.document?.[field2.key];
12190
11683
  const state = editing ? editing.stateOf(row.id, field2.key) : null;
12191
- const refusal4 = editing ? editing.refusalOf(row.id, field2.key) : null;
11684
+ const refusal3 = editing ? editing.refusalOf(row.id, field2.key) : null;
12192
11685
  const editable = Boolean(editing) && canWrite && fieldIsEditable(field2);
12193
11686
  if (open && editing) {
12194
11687
  return /* @__PURE__ */ jsxs39("span", { "data-records-open-cell": "", className: "relative block w-full min-w-0", children: [
@@ -12225,10 +11718,10 @@ function GridCell({
12225
11718
  // state they are in, so only Discard is offered. It is INSIDE the open
12226
11719
  // cell, so pressing Discard is not "focus left the cell" — which would
12227
11720
  // commit the refused value one more time on its way out.
12228
- refusal4 && !refusal4.conflict ? /* @__PURE__ */ jsx44(
11721
+ refusal3 && !refusal3.conflict ? /* @__PURE__ */ jsx44(
12229
11722
  RefusalNotice,
12230
11723
  {
12231
- error: refusal4.error,
11724
+ error: refusal3.error,
12232
11725
  className: "py-1.5 text-left",
12233
11726
  onDiscard: () => editing.discard(row.id, field2.key)
12234
11727
  }
@@ -12253,14 +11746,14 @@ function GridCell({
12253
11746
  }
12254
11747
  ),
12255
11748
  answered ? null : /* @__PURE__ */ jsx44("span", { className: "text-xs text-muted-foreground", title: "nobody has answered this yet", children: "\u2014" }),
12256
- refusal4 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal4, field: field2, row, editing, typed: false }) : null
11749
+ refusal3 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: false }) : null
12257
11750
  ] });
12258
11751
  }
12259
11752
  if (editable && format?.id === "rating") {
12260
11753
  return /* @__PURE__ */ jsxs39("span", { "data-matrx-cell-control": "", className: "relative flex h-full w-full flex-wrap items-center gap-1.5", children: [
12261
11754
  /* @__PURE__ */ jsx44(FormattedValue, { value, format, onRate: (next) => editing?.setCell(row.id, field2.key, next), selectFirst: true }),
12262
11755
  state === "saving" ? /* @__PURE__ */ jsx44("span", { "data-records-cell-saving": "", className: "pointer-events-none absolute right-1 top-1/2 z-10 -translate-y-1/2 rounded bg-card/90 px-1 text-[10px] text-muted-foreground", children: "Saving\u2026" }) : null,
12263
- refusal4 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal4, field: field2, row, editing, typed: false }) : null
11756
+ refusal3 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: false }) : null
12264
11757
  ] });
12265
11758
  }
12266
11759
  const openThisCell = (event) => {
@@ -12382,40 +11875,40 @@ function GridCell({
12382
11875
  ) : null
12383
11876
  ] }),
12384
11877
  state === "saving" ? /* @__PURE__ */ jsx44("span", { "data-records-cell-saving": "", className: "pointer-events-none absolute right-1 top-1/2 z-10 -translate-y-1/2 rounded bg-card/90 px-1 text-[10px] text-muted-foreground", children: "Saving\u2026" }) : null,
12385
- refusal4 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal4, field: field2, row, editing, typed: true }) : null
11878
+ refusal3 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: true }) : null
12386
11879
  ]
12387
11880
  }
12388
11881
  )
12389
11882
  );
12390
11883
  }
12391
11884
  function CellRefusalNotice({
12392
- refusal: refusal4,
11885
+ refusal: refusal3,
12393
11886
  field: field2,
12394
11887
  row,
12395
11888
  editing,
12396
11889
  typed: typed2
12397
11890
  }) {
12398
11891
  const [open, setOpen] = useState34(true);
12399
- const line = refusal4.unsent ? UNSENT_LINE : refusalLineForAPerson(refusal4.error);
12400
- const notice = refusal4.unsent ? (
11892
+ const line = refusal3.unsent ? UNSENT_LINE : refusalLineForAPerson(refusal3.error);
11893
+ const notice = refusal3.unsent ? (
12401
11894
  // NOT SENT, NOT REFUSED: what was typed is still in the cell; it goes again once online.
12402
11895
  /* @__PURE__ */ jsxs39("div", { className: "flex flex-col gap-1.5 px-3 py-2 text-xs", "data-records-cell-unsent": "", children: [
12403
11896
  /* @__PURE__ */ jsx44("span", { className: "font-medium", children: UNSENT_LINE }),
12404
- /* @__PURE__ */ jsx44("span", { className: "max-w-[16rem] truncate text-muted-foreground", title: valueInALine(refusal4.attempted), children: valueInALine(refusal4.attempted) }),
11897
+ /* @__PURE__ */ jsx44("span", { className: "max-w-[16rem] truncate text-muted-foreground", title: valueInALine(refusal3.attempted), children: valueInALine(refusal3.attempted) }),
12405
11898
  /* @__PURE__ */ jsxs39("span", { className: "flex flex-wrap gap-1", children: [
12406
11899
  /* @__PURE__ */ jsx44(Button19, { size: "sm", variant: "outline", className: "h-6", "data-records-cell-try-now": "", onClick: () => editing?.tryNow(row.id, field2.key), children: "Try now" }),
12407
11900
  /* @__PURE__ */ jsx44(Button19, { size: "sm", variant: "ghost", className: "h-6", "data-records-cell-discard": "", onClick: () => editing?.discard(row.id, field2.key), children: "Discard" })
12408
11901
  ] })
12409
11902
  ] })
12410
- ) : refusal4.conflict ? /* @__PURE__ */ jsx44(
11903
+ ) : refusal3.conflict ? /* @__PURE__ */ jsx44(
12411
11904
  RefusalNotice,
12412
11905
  {
12413
- error: refusal4.error,
11906
+ error: refusal3.error,
12414
11907
  className: "py-1.5 text-left",
12415
11908
  actions: /* @__PURE__ */ jsxs39("span", { className: "flex flex-col gap-1", "data-refusal-conflict": "", children: [
12416
11909
  /* @__PURE__ */ jsxs39("span", { className: "text-[11px]", children: [
12417
11910
  "Theirs: ",
12418
- /* @__PURE__ */ jsx44("strong", { children: formatTheirs(refusal4.conflict, field2.key) })
11911
+ /* @__PURE__ */ jsx44("strong", { children: formatTheirs(refusal3.conflict, field2.key) })
12419
11912
  ] }),
12420
11913
  /* @__PURE__ */ jsxs39("span", { className: "flex flex-wrap gap-1", children: [
12421
11914
  /* @__PURE__ */ jsx44(Button19, { size: "sm", variant: "outline", onClick: () => editing?.retry(row.id, field2.key), children: "Try again" }),
@@ -12426,7 +11919,7 @@ function CellRefusalNotice({
12426
11919
  ) : /* @__PURE__ */ jsx44(
12427
11920
  RefusalNotice,
12428
11921
  {
12429
- error: refusal4.error,
11922
+ error: refusal3.error,
12430
11923
  className: "py-1.5 text-left",
12431
11924
  ...typed2 ? { onKeepEditing: () => editing?.keepEditing(row.id, field2.key) } : {},
12432
11925
  onDiscard: () => editing?.discard(row.id, field2.key)
@@ -12440,8 +11933,8 @@ function CellRefusalNotice({
12440
11933
  "data-records-cell-refusal-line": "",
12441
11934
  title: line,
12442
11935
  "aria-label": line,
12443
- "data-records-cell-unsent-mark": refusal4.unsent ? "" : void 0,
12444
- className: `absolute right-1 top-1/2 z-10 flex h-4 w-4 -translate-y-1/2 items-center justify-center rounded-full text-[10px] font-bold leading-none ${refusal4.unsent ? "bg-amber-500 text-white" : "bg-destructive text-destructive-foreground"}`,
11936
+ "data-records-cell-unsent-mark": refusal3.unsent ? "" : void 0,
11937
+ className: `absolute right-1 top-1/2 z-10 flex h-4 w-4 -translate-y-1/2 items-center justify-center rounded-full text-[10px] font-bold leading-none ${refusal3.unsent ? "bg-amber-500 text-white" : "bg-destructive text-destructive-foreground"}`,
12445
11938
  children: "!"
12446
11939
  }
12447
11940
  ) }),
@@ -13090,7 +12583,7 @@ function MergeRecordDialog({ tableId, record, open, onOpenChange, onMerged }) {
13090
12583
  const records = useRecords3(tableId, { pageSize: 200 });
13091
12584
  const [other, setOther] = useState37(null);
13092
12585
  const [busy, setBusy] = useState37(false);
13093
- const [refusal4, setRefusal] = useState37(null);
12586
+ const [refusal3, setRefusal] = useState37(null);
13094
12587
  const options = useMemo15(
13095
12588
  () => (records.data?.rows ?? []).filter((row) => row.id !== record.id).map((row) => ({ value: row.id, label: rowNameIn(table.data ?? null, row) })),
13096
12589
  [records.data, record.id, table.data]
@@ -13160,7 +12653,7 @@ function MergeRecordDialog({ tableId, record, open, onOpenChange, onMerged }) {
13160
12653
  ariaLabel: "Record to merge"
13161
12654
  }
13162
12655
  ),
13163
- refusal4 ? /* @__PURE__ */ jsx47(RefusalNotice, { error: refusal4 }) : null,
12656
+ refusal3 ? /* @__PURE__ */ jsx47(RefusalNotice, { error: refusal3 }) : null,
13164
12657
  /* @__PURE__ */ jsxs42(DialogFooter, { children: [
13165
12658
  /* @__PURE__ */ jsx47(Button21, { variant: "ghost", size: "sm", onClick: () => close(false), disabled: busy, children: "Cancel" }),
13166
12659
  /* @__PURE__ */ jsx47(Button21, { size: "sm", onClick: () => void merge(), disabled: !other || busy, "data-records-merge-go": "", children: busy ? "Merging\u2026" : "Merge" })
@@ -13344,7 +12837,7 @@ function useGridColours(args) {
13344
12837
  [client, tableId, decorations, notify]
13345
12838
  );
13346
12839
  const idOf = useCallback12((key) => fields.find((f) => f.key === key), [fields]);
13347
- const refusal4 = mayColour ? void 0 : whyNot;
12840
+ const refusal3 = mayColour ? void 0 : whyNot;
13348
12841
  const headerItem = useCallback12(
13349
12842
  (columnKey) => {
13350
12843
  if (!enabled) return null;
@@ -13359,7 +12852,7 @@ function useGridColours(args) {
13359
12852
  id: "col-colour",
13360
12853
  label: "Colour by\u2026",
13361
12854
  icon: "palette",
13362
- disabledReason: refusal4,
12855
+ disabledReason: refusal3,
13363
12856
  submenu: [
13364
12857
  byThis ? {
13365
12858
  id: "col-colour-off",
@@ -13395,7 +12888,7 @@ function useGridColours(args) {
13395
12888
  ]
13396
12889
  };
13397
12890
  },
13398
- [enabled, idOf, decorations.data, refusal4, write]
12891
+ [enabled, idOf, decorations.data, refusal3, write]
13399
12892
  );
13400
12893
  const cellItem = useCallback12(
13401
12894
  (rowId, columnKey) => {
@@ -13407,7 +12900,7 @@ function useGridColours(args) {
13407
12900
  id: "cell-highlight",
13408
12901
  label: "Highlight cell",
13409
12902
  icon: "palette",
13410
- disabledReason: refusal4,
12903
+ disabledReason: refusal3,
13411
12904
  submenu: swatches(
13412
12905
  "cell-highlight",
13413
12906
  current,
@@ -13415,7 +12908,7 @@ function useGridColours(args) {
13415
12908
  )
13416
12909
  };
13417
12910
  },
13418
- [enabled, idOf, decorations.data, refusal4, write]
12911
+ [enabled, idOf, decorations.data, refusal3, write]
13419
12912
  );
13420
12913
  const cellsItem = useCallback12(
13421
12914
  (cells) => {
@@ -13425,7 +12918,7 @@ function useGridColours(args) {
13425
12918
  id: "sel-highlight",
13426
12919
  label: `Highlight ${n} cells`,
13427
12920
  icon: "palette",
13428
- disabledReason: refusal4,
12921
+ disabledReason: refusal3,
13429
12922
  submenu: swatches("sel-highlight", void 0, (color) => {
13430
12923
  void (async () => {
13431
12924
  let kept = 0;
@@ -13445,7 +12938,7 @@ function useGridColours(args) {
13445
12938
  })
13446
12939
  };
13447
12940
  },
13448
- [enabled, idOf, refusal4, client, tableId, decorations, notify]
12941
+ [enabled, idOf, refusal3, client, tableId, decorations, notify]
13449
12942
  );
13450
12943
  const rowItem = useCallback12(
13451
12944
  (rowId) => {
@@ -13455,7 +12948,7 @@ function useGridColours(args) {
13455
12948
  id: "row-highlight",
13456
12949
  label: "Highlight row",
13457
12950
  icon: "palette",
13458
- disabledReason: refusal4,
12951
+ disabledReason: refusal3,
13459
12952
  submenu: swatches(
13460
12953
  "row-highlight",
13461
12954
  current,
@@ -13463,7 +12956,7 @@ function useGridColours(args) {
13463
12956
  )
13464
12957
  };
13465
12958
  },
13466
- [enabled, decorations.data, refusal4, write]
12959
+ [enabled, decorations.data, refusal3, write]
13467
12960
  );
13468
12961
  const dialogs = enabled ? /* @__PURE__ */ jsx48(
13469
12962
  ColourRulesDialog,
@@ -14235,7 +13728,7 @@ function stepOf(step2, original) {
14235
13728
  return { field: field2, set: "value", value: step2.value };
14236
13729
  }
14237
13730
  function actionOf(draft, original) {
14238
- const base = {
13731
+ const base2 = {
14239
13732
  ...draft.id ? { id: draft.id } : {},
14240
13733
  name: draft.name.trim(),
14241
13734
  kind: draft.kind,
@@ -14243,9 +13736,9 @@ function actionOf(draft, original) {
14243
13736
  ...draft.color ? { color: draft.color } : {},
14244
13737
  ...draft.icon ? { icon: draft.icon } : {}
14245
13738
  };
14246
- if (draft.kind === "agent") return { ...base, prompt: draft.prompt };
13739
+ if (draft.kind === "agent") return { ...base2, prompt: draft.prompt };
14247
13740
  return {
14248
- ...base,
13741
+ ...base2,
14249
13742
  steps: draft.steps.map((s, i) => stepOf(s, original?.steps?.[i]))
14250
13743
  };
14251
13744
  }
@@ -15511,19 +15004,19 @@ function planPastedBlock(args) {
15511
15004
  accepted[key] = judged.value;
15512
15005
  }
15513
15006
  const predicted = predictValueRefusals(args.fields, accepted);
15514
- for (const refusal4 of predicted) {
15515
- const key = refusal4.field_key;
15007
+ for (const refusal3 of predicted) {
15008
+ const key = refusal3.field_key;
15516
15009
  if (key === void 0) continue;
15517
15010
  const cell2 = built.find((b) => b.key === key && b.refusal === null);
15518
15011
  if (!cell2) continue;
15519
- cell2.refusal = refusal4.message;
15012
+ cell2.refusal = refusal3.message;
15520
15013
  cell2.value = null;
15521
15014
  delete accepted[key];
15522
15015
  refusals.push({
15523
15016
  fromLine,
15524
15017
  column: fieldName(byKey.get(key) ?? { key }),
15525
15018
  raw: cell2.raw,
15526
- why: refusal4.message
15019
+ why: refusal3.message
15527
15020
  });
15528
15021
  }
15529
15022
  cells += Object.keys(accepted).length;
@@ -15727,8 +15220,8 @@ function useMergedGridControls(args) {
15727
15220
  setHeld(null);
15728
15221
  }, [keptKey]);
15729
15222
  const order = useMemo21(() => {
15730
- const base = held?.order ?? columnsInKeptOrder(fieldKeys, keptOrder);
15731
- const known = columnsInKeptOrder(fieldKeys, base);
15223
+ const base2 = held?.order ?? columnsInKeptOrder(fieldKeys, keptOrder);
15224
+ const known = columnsInKeptOrder(fieldKeys, base2);
15732
15225
  if (frozenKeys.size === 0) return known;
15733
15226
  return [...known.filter((k) => frozenKeys.has(k)), ...known.filter((k) => !frozenKeys.has(k))];
15734
15227
  }, [held, fieldKeys, keptOrder, frozenKeys]);
@@ -15784,10 +15277,10 @@ function useMergedGridControls(args) {
15784
15277
  return;
15785
15278
  }
15786
15279
  let cancelled = false;
15787
- const [keys, filters, base, searched] = JSON.parse(countQuestionKey);
15280
+ const [keys, filters, base2, searched] = JSON.parse(countQuestionKey);
15788
15281
  for (const key of keys) {
15789
15282
  const { [key]: _own, ...others } = filters;
15790
- const asked2 = storeQuestion(fieldsRef.current, base ?? void 0, others);
15283
+ const asked2 = storeQuestion(fieldsRef.current, base2 ?? void 0, others);
15791
15284
  void (0, askOnce_exports.askOnce)(
15792
15285
  client,
15793
15286
  `value_counts:${tableId}:${key}:${searched}:${JSON.stringify(asked2.filter ?? null)}`,
@@ -16403,9 +15896,9 @@ function readersThrough(fields, key) {
16403
15896
  });
16404
15897
  }
16405
15898
  function backLinkSentence(column, readers = [], tableName2 = null) {
16406
- const base = `It goes when ${column.source_field_label} is archived on ${column.source_table_name}. Archiving it removes the links it holds there too; it can be brought back from Archived.`;
16407
- if (readers.length === 0) return base;
16408
- return `${readersSentence(readers.length, tableName2)} ${base}`;
15899
+ const base2 = `It goes when ${column.source_field_label} is archived on ${column.source_table_name}. Archiving it removes the links it holds there too; it can be brought back from Archived.`;
15900
+ if (readers.length === 0) return base2;
15901
+ return `${readersSentence(readers.length, tableName2)} ${base2}`;
16409
15902
  }
16410
15903
  function afterMenuLayerCloses(next) {
16411
15904
  if (typeof window === "undefined") return next();
@@ -17744,8 +17237,8 @@ function useDrillDefinition(source) {
17744
17237
  }, [client, key]);
17745
17238
  return state.key === key ? { def: state.def, error: state.error } : { def: null, error: null };
17746
17239
  }
17747
- function drillWhere(base, trail, booleans) {
17748
- const where = { ...base ?? {} };
17240
+ function drillWhere(base2, trail, booleans) {
17241
+ const where = { ...base2 ?? {} };
17749
17242
  for (const w of trail) {
17750
17243
  const { key, grain } = parseDimensionRef2(w.dim);
17751
17244
  if (grain) where[w.dim] = w.value;
@@ -17924,10 +17417,10 @@ function useDrill(args) {
17924
17417
  const booleans = useMemo25(() => new Set((def?.dimensions ?? []).filter((d) => d.kind === "boolean").map((d) => d.key)), [def]);
17925
17418
  const baseKey = JSON.stringify(args.base ?? []);
17926
17419
  const filter = useMemo25(() => {
17927
- const base = JSON.parse(baseKey);
17928
- if (base.length === 0) return args.filter;
17420
+ const base2 = JSON.parse(baseKey);
17421
+ if (base2.length === 0) return args.filter;
17929
17422
  const out = { ...args.filter ?? {} };
17930
- for (const b of base) out[b.key] = b.value;
17423
+ for (const b of base2) out[b.key] = b.value;
17931
17424
  return out;
17932
17425
  }, [args.filter, baseKey]);
17933
17426
  const where = useMemo25(() => drillWhere(filter, question.where, booleans), [filter, question.where, booleans]);
@@ -18056,17 +17549,17 @@ function trailClause(fields, w) {
18056
17549
  }
18057
17550
  return { key, value: w.value, field: field2 };
18058
17551
  }
18059
- function filterWithTrail(fields, base, trail) {
18060
- if (trail.length === 0) return base;
18061
- if (!base || !isRuleFilter2(base)) {
18062
- const flat = { ...base ?? {} };
17552
+ function filterWithTrail(fields, base2, trail) {
17553
+ if (trail.length === 0) return base2;
17554
+ if (!base2 || !isRuleFilter2(base2)) {
17555
+ const flat = { ...base2 ?? {} };
18063
17556
  for (const w of trail) {
18064
17557
  const clause = trailClause(fields, w);
18065
17558
  flat[clause.key] = clause.value;
18066
17559
  }
18067
17560
  return flat;
18068
17561
  }
18069
- const args = [base];
17562
+ const args = [base2];
18070
17563
  for (const w of trail) {
18071
17564
  const clause = trailClause(fields, w);
18072
17565
  if (!clause.field) continue;
@@ -18080,14 +17573,14 @@ function filterWithTrail(fields, base, trail) {
18080
17573
  }
18081
17574
  return { op: "and", args };
18082
17575
  }
18083
- function filterWithWindow(fields, base, key, range) {
18084
- if (!base || !isRuleFilter2(base)) return { ...base ?? {}, [key]: { from: range.from, to: range.to } };
17576
+ function filterWithWindow(fields, base2, key, range) {
17577
+ if (!base2 || !isRuleFilter2(base2)) return { ...base2 ?? {}, [key]: { from: range.from, to: range.to } };
18085
17578
  const field2 = fields.find((f) => f.key === key);
18086
- if (!field2) return base;
17579
+ if (!field2) return base2;
18087
17580
  const ref = { field: field2.id };
18088
17581
  return {
18089
17582
  op: "and",
18090
- args: [base, { op: "gte", args: [ref, { const: range.from }] }, { op: "lt", args: [ref, { const: range.to }] }]
17583
+ args: [base2, { op: "gte", args: [ref, { const: range.from }] }, { op: "lt", args: [ref, { const: range.to }] }]
18091
17584
  };
18092
17585
  }
18093
17586
  function useGridDrillQuestion(args) {
@@ -18769,7 +18262,7 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
18769
18262
  ...look?.frozen ? { frozen: true, width: Math.max(FROZEN_COLUMN_WIDTH, defaultColumnWidth(field2)) } : { width: defaultColumnWidth(field2) },
18770
18263
  // A column that holds numbers filters as numbers (=, <, >, between) — the record number too,
18771
18264
  // which is worked out but kept (review 2: the autonumber header offered "Contains").
18772
- filter: filterRefusal(field2) !== null ? false : editorKindFor(field2) === "select" || editorKindFor(field2) === "multi_select" ? "select" : holdsNumbers(field2) ? "number" : "auto",
18265
+ filter: filterRefusal(field2) !== null ? false : editorKindFor(field2) === "select" || editorKindFor(field2) === "multi_select" ? "select" : holdsNumbers2(field2) ? "number" : "auto",
18773
18266
  // THE MENU'S VALUE LIST WEARS THE CHOICES' COLOURS (lane CELL-EDITORS, night walk 2026-10-06): the
18774
18267
  // same chip the cell draws, never bare words beside a coloured column.
18775
18268
  ...editorKindFor(field2) === "select" || editorKindFor(field2) === "multi_select" ? { filterValueClass: (value, label) => choiceChipLookOf(field2, value, label).className } : {},
@@ -18896,6 +18389,18 @@ function withTypeMark(field2, header) {
18896
18389
  // src/ReverseColumns.tsx
18897
18390
  import { useCallback as useCallback20, useEffect as useEffect44, useMemo as useMemo27, useRef as useRef29, useState as useState55, useSyncExternalStore as useSyncExternalStore3 } from "react";
18898
18391
  import { isReverseField } from "@ai-matrx/records";
18392
+
18393
+ // src/groupReads.ts
18394
+ import {
18395
+ REVERSE_CELL_CHIPS,
18396
+ choiceFieldKeys,
18397
+ groupFactMeasures,
18398
+ groupedPageSort,
18399
+ isPlainGrouping,
18400
+ summaryBarMeasures
18401
+ } from "@ai-matrx/records/first-page";
18402
+
18403
+ // src/ReverseColumns.tsx
18899
18404
  import { useFields as useFields6, useOptionalRecordsClient as useOptionalRecordsClient11, useReverseColumns as useReverseColumns3, useReverseLinks, useTable as useTable4 } from "@ai-matrx/records/react";
18900
18405
  import { Button as Button37, Dialog as Dialog11, DialogContent as DialogContent11, DialogHeader as DialogHeader11, DialogTitle as DialogTitle11, Popover as Popover8, PopoverContent as PopoverContent8, PopoverTrigger as PopoverTrigger8, Separator as Separator4, Skeleton as Skeleton5, cn as cn36 } from "@ai-matrx/design-system";
18901
18406
  import { Fragment as Fragment19, jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
@@ -19356,10 +18861,10 @@ function PastePreview({
19356
18861
  /* @__PURE__ */ jsx67(PlanTable, { plan }),
19357
18862
  plan.refusals.length > 0 ? /* @__PURE__ */ jsxs62("div", { "data-matrx-paste-refusals": true, className: "flex flex-col gap-1", children: [
19358
18863
  /* @__PURE__ */ jsx67("p", { className: "text-xs font-medium", children: plan.refusals.length === 1 ? "One cell will be left alone:" : `${plan.refusals.length} cells will be left alone:` }),
19359
- /* @__PURE__ */ jsx67("ul", { className: "flex flex-col gap-1", children: plan.refusals.slice(0, 12).map((refusal4, index) => /* @__PURE__ */ jsxs62("li", { className: "text-xs text-muted-foreground", children: [
19360
- /* @__PURE__ */ jsx67("span", { className: "font-medium", children: refusal4.fromLine > 0 ? `Row ${refusal4.fromLine}, ${refusal4.column}` : refusal4.column }),
18864
+ /* @__PURE__ */ jsx67("ul", { className: "flex flex-col gap-1", children: plan.refusals.slice(0, 12).map((refusal3, index) => /* @__PURE__ */ jsxs62("li", { className: "text-xs text-muted-foreground", children: [
18865
+ /* @__PURE__ */ jsx67("span", { className: "font-medium", children: refusal3.fromLine > 0 ? `Row ${refusal3.fromLine}, ${refusal3.column}` : refusal3.column }),
19361
18866
  " \u2014 ",
19362
- refusal4.why
18867
+ refusal3.why
19363
18868
  ] }, index)) }),
19364
18869
  plan.refusals.length > 12 ? /* @__PURE__ */ jsxs62("p", { className: "text-xs text-muted-foreground", children: [
19365
18870
  plan.refusals.length - 12,
@@ -19836,8 +19341,8 @@ function offerDownload(name, text, type = "text/csv") {
19836
19341
  return true;
19837
19342
  }
19838
19343
  function refusedFileName(sourceName) {
19839
- const base = (sourceName ?? "import").replace(/\.(csv|xlsx)$/i, "");
19840
- return `${base} \u2014 rows not added.csv`;
19344
+ const base2 = (sourceName ?? "import").replace(/\.(csv|xlsx)$/i, "");
19345
+ return `${base2} \u2014 rows not added.csv`;
19841
19346
  }
19842
19347
 
19843
19348
  // src/ImportWizard.tsx
@@ -21291,11 +20796,11 @@ function cellWords(raw) {
21291
20796
  function uniqueLabels(raw) {
21292
20797
  const seen = /* @__PURE__ */ new Map();
21293
20798
  return raw.map((label, index) => {
21294
- const base = label.trim() || `Column ${index + 1}`;
21295
- const key = base.toLowerCase();
20799
+ const base2 = label.trim() || `Column ${index + 1}`;
20800
+ const key = base2.toLowerCase();
21296
20801
  const count = (seen.get(key) ?? 0) + 1;
21297
20802
  seen.set(key, count);
21298
- return count === 1 ? base : `${base} ${count}`;
20803
+ return count === 1 ? base2 : `${base2} ${count}`;
21299
20804
  });
21300
20805
  }
21301
20806
  function rowsOf(headers, matrix) {
@@ -21356,7 +20861,7 @@ function recordsFromPairs(pairs) {
21356
20861
  if (current.size > 0) records.push(current);
21357
20862
  return records;
21358
20863
  }
21359
- function shapeFromRecords(records, base, from) {
20864
+ function shapeFromRecords(records, base2, from) {
21360
20865
  const order = [];
21361
20866
  for (const r of records) for (const k of r.keys()) if (!order.some((o) => o.toLowerCase() === k.toLowerCase())) order.push(k);
21362
20867
  const headers = uniqueLabels(order);
@@ -21369,7 +20874,7 @@ function shapeFromRecords(records, base, from) {
21369
20874
  return row;
21370
20875
  });
21371
20876
  return {
21372
- ...base,
20877
+ ...base2,
21373
20878
  kind: "key_value",
21374
20879
  headers,
21375
20880
  rows,
@@ -21948,7 +21453,7 @@ function valueListKind(field2) {
21948
21453
  if (kind === "text" || kind === "long_text" || kind === "email" || kind === "phone" || kind === "url") return "words";
21949
21454
  if (kind === "datetime" || kind === "date") return "days";
21950
21455
  if (kind === "checkbox") return "yesno";
21951
- if (holdsNumbers(field2) || kind === "rating") return "numbers";
21456
+ if (holdsNumbers2(field2) || kind === "rating") return "numbers";
21952
21457
  return "loaded";
21953
21458
  }
21954
21459
  function noValueList(columnId2) {
@@ -22214,35 +21719,35 @@ function useGridUndo(args) {
22214
21719
  if (!step2) return;
22215
21720
  setBusy(true);
22216
21721
  const changes = changesFor(step2, direction, known.current);
22217
- let refusal4 = null;
21722
+ let refusal3 = null;
22218
21723
  if (direction === "redo" && (step2.created?.length ?? 0) > 0) {
22219
21724
  const answers = await Promise.all((step2.created ?? []).map((id) => client.recordRestore({ record_id: id })));
22220
21725
  const failed = answers.find((a) => !a.ok);
22221
- if (failed && !failed.ok) refusal4 = failed.error;
21726
+ if (failed && !failed.ok) refusal3 = failed.error;
22222
21727
  }
22223
- if (!refusal4 && step2.retiredField) {
21728
+ if (!refusal3 && step2.retiredField) {
22224
21729
  const fieldId = step2.retiredField.fieldId;
22225
21730
  const done = direction === "undo" ? await client.fieldRestore({ field_id: fieldId }) : await client.fieldRetire({ field_id: fieldId });
22226
- if (!done.ok) refusal4 = done.error;
21731
+ if (!done.ok) refusal3 = done.error;
22227
21732
  else tableShapeChanged6(tableId);
22228
21733
  }
22229
- if (!refusal4 && changes.length > 0) {
21734
+ if (!refusal3 && changes.length > 0) {
22230
21735
  const done = await (0, recordVersions_exports.changeRecordsAt)(client, { table_id: tableId, changes });
22231
- if (!done.ok) refusal4 = done.error;
21736
+ if (!done.ok) refusal3 = done.error;
22232
21737
  else {
22233
21738
  for (const result of done.data ?? []) if (result.op === "update") known.current.set(result.id, result.version);
22234
21739
  onVersions?.((done.data ?? []).flatMap((r) => r.op === "update" ? [{ id: r.id, version: r.version }] : []));
22235
21740
  }
22236
21741
  }
22237
- if (!refusal4 && direction === "undo" && (step2.archived?.length ?? 0) > 0) {
21742
+ if (!refusal3 && direction === "undo" && (step2.archived?.length ?? 0) > 0) {
22238
21743
  const answers = await Promise.all((step2.archived ?? []).map((id) => client.recordRestore({ record_id: id })));
22239
21744
  const failed = answers.find((a) => !a.ok);
22240
- if (failed && !failed.ok) refusal4 = failed.error;
21745
+ if (failed && !failed.ok) refusal3 = failed.error;
22241
21746
  }
22242
21747
  setBusy(false);
22243
- if (refusal4) {
22244
- setNotice({ says: `${direction === "undo" ? "Undo" : "Redo"} changed nothing: ${refusalSentence(refusal4)}`, refusal: refusal4, canUndo: false });
22245
- if ((0, recordVersions_exports.isChangedElsewhere)(refusal4)) reload();
21748
+ if (refusal3) {
21749
+ setNotice({ says: `${direction === "undo" ? "Undo" : "Redo"} changed nothing: ${refusalSentence(refusal3)}`, refusal: refusal3, canUndo: false });
21750
+ if ((0, recordVersions_exports.isChangedElsewhere)(refusal3)) reload();
22246
21751
  return;
22247
21752
  }
22248
21753
  forget(step2.cells.map((c) => ({ rowId: c.rowId, key: c.key })));
@@ -22973,7 +22478,7 @@ function useGridBulk(args) {
22973
22478
  const client = useRecordsClient37();
22974
22479
  const { tableId, rows, fields, noun, nounPlural, reload, forget, pushUndo: pushUndo2, versions } = args;
22975
22480
  const [busy, setBusy] = useState62(false);
22976
- const [refusal4, setRefusal] = useState62(null);
22481
+ const [refusal3, setRefusal] = useState62(null);
22977
22482
  const send = useCallback26(
22978
22483
  async (changes) => {
22979
22484
  setBusy(true);
@@ -23037,7 +22542,7 @@ function useGridBulk(args) {
23037
22542
  },
23038
22543
  [send, rows, pushUndo2, reload, noun, nounPlural]
23039
22544
  );
23040
- return { busy, refusal: refusal4, clearRefusal: () => setRefusal(null), apply, duplicate, archive };
22545
+ return { busy, refusal: refusal3, clearRefusal: () => setRefusal(null), apply, duplicate, archive };
23041
22546
  }
23042
22547
  function BulkActions({
23043
22548
  ids,
@@ -23158,6 +22663,31 @@ import { useEffect as useEffect52, useMemo as useMemo34, useRef as useRef35, use
23158
22663
  import { useRecordsClient as useRecordsClient38 } from "@ai-matrx/records/react";
23159
22664
  import { stableFilterKey as stableFilterKey2 } from "@ai-matrx/records";
23160
22665
  import { Button as Button43, ConfirmDialog as ConfirmDialog4, Popover as Popover9, PopoverContent as PopoverContent9, PopoverTrigger as PopoverTrigger9, cn as cn38 } from "@ai-matrx/design-system";
22666
+
22667
+ // src/views.ts
22668
+ import {
22669
+ STORE_KEEPS_TIMELINE as STORE_KEEPS_TIMELINE2,
22670
+ STORE_KEPT_LAYOUTS as STORE_KEPT_LAYOUTS2,
22671
+ storeKeepsLayout as storeKeepsLayout2,
22672
+ VIEW_LAYOUTS,
22673
+ LAYOUT_LABEL,
22674
+ wordsList,
22675
+ VIEW_NEEDS,
22676
+ freeColumnName,
22677
+ viewOrderOf,
22678
+ defaultViewOf,
22679
+ LAYOUT_FIELD_KIND,
22680
+ PAGE_VIEWS,
22681
+ PAGE_VIEW_LABEL,
22682
+ pageViewFromParam,
22683
+ unknownViewLine,
22684
+ makeDefaultLabel,
22685
+ designateView,
22686
+ viewPatchFor
22687
+ } from "@ai-matrx/records/views";
22688
+ var { viewDocument, viewFromRow, declareView, saveViewPatch, viewPatchDocument } = boundViews;
22689
+
22690
+ // src/handOrder.tsx
23161
22691
  import { jsx as jsx76, jsxs as jsxs69 } from "react/jsx-runtime";
23162
22692
  function sortArrow(direction) {
23163
22693
  return direction === "asc" ? "\u2191" : "\u2193";
@@ -25716,6 +25246,11 @@ import {
25716
25246
  useEntityWrite,
25717
25247
  useOptionalEntityScope
25718
25248
  } from "@ai-matrx/records/entity/react";
25249
+
25250
+ // src/entityQuery.ts
25251
+ import { entityChartQuestion, entityTableQuery } from "@ai-matrx/records/first-page";
25252
+
25253
+ // src/entityTable.tsx
25719
25254
  import { Fragment as Fragment27, jsx as jsx78 } from "react/jsx-runtime";
25720
25255
  function EntityDataScope({ children }) {
25721
25256
  const above = useOptionalEntityScope();
@@ -26446,19 +25981,19 @@ function fieldsForNewColumns(columns) {
26446
25981
  let key = tokenFor(column.label) || `column_${i + 1}`;
26447
25982
  while (keys.has(key)) key = `${key}_${i + 1}`;
26448
25983
  keys.add(key);
26449
- const base = { key, label: column.label, sort: (i + 1) * 10, required: false };
25984
+ const base2 = { key, label: column.label, sort: (i + 1) * 10, required: false };
26450
25985
  switch (column.type) {
26451
25986
  case "date":
26452
- return { ...base, type: "datetime", kind: "date" };
25987
+ return { ...base2, type: "datetime", kind: "date" };
26453
25988
  case "datetime":
26454
- return { ...base, type: "datetime", kind: "datetime" };
25989
+ return { ...base2, type: "datetime", kind: "datetime" };
26455
25990
  case "currency":
26456
- return { ...base, type: "currency", unit: "$" };
25991
+ return { ...base2, type: "currency", unit: "$" };
26457
25992
  case "select":
26458
25993
  case "multi_select":
26459
- return { ...base, type: column.type, multi: column.type === "multi_select", options: column.options ?? [] };
25994
+ return { ...base2, type: column.type, multi: column.type === "multi_select", options: column.options ?? [] };
26460
25995
  default:
26461
- return { ...base, type: column.type };
25996
+ return { ...base2, type: column.type };
26462
25997
  }
26463
25998
  });
26464
25999
  }
@@ -27124,15 +26659,15 @@ function objectActionForKey(actions, event) {
27124
26659
  const id = Object.keys(TABLE_ACTION_KEYS).find((k) => TABLE_ACTION_KEYS[k].code === event.code);
27125
26660
  return id ? actions.find((a) => a.id === id) ?? null : null;
27126
26661
  }
27127
- function action(base, needs, input, perform) {
27128
- const chord = TABLE_ACTION_KEYS[base.id];
27129
- if (chord && base.shortcut === void 0) base = { ...base, shortcut: chord.label };
26662
+ function action(base2, needs, input, perform) {
26663
+ const chord = TABLE_ACTION_KEYS[base2.id];
26664
+ if (chord && base2.shortcut === void 0) base2 = { ...base2, shortcut: chord.label };
27130
26665
  const refused = rightsReason(input.rights, needs, input.table);
27131
- if (refused !== null) return { ...base, disabledReason: refused, run: NOOP };
26666
+ if (refused !== null) return { ...base2, disabledReason: refused, run: NOOP };
27132
26667
  if (perform === void 0) {
27133
- return { ...base, disabledReason: input.host.unavailableReasons?.[base.id] ?? ACTION_NOT_HERE_REASON, run: NOOP };
26668
+ return { ...base2, disabledReason: input.host.unavailableReasons?.[base2.id] ?? ACTION_NOT_HERE_REASON, run: NOOP };
27134
26669
  }
27135
- return { ...base, run: perform };
26670
+ return { ...base2, run: perform };
27136
26671
  }
27137
26672
  function bind(handler, table) {
27138
26673
  return handler ? () => handler(table) : void 0;
@@ -27203,9 +26738,9 @@ function tableActions(input) {
27203
26738
  ];
27204
26739
  return withExtensions(built, host.extend ? host.extend(table, input.rights) : []);
27205
26740
  }
27206
- function withExtensions(base, extra) {
27207
- if (extra.length === 0) return [...base];
27208
- const seen = new Set(base.map((a) => a.id));
26741
+ function withExtensions(base2, extra) {
26742
+ if (extra.length === 0) return [...base2];
26743
+ const seen = new Set(base2.map((a) => a.id));
27209
26744
  for (const entry of extra) {
27210
26745
  if (entry.group === "danger") {
27211
26746
  throw new Error(`Object action "${entry.id}": the danger group is closed to extensions.`);
@@ -27220,7 +26755,7 @@ function withExtensions(base, extra) {
27220
26755
  }
27221
26756
  const out = [];
27222
26757
  for (const group of OBJECT_ACTION_GROUPS) {
27223
- out.push(...base.filter((a) => a.group === group.id), ...extra.filter((a) => a.group === group.id));
26758
+ out.push(...base2.filter((a) => a.group === group.id), ...extra.filter((a) => a.group === group.id));
27224
26759
  }
27225
26760
  return out;
27226
26761
  }
@@ -27426,7 +26961,7 @@ function ArchivedBuiltOn({ tableId, onRestored }) {
27426
26961
  const [things, setThings] = useState68(null);
27427
26962
  const [error, setError] = useState68(null);
27428
26963
  const [restoring, setRestoring] = useState68(null);
27429
- const [refusal4, setRefusal] = useState68(null);
26964
+ const [refusal3, setRefusal] = useState68(null);
27430
26965
  const [said2, setSaid] = useState68(null);
27431
26966
  const read = useCallback30(async () => {
27432
26967
  const [forms, checklists] = await Promise.all([
@@ -27479,7 +27014,7 @@ function ArchivedBuiltOn({ tableId, onRestored }) {
27479
27014
  " \xB7 archived ",
27480
27015
  archivedWhen(thing.archivedAt)
27481
27016
  ] }),
27482
- refusal4 && refusal4.id === thing.id ? /* @__PURE__ */ jsx87(RefusalNotice, { error: refusal4.error, className: "mt-2" }) : null
27017
+ refusal3 && refusal3.id === thing.id ? /* @__PURE__ */ jsx87(RefusalNotice, { error: refusal3.error, className: "mt-2" }) : null
27483
27018
  ] }),
27484
27019
  thing.whyNot ? /* @__PURE__ */ jsx87("span", { className: "text-xs text-muted-foreground", children: thing.whyNot }) : /* @__PURE__ */ jsx87(
27485
27020
  Button50,
@@ -28323,20 +27858,20 @@ function draftsFor(headers, rows) {
28323
27858
  function keysFor(labels) {
28324
27859
  const used = /* @__PURE__ */ new Set();
28325
27860
  return labels.map((label, i) => {
28326
- const base = tokenFor(label) === "table" && !/table/i.test(label) ? `column_${i + 1}` : tokenFor(label);
28327
- let key = base;
27861
+ const base2 = tokenFor(label) === "table" && !/table/i.test(label) ? `column_${i + 1}` : tokenFor(label);
27862
+ let key = base2;
28328
27863
  let n = 2;
28329
- while (used.has(key)) key = `${base}_${n++}`;
27864
+ while (used.has(key)) key = `${base2}_${n++}`;
28330
27865
  used.add(key);
28331
27866
  return key;
28332
27867
  });
28333
27868
  }
28334
27869
  function freeName(name, taken) {
28335
27870
  const lower = new Set(taken.map((t) => t.trim().toLowerCase()));
28336
- const base = name.trim() || "Saved table";
28337
- if (!lower.has(base.toLowerCase())) return base;
28338
- for (let n = 2; n < 100; n += 1) if (!lower.has(`${base} ${n}`.toLowerCase())) return `${base} ${n}`;
28339
- return `${base} ${Date.now()}`;
27871
+ const base2 = name.trim() || "Saved table";
27872
+ if (!lower.has(base2.toLowerCase())) return base2;
27873
+ for (let n = 2; n < 100; n += 1) if (!lower.has(`${base2} ${n}`.toLowerCase())) return `${base2} ${n}`;
27874
+ return `${base2} ${Date.now()}`;
28340
27875
  }
28341
27876
  async function sha256Text(text) {
28342
27877
  const subtle = globalThis.crypto?.subtle;
@@ -29256,11 +28791,11 @@ import { Badge as Badge14, Button as Button61, Separator as Separator8, cn as cn
29256
28791
  var TableRestoreRefused = class extends Error {
29257
28792
  refusal;
29258
28793
  sentence;
29259
- constructor(refusal4) {
29260
- const sentence2 = refusalSentence(refusal4);
28794
+ constructor(refusal3) {
28795
+ const sentence2 = refusalSentence(refusal3);
29261
28796
  super(sentence2);
29262
28797
  this.name = "TableRestoreRefused";
29263
- this.refusal = refusal4;
28798
+ this.refusal = refusal3;
29264
28799
  this.sentence = sentence2;
29265
28800
  }
29266
28801
  };
@@ -30778,6 +30313,22 @@ function usePlatformTable(spec) {
30778
30313
  return state;
30779
30314
  }
30780
30315
 
30316
+ // src/viewLook.ts
30317
+ import { applyLook, lookDiffers, lookPart, saveToViewPlan } from "@ai-matrx/records/views";
30318
+ var { lookDocument, lookFromDocument, readLooks, keepLook } = boundViews;
30319
+ var LOOK_WORDS = {
30320
+ /** The reason, for a tooltip or a screen reader — never a line on the page (interface-text). */
30321
+ yours: "You changed how this view looks. Only you see it.",
30322
+ /** The visible label for the same fact. */
30323
+ yoursLabel: "Only you see this",
30324
+ saveToView: "Save to view",
30325
+ saveAsNew: "Save as new view",
30326
+ reset: "Reset to view",
30327
+ /** The one button your look's doors fold into when the toolbar row has no room for three. */
30328
+ folded: "Your look",
30329
+ newName: "Name for the new view"
30330
+ };
30331
+
30781
30332
  // src/ViewSwitcher.tsx
30782
30333
  import { useEffect as useEffect79, useMemo as useMemo55, useState as useState93 } from "react";
30783
30334
  import { mayDrag as mayDrag4, useFields as useFields18, useRecordPage as useRecordPage2, useRecordsClient as useRecordsClient65, useTable as useTable18 } from "@ai-matrx/records/react";
@@ -31072,13 +30623,13 @@ function recordLink(tableId, recordId, origin = DEFAULT_ACTION_ORIGIN) {
31072
30623
  }
31073
30624
  var NOOP2 = () => {
31074
30625
  };
31075
- function action2(base, needs, input, perform) {
30626
+ function action2(base2, needs, input, perform) {
31076
30627
  const refused = rightsReason(input.rights, needs);
31077
- if (refused !== null) return { ...base, disabledReason: refused, run: NOOP2 };
30628
+ if (refused !== null) return { ...base2, disabledReason: refused, run: NOOP2 };
31078
30629
  if (perform === void 0) {
31079
- return { ...base, disabledReason: input.host.unavailableReasons?.[base.id] ?? ACTION_NOT_HERE_REASON, run: NOOP2 };
30630
+ return { ...base2, disabledReason: input.host.unavailableReasons?.[base2.id] ?? ACTION_NOT_HERE_REASON, run: NOOP2 };
31080
30631
  }
31081
- return { ...base, run: perform };
30632
+ return { ...base2, run: perform };
31082
30633
  }
31083
30634
  function bind2(handler, record) {
31084
30635
  return handler ? () => handler(record) : void 0;
@@ -33845,12 +33396,12 @@ function viewNeedFor(layout) {
33845
33396
  return VIEW_NEEDS[layout];
33846
33397
  }
33847
33398
  function columnDeclarationFor(need, label, options, fields) {
33848
- const base = { label: label.trim(), sort: nextFieldSort(fields) };
33399
+ const base2 = { label: label.trim(), sort: nextFieldSort(fields) };
33849
33400
  if (need.starter.type === "select") {
33850
- return { ...base, parity_type: "select", options: options.map((o) => o.trim()).filter((o) => o !== "") };
33401
+ return { ...base2, parity_type: "select", options: options.map((o) => o.trim()).filter((o) => o !== "") };
33851
33402
  }
33852
- if (need.starter.type === "datetime") return { ...base, parity_type: "datetime", kind: "date" };
33853
- return { ...base, parity_type: "attachment" };
33403
+ if (need.starter.type === "datetime") return { ...base2, parity_type: "datetime", kind: "date" };
33404
+ return { ...base2, parity_type: "attachment" };
33854
33405
  }
33855
33406
  var askedFor = /* @__PURE__ */ new Map();
33856
33407
  var askKey = (tableId, layout) => `${tableId}:${layout}`;
@@ -34730,10 +34281,10 @@ function Board({
34730
34281
  ...view.endField ? { endKey: view.endField } : {},
34731
34282
  groupKey: view.groupField ?? null,
34732
34283
  ...view.presentation?.style?.colorBy !== void 0 ? { colorKey: view.presentation.style.colorBy?.field ?? null } : {},
34733
- layoutKept: remembered && STORE_KEEPS_TIMELINE,
34284
+ layoutKept: remembered && STORE_KEEPS_TIMELINE2,
34734
34285
  onSettingsChange: (patch) => {
34735
34286
  if (patch.startKey !== void 0) {
34736
- onChange({ startField: patch.startKey, ...STORE_KEEPS_TIMELINE ? {} : { dateField: patch.startKey } });
34287
+ onChange({ startField: patch.startKey, ...STORE_KEEPS_TIMELINE2 ? {} : { dateField: patch.startKey } });
34737
34288
  }
34738
34289
  if (patch.endKey !== void 0) onChange({ endField: patch.endKey });
34739
34290
  if (patch.groupKey !== void 0) onChange({ groupField: patch.groupKey });
@@ -35333,7 +34884,7 @@ function ArchivedView({
35333
34884
  const [loading, setLoading] = useState94(true);
35334
34885
  const [error, setError] = useState94(null);
35335
34886
  const [restoring, setRestoring] = useState94(null);
35336
- const [refusal4, setRefusal] = useState94(null);
34887
+ const [refusal3, setRefusal] = useState94(null);
35337
34888
  useEffect80(() => {
35338
34889
  if (laneFromHost) setLane(laneFromHost);
35339
34890
  }, [laneFromHost]);
@@ -35410,7 +34961,7 @@ function ArchivedView({
35410
34961
  /* @__PURE__ */ jsxs106("div", { className: "flex min-w-0 flex-1 flex-col", children: [
35411
34962
  /* @__PURE__ */ jsx116("span", { className: "truncate text-sm", children: recordName(row.document, titleKey) }),
35412
34963
  /* @__PURE__ */ jsx116("span", { className: "truncate text-xs text-muted-foreground", "data-testid": "archived-who", children: archivedByLine(row) }),
35413
- refusal4 && refusal4.recordId === row.id ? /* @__PURE__ */ jsx116(RefusalNotice, { error: refusal4.error, className: "mt-2" }) : null
34964
+ refusal3 && refusal3.recordId === row.id ? /* @__PURE__ */ jsx116(RefusalNotice, { error: refusal3.error, className: "mt-2" }) : null
35414
34965
  ] }),
35415
34966
  mayRestore ? /* @__PURE__ */ jsx116(
35416
34967
  Button71,
@@ -35439,7 +34990,7 @@ function RetiredColumns({ tableId, mayRestore, whyNot }) {
35439
34990
  const [rows, setRows] = useState94(null);
35440
34991
  const [error, setError] = useState94(null);
35441
34992
  const [restoring, setRestoring] = useState94(null);
35442
- const [refusal4, setRefusal] = useState94(null);
34993
+ const [refusal3, setRefusal] = useState94(null);
35443
34994
  const read = useCallback40(async () => {
35444
34995
  const answer = await client.fieldsRetired({ table_id: tableId });
35445
34996
  if (answer.ok) {
@@ -35483,7 +35034,7 @@ function RetiredColumns({ tableId, mayRestore, whyNot }) {
35483
35034
  /* @__PURE__ */ jsxs106("div", { className: "flex min-w-0 flex-1 flex-col", children: [
35484
35035
  /* @__PURE__ */ jsx116("span", { className: "truncate text-sm", children: name }),
35485
35036
  /* @__PURE__ */ jsx116("span", { className: "truncate text-xs text-muted-foreground", children: retiredColumnLine(row) }),
35486
- refusal4 && refusal4.fieldId === row.id ? /* @__PURE__ */ jsx116(RefusalNotice, { error: refusal4.error, className: "mt-2" }) : null
35037
+ refusal3 && refusal3.fieldId === row.id ? /* @__PURE__ */ jsx116(RefusalNotice, { error: refusal3.error, className: "mt-2" }) : null
35487
35038
  ] }),
35488
35039
  mayRestore ? /* @__PURE__ */ jsx116(Button71, { size: "sm", variant: "outline", disabled: restoring === row.id, onClick: () => void restore(row.id), children: restoring === row.id ? "Bringing it back\u2026" : "Restore" }) : null
35489
35040
  ]
@@ -35552,7 +35103,7 @@ function ArchivedPortals({
35552
35103
  const [confirming, setConfirming] = useState95(null);
35553
35104
  const [typed2, setTyped] = useState95("");
35554
35105
  const [restoring, setRestoring] = useState95(null);
35555
- const [refusal4, setRefusal] = useState95(null);
35106
+ const [refusal3, setRefusal] = useState95(null);
35556
35107
  const [said2, setSaid] = useState95(null);
35557
35108
  const read = useCallback41(async () => {
35558
35109
  const answered = await client.listPortals({ archived: "archived" });
@@ -35668,7 +35219,7 @@ function ArchivedPortals({
35668
35219
  )
35669
35220
  ] })
35670
35221
  ] }) : null,
35671
- refusal4 && refusal4.portalId === portal.portal_id ? /* @__PURE__ */ jsx117(RefusalNotice, { error: refusal4.error }) : null
35222
+ refusal3 && refusal3.portalId === portal.portal_id ? /* @__PURE__ */ jsx117(RefusalNotice, { error: refusal3.error }) : null
35672
35223
  ]
35673
35224
  },
35674
35225
  portal.portal_id
@@ -35702,10 +35253,10 @@ import { useTable as useTable20 } from "@ai-matrx/records/react";
35702
35253
  var NOOP3 = () => {
35703
35254
  };
35704
35255
  function viewActions(whyNot, host) {
35705
- const one = (base, run) => {
35706
- if (whyNot !== null) return { ...base, disabledReason: whyNot, run: NOOP3 };
35707
- if (!run) return { ...base, disabledReason: ACTION_NOT_HERE_REASON, run: NOOP3 };
35708
- return { ...base, run };
35256
+ const one = (base2, run) => {
35257
+ if (whyNot !== null) return { ...base2, disabledReason: whyNot, run: NOOP3 };
35258
+ if (!run) return { ...base2, disabledReason: ACTION_NOT_HERE_REASON, run: NOOP3 };
35259
+ return { ...base2, run };
35709
35260
  };
35710
35261
  return [
35711
35262
  one({ id: "rename", label: "Rename view\u2026", icon: "pencil", group: "organize", verb: "rename" }, host.rename),
@@ -35717,8 +35268,8 @@ function viewActions(whyNot, host) {
35717
35268
  ];
35718
35269
  }
35719
35270
  function copyName(name, taken) {
35720
- const base = `${name} (copy)`;
35721
- if (!taken.includes(base)) return base;
35271
+ const base2 = `${name} (copy)`;
35272
+ if (!taken.includes(base2)) return base2;
35722
35273
  for (let n = 2; ; n += 1) {
35723
35274
  const next = `${name} (copy ${n})`;
35724
35275
  if (!taken.includes(next)) return next;
@@ -36490,7 +36041,7 @@ function MyChecklistSteps({
36490
36041
  }, [held, onSteps]);
36491
36042
  const steps = onlyIds ? held.filter((s) => onlyIds.has(s.step_id)) : held;
36492
36043
  const [busy, setBusy] = useState98(null);
36493
- const [refusal4, setRefusal] = useState98(null);
36044
+ const [refusal3, setRefusal] = useState98(null);
36494
36045
  const complete = useCallback44(
36495
36046
  async (step2, evidence) => {
36496
36047
  setBusy(step2.step_id);
@@ -36513,7 +36064,7 @@ function MyChecklistSteps({
36513
36064
  /* @__PURE__ */ jsx120("span", { className: "tabular-nums", children: steps.length })
36514
36065
  ] }),
36515
36066
  error ? /* @__PURE__ */ jsx120(RefusalNotice, { error }) : null,
36516
- refusal4 ? /* @__PURE__ */ jsx120(RefusalNotice, { error: refusal4 }) : null,
36067
+ refusal3 ? /* @__PURE__ */ jsx120(RefusalNotice, { error: refusal3 }) : null,
36517
36068
  /* @__PURE__ */ jsx120("ol", { className: "flex flex-col gap-1.5", children: steps.map(
36518
36069
  (step2) => actions ? /* @__PURE__ */ jsxs110("div", { className: "flex flex-col gap-0.5", "data-step-row": step2.step_id, children: [
36519
36070
  /* @__PURE__ */ jsx120(StepRow, { step: step2, busy: busy === step2.step_id, onComplete: (evidence) => void complete(step2, evidence) }),
@@ -36713,7 +36264,7 @@ function ChecklistTemplateEditor({
36713
36264
  const [saved, setSaved] = useState98(false);
36714
36265
  const [name, setName] = useState98("");
36715
36266
  const [rows, setRows] = useState98([{ ...EMPTY_ROW }]);
36716
- const [refusal4, setRefusal] = useState98(null);
36267
+ const [refusal3, setRefusal] = useState98(null);
36717
36268
  const [error, setError] = useState98(null);
36718
36269
  const [busy, setBusy] = useState98(false);
36719
36270
  const [loading, setLoading] = useState98(Boolean(templateId));
@@ -36889,10 +36440,10 @@ function ChecklistTemplateEditor({
36889
36440
  ] }, index)) }),
36890
36441
  /* @__PURE__ */ jsxs110("div", { className: "flex items-center gap-1.5", children: [
36891
36442
  /* @__PURE__ */ jsx120(Button75, { size: "sm", variant: "outline", onClick: () => setRows((held) => [...held, { ...EMPTY_ROW }]), children: "Add a step" }),
36892
- /* @__PURE__ */ jsx120(Button75, { size: "sm", disabled: busy || refusal4 !== null || spec.steps.length === 0, onClick: () => void save(), children: busy ? "\u2026" : "Save" }),
36443
+ /* @__PURE__ */ jsx120(Button75, { size: "sm", disabled: busy || refusal3 !== null || spec.steps.length === 0, onClick: () => void save(), children: busy ? "\u2026" : "Save" }),
36893
36444
  saved && !busy ? /* @__PURE__ */ jsx120("span", { className: "text-xs text-muted-foreground", "data-testid": "checklist-editor-saved", role: "status", children: "Saved" }) : null
36894
36445
  ] }),
36895
- refusal4 ? /* @__PURE__ */ jsx120("p", { className: "text-xs text-muted-foreground", "data-testid": "checklist-editor-refusal", children: refusal4 }) : null
36446
+ refusal3 ? /* @__PURE__ */ jsx120("p", { className: "text-xs text-muted-foreground", "data-testid": "checklist-editor-refusal", children: refusal3 }) : null
36896
36447
  ] });
36897
36448
  }
36898
36449
  function toStepSpec(row, index) {
@@ -42228,7 +41779,7 @@ function FormStage({
42228
41779
  const [answers, setAnswers] = useState114(() => ({ ...initialAnswers ?? {} }));
42229
41780
  const [at, setAt] = useState114(0);
42230
41781
  const [error, setError] = useState114(null);
42231
- const [refusal4, setRefusal] = useState114(null);
41782
+ const [refusal3, setRefusal] = useState114(null);
42232
41783
  const [writing, setWriting] = useState114(false);
42233
41784
  const [done, setDone] = useState114(null);
42234
41785
  const [hidden, setHidden] = useState114({});
@@ -42601,10 +42152,10 @@ function FormStage({
42601
42152
  ) : null,
42602
42153
  form.intro && index === 0 ? /* @__PURE__ */ jsx137("p", { className: "text-base text-muted-foreground", children: authored(host, form.intro, "form-intro") }) : null,
42603
42154
  error ? /* @__PURE__ */ jsx137(RefusalNotice, { error, className: "text-left" }) : null,
42604
- refusal4 ? /* @__PURE__ */ jsx137(
42155
+ refusal3 ? /* @__PURE__ */ jsx137(
42605
42156
  RefusalNotice,
42606
42157
  {
42607
- error: refusal4,
42158
+ error: refusal3,
42608
42159
  className: "text-left",
42609
42160
  onKeepEditing: () => {
42610
42161
  setRefusal(null);
@@ -42799,11 +42350,11 @@ import {
42799
42350
  formLookDocument
42800
42351
  } from "@ai-matrx/records/forms";
42801
42352
  import { Fragment as Fragment56, jsx as jsx138, jsxs as jsxs128 } from "react/jsx-runtime";
42802
- function freshFormName(base, taken) {
42353
+ function freshFormName(base2, taken) {
42803
42354
  const names = new Set(taken.map((n) => n.trim().toLowerCase()));
42804
- if (!names.has(base.toLowerCase())) return base;
42355
+ if (!names.has(base2.toLowerCase())) return base2;
42805
42356
  for (let n = 2; ; n += 1) {
42806
- const next = `${base} ${n}`;
42357
+ const next = `${base2} ${n}`;
42807
42358
  if (!names.has(next.toLowerCase())) return next;
42808
42359
  }
42809
42360
  }
@@ -43100,8 +42651,8 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
43100
42651
  return;
43101
42652
  }
43102
42653
  setMakeOnMount("making");
43103
- const base = table.data?.name?.trim() ? `${table.data.name.trim()} form` : "Form";
43104
- void create(freshFormName(base, forms.map((f) => f.name))).then(
42654
+ const base2 = table.data?.name?.trim() ? `${table.data.name.trim()} form` : "Form";
42655
+ void create(freshFormName(base2, forms.map((f) => f.name))).then(
43105
42656
  (made) => setMakeOnMount(made ? "made" : "not-made")
43106
42657
  );
43107
42658
  }, [createOnMount, makeOnMount, forms, fields.data, create, table.data, table.error]);
@@ -45063,7 +44614,7 @@ function AddChart({ subject, onAdd, onClose }) {
45063
44614
  const field2 = all.find((f) => f.key === key);
45064
44615
  return field2 ? scalarText(field2, value, labels) : String(value);
45065
44616
  };
45066
- const [measureKey5, setMeasureKey] = useState121("count");
44617
+ const [measureKey4, setMeasureKey] = useState121("count");
45067
44618
  const [splitKey, setSplitKey] = useState121("none");
45068
44619
  const [kind, setKind] = useState121("auto");
45069
44620
  const [filter, setFilter] = useState121({});
@@ -45071,7 +44622,7 @@ function AddChart({ subject, onAdd, onClose }) {
45071
44622
  const numbers = numberColumns(all);
45072
44623
  const choices = offerableFields(all, "choice");
45073
44624
  const dates = offerableFields(all, "date");
45074
- const measure = measureKey5 === "count" ? { op: "count" } : { op: measureKey5.split(":")[0], key: measureKey5.split(":")[1] };
44625
+ const measure = measureKey4 === "count" ? { op: "count" } : { op: measureKey4.split(":")[0], key: measureKey4.split(":")[1] };
45075
44626
  const split = splitKey === "none" ? { kind: "none" } : splitKey.startsWith("period:") ? { kind: "period", key: splitKey.split(":")[2], by: splitKey.split(":")[1] } : { kind: "column", key: splitKey.slice("column:".length) };
45076
44627
  const shape = kind !== "auto" ? kind : split.kind === "period" ? "line" : split.kind === "column" ? "column" : "number";
45077
44628
  function pickTable(next) {
@@ -45089,7 +44640,7 @@ function AddChart({ subject, onAdd, onClose }) {
45089
44640
  return /* @__PURE__ */ jsxs135("div", { className: "flex flex-col gap-2 rounded border p-2 text-xs", role: "group", "aria-label": "Add chart", children: [
45090
44641
  /* @__PURE__ */ jsxs135("div", { className: "flex flex-wrap items-center gap-1", children: [
45091
44642
  /* @__PURE__ */ jsx146("div", { className: "min-w-[12rem]", children: /* @__PURE__ */ jsx146(TablePicker, { dataSource: client.config.dataSource, value: tableId, onChange: pickTable }) }),
45092
- /* @__PURE__ */ jsxs135(Select17, { value: measureKey5, onValueChange: setMeasureKey, children: [
44643
+ /* @__PURE__ */ jsxs135(Select17, { value: measureKey4, onValueChange: setMeasureKey, children: [
45093
44644
  /* @__PURE__ */ jsx146(SelectTrigger17, { size: "sm", "aria-label": "What the chart counts", className: "h-7 min-w-[8rem] text-xs", children: /* @__PURE__ */ jsx146(SelectValue17, {}) }),
45094
44645
  /* @__PURE__ */ jsxs135(SelectContent17, { children: [
45095
44646
  /* @__PURE__ */ jsx146(SelectItem17, { value: "count", children: "How many" }),
@@ -45185,14 +44736,14 @@ function filterTargets(filter, blocks) {
45185
44736
  if (filter.targets && filter.targets.length > 0) return filter.targets;
45186
44737
  return blocks.filter((b) => b.kind === "list" && b.table_id === filter.table_id).map((b) => b.id);
45187
44738
  }
45188
- function combineFilter(base, extra, fieldIdOf) {
44739
+ function combineFilter(base2, extra, fieldIdOf) {
45189
44740
  const extraKeys = Object.keys(extra);
45190
- if (!base || !isRuleFilter3(base) && Object.keys(base).length === 0) {
44741
+ if (!base2 || !isRuleFilter3(base2) && Object.keys(base2).length === 0) {
45191
44742
  return { filter: extraKeys.length > 0 ? { ...extra } : null, dropped: [] };
45192
44743
  }
45193
- if (!isRuleFilter3(base)) return { filter: { ...base, ...extra }, dropped: [] };
44744
+ if (!isRuleFilter3(base2)) return { filter: { ...base2, ...extra }, dropped: [] };
45194
44745
  const dropped = [];
45195
- let rule = base;
44746
+ let rule = base2;
45196
44747
  for (const key of extraKeys) {
45197
44748
  const id = fieldIdOf(key);
45198
44749
  if (!id) {
@@ -45848,372 +45399,9 @@ import { Badge as Badge24, BasicInput as BasicInput33, Button as Button97, Check
45848
45399
  import { useFields as useFields31, useRecordsClient as useRecordsClient88 } from "@ai-matrx/records/react";
45849
45400
 
45850
45401
  // src/question.ts
45851
- import { measureKey as measureKey4 } from "@ai-matrx/records";
45852
- import { mapPgError as mapPgError3 } from "@ai-matrx/records/core";
45853
- var QUESTION_OPS = ["count", "sum", "avg", "min", "max"];
45854
- var QUESTION_LIMIT_DEFAULT = 25;
45855
- var QUESTION_GROUP_CEILING = 200;
45856
- var QUESTION_THROUGH_GROUP_CAP = 60;
45857
- function newQuestion() {
45858
- return { v: 1, measures: [{ op: "count" }], where: null, through: [], group: null, asOf: null, order: null, limit: QUESTION_LIMIT_DEFAULT, show: "table" };
45859
- }
45860
- function questionFromDefinition(definition) {
45861
- const raw = definition && typeof definition === "object" ? definition.question : null;
45862
- const base = newQuestion();
45863
- if (!raw || typeof raw !== "object") return base;
45864
- const measures = Array.isArray(raw.measures) ? raw.measures.filter((m) => !!m && QUESTION_OPS.includes(m.op)) : [];
45865
- return {
45866
- v: 1,
45867
- measures: measures.length > 0 ? measures : base.measures,
45868
- where: raw.where && typeof raw.where === "object" ? raw.where : null,
45869
- through: Array.isArray(raw.through) ? raw.through.filter((t) => t && typeof t.relation === "string" && typeof t.key === "string") : [],
45870
- group: raw.group && typeof raw.group === "object" && "kind" in raw.group ? raw.group : null,
45871
- asOf: typeof raw.asOf === "string" && raw.asOf !== "" ? raw.asOf : null,
45872
- order: raw.order && (raw.order.by === "measure" || raw.order.by === "count") ? raw.order : null,
45873
- limit: typeof raw.limit === "number" && raw.limit > 0 ? Math.min(Math.floor(raw.limit), QUESTION_GROUP_CEILING) : base.limit,
45874
- show: ["table", "bar", "column", "line", "donut", "number"].includes(raw.show) ? raw.show : base.show
45875
- };
45876
- }
45877
- function refusal(message, hint) {
45878
- return { ok: false, error: { code: "invalid_argument", message, ...hint ? { hint } : {} } };
45879
- }
45880
- function fieldById(fields, id) {
45881
- return fields.find((f) => f.id === id);
45882
- }
45883
- function flatWhere(where, fields) {
45884
- if (!where) return {};
45885
- const node = where;
45886
- const clauses = node.op === "and" ? node.args ?? [] : [where];
45887
- const out = {};
45888
- for (const clause of clauses) {
45889
- const c = clause;
45890
- if (c.op !== "eq" || !c.args?.[0]?.field || !c.args[1] || !("const" in c.args[1])) return null;
45891
- const f = fieldById(fields, c.args[0].field);
45892
- if (!f) return null;
45893
- out[f.key] = c.args[1].const;
45894
- }
45895
- return out;
45896
- }
45897
- function isFormula(fields, key) {
45898
- if (!key) return false;
45899
- const f = fields.find((x) => x.key === key);
45900
- return !!f && (f.type === "formula" || editorKindFor(f) === "formula");
45901
- }
45902
- function rowsOf2(rows, groupKey, keys) {
45903
- return rows.map((r) => {
45904
- const values = {};
45905
- for (const k of keys) {
45906
- const v = (r.measures ?? {})[k];
45907
- values[k] = v === null || v === void 0 ? null : Number(v);
45908
- }
45909
- const withheld = {};
45910
- for (const [name, notice] of Object.entries(r.withheld ?? {})) if (keys.includes(name)) withheld[name] = notice;
45911
- const g = groupKey ? (r.groups ?? {})[groupKey] : null;
45912
- return { group: g === null || g === void 0 ? null : String(g), values, withheld, n: Number(r.row_count ?? 0) };
45913
- });
45914
- }
45915
- function sortAndCut(rows, spec, keys) {
45916
- const first = keys[0];
45917
- const by = spec.order?.by ?? "count";
45918
- const dir = spec.order?.direction ?? "desc";
45919
- const value = (r) => by === "count" ? r.n : first ? r.values[first] : null;
45920
- const present = rows.filter((r) => value(r) !== null && value(r) !== void 0);
45921
- const blank = rows.filter((r) => value(r) === null || value(r) === void 0);
45922
- present.sort((a, b) => dir === "desc" ? value(b) - value(a) : value(a) - value(b));
45923
- return [...present, ...blank];
45924
- }
45925
- async function askQuestion(client, tableId, spec, fields) {
45926
- const measures = spec.measures.length > 0 ? spec.measures : [{ op: "count" }];
45927
- for (const m of measures) {
45928
- if (m.op !== "count" && !m.key) return refusal(`Pick the column to ${m.op === "avg" ? "average" : m.op}.`);
45929
- }
45930
- const keys = measures.map((m) => measureKey4({ op: m.op, ...m.key ? { key: m.key } : {} }));
45931
- const group = spec.group;
45932
- if (spec.asOf) return askAsOf(client, tableId, spec, fields, measures, keys);
45933
- let filter = spec.where ?? {};
45934
- if (spec.through.length > 0) {
45935
- const flat = flatWhere(spec.where, fields);
45936
- if (flat === null) {
45937
- return refusal(
45938
- "A condition on a related table can only be joined with \u201Cis\u201D conditions, all of them true.",
45939
- "Simplify the other conditions, or move them to the related table."
45940
- );
45941
- }
45942
- for (const t of spec.through) flat[`${t.relation}.${t.key}`] = t.value;
45943
- filter = flat;
45944
- }
45945
- if (group?.kind === "through") return askThrough(client, tableId, spec, fields, measures, keys, filter);
45946
- const ordered = measures.map((m, i) => {
45947
- const one = { op: m.op, ...m.key ? { key: m.key } : {} };
45948
- if (i === 0 && spec.order?.by === "measure") one["order"] = spec.order.direction;
45949
- return one;
45950
- });
45951
- if (spec.order?.by === "count") {
45952
- const at = measures.findIndex((m) => m.op === "count");
45953
- if (at >= 0) ordered[at]["order"] = spec.order.direction;
45954
- else ordered.unshift({ op: "count", order: spec.order.direction });
45955
- }
45956
- const groupBy = group?.kind === "field" ? [group.key] : [];
45957
- const bucket = group?.kind === "bucket" ? { key: group.key, by: group.by } : null;
45958
- const groupKey = group?.kind === "field" ? group.key : group?.kind === "bucket" ? `${group.key}_${group.by}` : null;
45959
- const limit = group ? Math.max(1, Math.min(spec.limit, QUESTION_GROUP_CEILING)) : 1;
45960
- const asked2 = await client.recordAggregate({
45961
- table_id: tableId,
45962
- groupBy,
45963
- // `order` rides the measure into custom.agg_sql (VISION-REACH W2); the type predates it.
45964
- measures: ordered,
45965
- bucket,
45966
- filter,
45967
- limit
45968
- });
45969
- if (!asked2.ok) return asked2;
45970
- const rows = rowsOf2(asked2.data, groupKey, keys);
45971
- let groupsTotal = group ? rows.length : null;
45972
- let groupsExact = true;
45973
- if (group && rows.length >= limit && limit < QUESTION_GROUP_CEILING) {
45974
- const every = await client.recordAggregate({
45975
- table_id: tableId,
45976
- groupBy,
45977
- measures: [{ op: "count" }],
45978
- bucket,
45979
- filter,
45980
- limit: QUESTION_GROUP_CEILING
45981
- });
45982
- if (every.ok) {
45983
- groupsTotal = every.data.length;
45984
- groupsExact = every.data.length < QUESTION_GROUP_CEILING;
45985
- } else {
45986
- groupsExact = false;
45987
- }
45988
- } else if (group && rows.length >= QUESTION_GROUP_CEILING) {
45989
- groupsExact = false;
45990
- }
45991
- return {
45992
- ok: true,
45993
- data: {
45994
- rows,
45995
- measures: keys,
45996
- groupKey,
45997
- groupsTotal,
45998
- groupsExact,
45999
- truncated: groupsTotal !== null && (groupsTotal > rows.length || !groupsExact),
46000
- asOf: null
46001
- }
46002
- };
46003
- }
46004
- async function askThrough(client, tableId, spec, fields, measures, keys, filter) {
46005
- const group = spec.group;
46006
- const rel = fields.find((f) => f.key === group.relation);
46007
- if (!rel || !rel.relation_target) return refusal(`\u201C${group.relation}\u201D is not a relation of this table.`);
46008
- const flat = filter && !filter.op ? filter : flatWhere(filter, fields);
46009
- if (flat === null) {
46010
- return refusal(
46011
- "Summarizing by a related table's column can only be joined with \u201Cis\u201D conditions, all of them true.",
46012
- "Simplify the conditions, or summarize by a column of this table."
46013
- );
46014
- }
46015
- const values = await client.recordAggregate({
46016
- table_id: rel.relation_target,
46017
- groupBy: [group.key],
46018
- measures: [{ op: "count" }],
46019
- limit: QUESTION_THROUGH_GROUP_CAP + 1
46020
- });
46021
- if (!values.ok) return values;
46022
- const named = values.data.map((r) => (r.groups ?? {})[group.key] ?? null).filter((v) => v !== null && v !== "");
46023
- if (named.length > QUESTION_THROUGH_GROUP_CAP) {
46024
- return refusal(
46025
- `That column has more than ${QUESTION_THROUGH_GROUP_CAP} values, too many to summarize by.`,
46026
- "Add a condition that narrows it, or summarize by a column of this table."
46027
- );
46028
- }
46029
- const answered = [];
46030
- for (let i = 0; i < named.length; i += 8) {
46031
- const batch = await Promise.all(
46032
- named.slice(i, i + 8).map(async (value) => {
46033
- const one = await client.recordAggregate({
46034
- table_id: tableId,
46035
- groupBy: [],
46036
- measures: measures.map((m) => ({ op: m.op, ...m.key ? { key: m.key } : {} })),
46037
- filter: { ...flat, [`${group.relation}.${group.key}`]: value },
46038
- limit: 1
46039
- });
46040
- return { value, one };
46041
- })
46042
- );
46043
- for (const { value, one } of batch) {
46044
- if (!one.ok) return one;
46045
- const [row] = rowsOf2(one.data, null, keys);
46046
- if (row && row.n > 0) answered.push({ ...row, group: value });
46047
- }
46048
- }
46049
- const sorted = sortAndCut(answered, spec, keys);
46050
- const limit = Math.max(1, Math.min(spec.limit, QUESTION_GROUP_CEILING));
46051
- return {
46052
- ok: true,
46053
- data: {
46054
- rows: sorted.slice(0, limit),
46055
- measures: keys,
46056
- groupKey: `${group.relation}.${group.key}`,
46057
- groupsTotal: sorted.length,
46058
- groupsExact: true,
46059
- truncated: sorted.length > limit,
46060
- asOf: null
46061
- }
46062
- };
46063
- }
46064
- async function askAsOf(client, tableId, spec, fields, measures, keys) {
46065
- const group = spec.group;
46066
- if (spec.through.length > 0 || group?.kind === "through") {
46067
- return refusal("\u201CAs of\u201D cannot reach across a relation yet.", "Ask without the related table's column, or without \u201Cas of\u201D.");
46068
- }
46069
- if (group?.kind === "bucket") {
46070
- return refusal("\u201CAs of\u201D cannot cut dates into periods yet.", "Summarize by the date itself, or ask without \u201Cas of\u201D.");
46071
- }
46072
- const match = flatWhere(spec.where, fields);
46073
- if (match === null) {
46074
- return refusal("\u201CAs of\u201D can only be filtered with \u201Cis\u201D conditions, all of them true.", "Simplify the filter, or ask without \u201Cas of\u201D.");
46075
- }
46076
- const formula = [...measures.map((m) => m.key), group?.key, ...Object.keys(match)].find((k) => isFormula(fields, k));
46077
- if (formula) {
46078
- const f = fields.find((x) => x.key === formula);
46079
- return refusal(
46080
- `${f?.label || formula} is worked out when a record is read, so it cannot be measured as of a moment.`,
46081
- "Measure a stored column, or ask without \u201Cas of\u201D."
46082
- );
46083
- }
46084
- const moment = new Date(spec.asOf);
46085
- if (Number.isNaN(moment.getTime())) return refusal("\u201CAs of\u201D is not a date and time.");
46086
- const config = client.config;
46087
- const groupKey = group?.kind === "field" ? group.key : null;
46088
- const byGroup = /* @__PURE__ */ new Map();
46089
- for (let i = 0; i < measures.length; i++) {
46090
- const m = measures[i];
46091
- const response = await config.dataSource.rpc(
46092
- "record_aggregate_as_of",
46093
- {
46094
- p_organization_id: config.organizationId,
46095
- p_table_id: tableId,
46096
- p_recorded_at: moment.toISOString(),
46097
- p_measure: m.op,
46098
- p_field_key: m.key ?? null,
46099
- p_group_by: groupKey,
46100
- p_match: match
46101
- },
46102
- { schema: config.schema ?? "custom" }
46103
- );
46104
- if (response.error) return { ok: false, error: mapPgError3(response.error, "askQuestion.asOf") };
46105
- const rows2 = Array.isArray(response.data) ? response.data : [];
46106
- const bad = rows2.find((r) => Number(r.not_numbers ?? 0) > 0);
46107
- if (bad && m.op !== "count") {
46108
- return refusal(`${m.key} held \u201C${bad.a_non_number}\u201D then, which is not a number, so its ${m.op} cannot be worked out.`);
46109
- }
46110
- for (const r of rows2) {
46111
- const g = groupKey ? r.bucket ?? null : null;
46112
- const at = g ?? "\0all";
46113
- const row = byGroup.get(at) ?? { group: g, values: {}, withheld: {}, n: Number(r.row_count ?? 0) };
46114
- row.values[keys[i]] = m.op === "count" ? Number(r.row_count ?? 0) : r.result === null ? null : Number(r.result);
46115
- byGroup.set(at, row);
46116
- }
46117
- }
46118
- let rows = [...byGroup.values()];
46119
- if (!groupKey && rows.length === 0) {
46120
- rows = [{ group: null, values: Object.fromEntries(keys.map((k, i) => [k, measures[i].op === "count" ? 0 : null])), withheld: {}, n: 0 }];
46121
- }
46122
- for (const r of rows) for (const k of keys) if (!(k in r.values)) r.values[k] = null;
46123
- const sorted = groupKey ? sortAndCut(rows, spec, keys) : rows;
46124
- const limit = groupKey ? Math.max(1, Math.min(spec.limit, QUESTION_GROUP_CEILING)) : 1;
46125
- return {
46126
- ok: true,
46127
- data: {
46128
- rows: sorted.slice(0, limit),
46129
- measures: keys,
46130
- groupKey,
46131
- groupsTotal: groupKey ? sorted.length : null,
46132
- groupsExact: true,
46133
- truncated: groupKey ? sorted.length > limit : false,
46134
- asOf: moment.toISOString()
46135
- }
46136
- };
46137
- }
46138
- async function unreadableKeys(client, tableId, fields) {
46139
- const guarded = fields.filter((f) => f.sensitivity === "confidential" || f.sensitivity === "restricted");
46140
- const out = /* @__PURE__ */ new Set();
46141
- if (guarded.length === 0) return out;
46142
- const asked2 = await client.recordAggregate({
46143
- table_id: tableId,
46144
- groupBy: [],
46145
- measures: guarded.map((f) => ({ op: "filled", key: f.key })),
46146
- limit: 1
46147
- });
46148
- if (!asked2.ok) {
46149
- for (const f of guarded) {
46150
- const one = await client.recordAggregate({ table_id: tableId, groupBy: [], measures: [{ op: "filled", key: f.key }], limit: 1 });
46151
- if (!one.ok || Object.keys(one.data[0]?.withheld ?? {}).length > 0) out.add(f.key);
46152
- }
46153
- return out;
46154
- }
46155
- for (const f of guarded) if (asked2.data.some((r) => r.withheld && `filled_${f.key}` in r.withheld)) out.add(f.key);
46156
- return out;
46157
- }
46158
- function measurableFields(fields, op2) {
46159
- if (op2 === "count") return [];
46160
- return fields.filter((f) => isNumericField(f) || (op2 === "min" || op2 === "max") && editorKindFor(f) === "datetime");
46161
- }
46162
- var QUESTION_SURFACE = "custom/records/question";
46163
- function savedOf(row) {
46164
- return {
46165
- id: row["id"],
46166
- name: String(row["name"] ?? ""),
46167
- spec: questionFromDefinition(row["definition"]),
46168
- shared: row["visibility"] !== "personal",
46169
- version: Number(row["version"] ?? 1),
46170
- createdBy: row["created_by"] ?? null
46171
- };
46172
- }
46173
- async function questionsOf(client, tableId) {
46174
- const response = await client.config.dataSource.schema("platform").from("saved_view").select("id, name, definition, visibility, version, created_by").eq("surface_key", QUESTION_SURFACE).eq("subject_id", tableId).is("deleted_at", null).order("name", { ascending: true });
46175
- if (response.error) return { ok: false, error: mapPgError3(response.error, "questionsOf") };
46176
- const me = client.config.actor?.user_id ?? null;
46177
- return {
46178
- ok: true,
46179
- data: (response.data ?? []).map(savedOf).filter((q) => q.shared || me !== null && q.createdBy === me)
46180
- };
46181
- }
46182
- async function questionSave(client, args) {
46183
- const name = args.name.trim();
46184
- if (!name) return refusal("Name the question so the team can find it.");
46185
- const response = await client.config.dataSource.rpc(
46186
- "saved_view_save",
46187
- {
46188
- p_surface_key: QUESTION_SURFACE,
46189
- p_id: args.id ?? null,
46190
- p_subject_id: args.tableId,
46191
- p_organization_id: client.config.organizationId,
46192
- p_name: name,
46193
- p_definition: { question: args.spec },
46194
- p_visibility: args.shared ? "internal" : "personal",
46195
- p_touch: true,
46196
- ...args.expectedVersion !== void 0 ? { p_expected_version: args.expectedVersion } : {}
46197
- },
46198
- { schema: "public" }
46199
- );
46200
- if (response.error) {
46201
- if (response.error.code === "23505") {
46202
- return { ok: false, error: { code: "already_exists", message: `You already have a question called \u201C${name}\u201D.` } };
46203
- }
46204
- return { ok: false, error: mapPgError3(response.error, "questionSave") };
46205
- }
46206
- return { ok: true, data: response.data ? savedOf(response.data) : null };
46207
- }
46208
- async function questionArchive(client, id, version) {
46209
- const response = await client.config.dataSource.rpc(
46210
- "saved_view_archive",
46211
- { p_surface_key: QUESTION_SURFACE, p_id: id, ...version !== void 0 ? { p_expected_version: version } : {} },
46212
- { schema: "public" }
46213
- );
46214
- if (response.error) return { ok: false, error: mapPgError3(response.error, "questionArchive") };
46215
- return { ok: true, data: response.data !== null };
46216
- }
45402
+ var question_exports = {};
45403
+ __reExport(question_exports, questions_star);
45404
+ import * as questions_star from "@ai-matrx/records/questions";
46217
45405
 
46218
45406
  // src/QuestionPanel.tsx
46219
45407
  import { Fragment as Fragment59, jsx as jsx148, jsxs as jsxs137 } from "react/jsx-runtime";
@@ -46269,12 +45457,12 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46269
45457
  }
46270
45458
  let live = true;
46271
45459
  void (async () => {
46272
- const mine2 = await unreadableKeys(client, tableId, all);
45460
+ const mine2 = await (0, question_exports.unreadableKeys)(client, tableId, all);
46273
45461
  const out = {};
46274
45462
  for (const rel of all.filter((f) => editorKindFor(f) === "relation" && f.relation_target && !mine2.has(f.key))) {
46275
45463
  const target = await client.fields({ table_id: rel.relation_target });
46276
45464
  if (!target.ok) continue;
46277
- const theirs = await unreadableKeys(client, rel.relation_target, target.data);
45465
+ const theirs = await (0, question_exports.unreadableKeys)(client, rel.relation_target, target.data);
46278
45466
  out[rel.key] = { relation: rel, fields: target.data.filter((f) => !theirs.has(f.key) && editorKindFor(f) !== "relation") };
46279
45467
  }
46280
45468
  if (!live) return;
@@ -46289,7 +45477,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46289
45477
  const [saved, setSaved] = useState123(null);
46290
45478
  const [savedEpoch, setSavedEpoch] = useState123(0);
46291
45479
  const [current, setCurrent] = useState123(null);
46292
- const [spec, setSpec] = useState123(newQuestion);
45480
+ const [spec, setSpec] = useState123(question_exports.newQuestion);
46293
45481
  const [name, setName] = useState123("");
46294
45482
  const [shared, setShared] = useState123(true);
46295
45483
  const [saveError, setSaveError] = useState123(null);
@@ -46298,7 +45486,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46298
45486
  const openedFromLink = useRef59(false);
46299
45487
  useEffect107(() => {
46300
45488
  let live = true;
46301
- void questionsOf(client, tableId).then((answer2) => {
45489
+ void (0, question_exports.questionsOf)(client, tableId).then((answer2) => {
46302
45490
  if (!live) return;
46303
45491
  setSaved(answer2.ok ? answer2.data : []);
46304
45492
  if (answer2.ok && activeQuestionId && !openedFromLink.current) {
@@ -46314,7 +45502,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46314
45502
  }, [client, tableId, savedEpoch, activeQuestionId]);
46315
45503
  const open = (q) => {
46316
45504
  setCurrent(q);
46317
- setSpec(q ? q.spec : newQuestion());
45505
+ setSpec(q ? q.spec : (0, question_exports.newQuestion)());
46318
45506
  setName(q ? q.name : "");
46319
45507
  setShared(q ? q.shared : true);
46320
45508
  setSaveError(null);
@@ -46333,7 +45521,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46333
45521
  let live = true;
46334
45522
  setAsking(true);
46335
45523
  const t = setTimeout(() => {
46336
- void askQuestion(client, tableId, spec, all).then((a) => {
45524
+ void (0, question_exports.askQuestion)(client, tableId, spec, all).then((a) => {
46337
45525
  if (!live) return;
46338
45526
  setAnswer(a);
46339
45527
  setAsking(false);
@@ -46349,7 +45537,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46349
45537
  setSaving(true);
46350
45538
  setSaveError(null);
46351
45539
  const editing = !asNew && current && mine;
46352
- const kept = await questionSave(client, {
45540
+ const kept = await (0, question_exports.questionSave)(client, {
46353
45541
  ...editing ? { id: current.id, expectedVersion: current.version } : {},
46354
45542
  tableId,
46355
45543
  name: asNew && current && name.trim() === current.name ? `${name.trim()} (copy)` : name,
@@ -46367,7 +45555,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46367
45555
  };
46368
45556
  const archive = async () => {
46369
45557
  if (!current) return;
46370
- const gone = await questionArchive(client, current.id, current.version);
45558
+ const gone = await (0, question_exports.questionArchive)(client, current.id, current.version);
46371
45559
  if (!gone.ok) return setSaveError(gone.error);
46372
45560
  open(null);
46373
45561
  setSavedEpoch((n) => n + 1);
@@ -46522,17 +45710,17 @@ function Measures({ measures, fields, onChange }) {
46522
45710
  const set = (i, next) => onChange(measures.map((m, j) => j === i ? next : m));
46523
45711
  return /* @__PURE__ */ jsxs137("div", { className: "flex flex-col gap-1", children: [
46524
45712
  measures.map((m, i) => {
46525
- const eligible = measurableFields(fields, m.op);
45713
+ const eligible = (0, question_exports.measurableFields)(fields, m.op);
46526
45714
  return /* @__PURE__ */ jsxs137("div", { className: "flex items-center gap-1", "data-testid": "question-measure", children: [
46527
45715
  /* @__PURE__ */ jsx148(
46528
45716
  PickOne,
46529
45717
  {
46530
45718
  label: "Measure",
46531
45719
  value: m.op,
46532
- options: QUESTION_OPS.map((op2) => ({ value: op2, label: OP_LABEL[op2] })),
45720
+ options: question_exports.QUESTION_OPS.map((op2) => ({ value: op2, label: OP_LABEL[op2] })),
46533
45721
  onChange: (op2) => {
46534
45722
  const nextOp = op2;
46535
- const keep = nextOp !== "count" && measurableFields(fields, nextOp).some((f) => f.key === m.key);
45723
+ const keep = nextOp !== "count" && (0, question_exports.measurableFields)(fields, nextOp).some((f) => f.key === m.key);
46536
45724
  set(i, nextOp === "count" ? { op: "count" } : { op: nextOp, ...keep ? { key: m.key } : {} });
46537
45725
  },
46538
45726
  className: "w-28",
@@ -46964,14 +46152,14 @@ function questionFromWords(text, fields, choices = {}) {
46964
46152
  const measured = head === "" ? null : columnNamed2(head, names);
46965
46153
  if (op2 === null) {
46966
46154
  if (head === "") op2 = "count";
46967
- else if (measured && measurableFields([...fields], "sum").some((f) => f.key === measured.key)) op2 = "sum";
46155
+ else if (measured && (0, question_exports.measurableFields)([...fields], "sum").some((f) => f.key === measured.key)) op2 = "sum";
46968
46156
  else return { ok: false, why: "Start with count, sum, average, smallest or largest" };
46969
46157
  }
46970
- const spec = { ...newQuestion(), group };
46158
+ const spec = { ...(0, question_exports.newQuestion)(), group };
46971
46159
  let measureReads = "Count";
46972
46160
  if (op2 !== "count") {
46973
46161
  if (!measured) return { ok: false, why: head === "" ? `${OP_READS[op2]} which column?` : `No column named \u201C${head}\u201D` };
46974
- if (!measurableFields([...fields], op2).some((f) => f.key === measured.key)) {
46162
+ if (!(0, question_exports.measurableFields)([...fields], op2).some((f) => f.key === measured.key)) {
46975
46163
  return { ok: false, why: `${fieldName(measured)} is not a number column` };
46976
46164
  }
46977
46165
  spec.measures = [{ op: op2, key: measured.key }];
@@ -47008,7 +46196,7 @@ function TableAsk({ tableId, onOpenInQuestions }) {
47008
46196
  const read = questionFromWords(words2, all, choices);
47009
46197
  if (!read.ok) return setSaid({ kind: "not-read", why: read.why });
47010
46198
  setSaid({ kind: "asking", reads: read.reads });
47011
- const answered = await askQuestion(client, tableId, read.spec, all);
46199
+ const answered = await (0, question_exports.askQuestion)(client, tableId, read.spec, all);
47012
46200
  setSaid(answered.ok ? { kind: "answer", reads: read.reads, spec: read.spec, answer: answered.data } : { kind: "refused", error: answered.error });
47013
46201
  };
47014
46202
  return /* @__PURE__ */ jsxs138(Popover14, { open, onOpenChange: setOpen, children: [
@@ -49608,16 +48796,16 @@ function toolbarFold(input) {
49608
48796
  };
49609
48797
  const withGap = (width) => width > 0 ? width + gap : 0;
49610
48798
  const shareNow = input.share ? withGap(input.share.now) : 0;
49611
- const base = pieces.reduce((rest, p) => rest - withGap(p.piece.now), needsNow - shareNow);
48799
+ const base2 = pieces.reduce((rest, p) => rest - withGap(p.piece.now), needsNow - shareNow);
49612
48800
  const stages = input.tools ? [0, 1, 2, 3] : [0, 1, 2];
49613
48801
  const shareOn = input.share ? withGap(input.share.full ?? input.share.now) : 0;
49614
- const needs = stages.map((fold) => pieces.reduce((sum, p) => sum + withGap(widthAt(p, fold)), base + shareOn));
48802
+ const needs = stages.map((fold) => pieces.reduce((sum, p) => sum + withGap(widthAt(p, fold)), base2 + shareOn));
49615
48803
  const fits = needs.findIndex((need) => need <= available + 0.5);
49616
48804
  if (fits >= 0) return stages[fits];
49617
48805
  const least = Math.min(...needs);
49618
48806
  const most = stages[needs.findIndex((need) => need <= least + 0.5)];
49619
48807
  if (!input.tools || !input.share) return most;
49620
- const fixed = pieces.reduce((sum, p) => sum + withGap(p.stage === 3 ? SLOT_MIN : widthAt(p, 3)), base + shareOn);
48808
+ const fixed = pieces.reduce((sum, p) => sum + withGap(p.stage === 3 ? SLOT_MIN : widthAt(p, 3)), base2 + shareOn);
49621
48809
  return fixed > available + 0.5 ? 4 : most;
49622
48810
  }
49623
48811
  function naturalWidth(el) {
@@ -49774,7 +48962,7 @@ function useSlotScroll(slot) {
49774
48962
  }
49775
48963
 
49776
48964
  // src/TablePage.tsx
49777
- import { isUuidShape as isUuidShape4 } from "@ai-matrx/kit/uuid";
48965
+ import { isUuidShape as isUuidShape3 } from "@ai-matrx/kit/uuid";
49778
48966
  import { Fragment as Fragment68, jsx as jsx163, jsxs as jsxs152 } from "react/jsx-runtime";
49779
48967
  var RAIL_TITLE = {
49780
48968
  settings: "Table settings",
@@ -49861,7 +49049,7 @@ function TableNotHere({
49861
49049
  const client = useRecordsClient98();
49862
49050
  const [archived, setArchived] = useState138({ phase: "asking" });
49863
49051
  const [restoring, setRestoring] = useState138(false);
49864
- const [refusal4, setRefusal] = useState138(null);
49052
+ const [refusal3, setRefusal] = useState138(null);
49865
49053
  useEffect117(() => {
49866
49054
  let alive = true;
49867
49055
  void client.tableArchived({ table_id: tableId }).then((answered) => {
@@ -49879,7 +49067,7 @@ function TableNotHere({
49879
49067
  /* @__PURE__ */ jsx163("p", { className: "text-sm font-medium", children: "This table is archived" }),
49880
49068
  /* @__PURE__ */ jsx163("p", { className: "max-w-prose text-xs text-muted-foreground", children: TABLE_IS_ARCHIVED }),
49881
49069
  /* @__PURE__ */ jsx163("p", { className: "text-xs text-muted-foreground", children: archivedByLine2(row) }),
49882
- refusal4 ? /* @__PURE__ */ jsx163(RefusalNotice, { error: refusal4 }) : null,
49070
+ refusal3 ? /* @__PURE__ */ jsx163(RefusalNotice, { error: refusal3 }) : null,
49883
49071
  /* @__PURE__ */ jsxs152("div", { className: "flex gap-2", children: [
49884
49072
  /* @__PURE__ */ jsx163(
49885
49073
  Button110,
@@ -49996,7 +49184,7 @@ function openingView(activeView, activeDashboardId) {
49996
49184
  }
49997
49185
  function savedViewFromParam(activeView) {
49998
49186
  const word = typeof activeView === "string" ? activeView.trim() : "";
49999
- return isUuidShape4(word) ? word.toLowerCase() : null;
49187
+ return isUuidShape3(word) ? word.toLowerCase() : null;
50000
49188
  }
50001
49189
  function addressForView(view, layout) {
50002
49190
  return view && !view.isDefault ? view.id : layout;
@@ -50368,7 +49556,7 @@ function TablePage({
50368
49556
  const [designateRefused, setDesignateRefused] = useState138(null);
50369
49557
  const opensAs = view?.isDefault ? view.layout : null;
50370
49558
  const canDesignate = Boolean(
50371
- rights.organise && view && layoutShowing && layoutShowing !== opensAs && storeKeepsLayout(layoutShowing)
49559
+ rights.organise && view && layoutShowing && layoutShowing !== opensAs && storeKeepsLayout2(layoutShowing)
50372
49560
  );
50373
49561
  const layoutShowingLabel = layoutShowing ? LAYOUT_LABEL[layoutShowing] : "";
50374
49562
  const designate = async () => {
@@ -50872,7 +50060,7 @@ function TablePage({
50872
50060
  QuestionPanel,
50873
50061
  {
50874
50062
  tableId,
50875
- activeQuestionId: questionsFromLink && activeItemId && isUuidShape4(activeItemId) ? activeItemId : null,
50063
+ activeQuestionId: questionsFromLink && activeItemId && isUuidShape3(activeItemId) ? activeItemId : null,
50876
50064
  draft: questionDraft
50877
50065
  }
50878
50066
  ) : main === "archived" ? (
@@ -51128,7 +50316,7 @@ function EntityBoard({ entity, groupBy, cardFields, onOpenRecord, className }) {
51128
50316
  const writable = !column.readOnly && entity.canUpdate;
51129
50317
  const placed = (row) => entityValueText(column, entityCellValue(row, column)) || null;
51130
50318
  const lanes = [...words2.map((w) => ({ key: w, label: w })), { key: "", label: `No ${column.label.toLowerCase()}` }];
51131
- const rowsOf3 = (key) => entity.rows.filter((r) => (placed(r) ?? "") === key);
50319
+ const rowsOf2 = (key) => entity.rows.filter((r) => (placed(r) ?? "") === key);
51132
50320
  const drop = async (event, to) => {
51133
50321
  event.preventDefault();
51134
50322
  setOver(null);
@@ -51140,7 +50328,7 @@ function EntityBoard({ entity, groupBy, cardFields, onOpenRecord, className }) {
51140
50328
  if (says) setRefused({ to, says });
51141
50329
  };
51142
50330
  return /* @__PURE__ */ jsx164("div", { className: cn98("flex min-h-40 gap-2 overflow-x-auto pb-1", className), "data-records-entity-board": column.key, children: lanes.map((lane) => {
51143
- const cards = rowsOf3(lane.key);
50331
+ const cards = rowsOf2(lane.key);
51144
50332
  if (lane.key === "" && cards.length === 0) return null;
51145
50333
  return /* @__PURE__ */ jsxs153(
51146
50334
  "section",
@@ -51182,9 +50370,9 @@ function EntityBoard({ entity, groupBy, cardFields, onOpenRecord, className }) {
51182
50370
  );
51183
50371
  }) });
51184
50372
  }
51185
- function blockOfAnswer(answer, base, by) {
50373
+ function blockOfAnswer(answer, base2, by) {
51186
50374
  if (!answer.ok) {
51187
- return { ...base, refused: refusalSentence(answer.error) || "This chart could not be read.", ...answer.error.code ? { sqlstate: answer.error.code } : {} };
50375
+ return { ...base2, refused: refusalSentence(answer.error) || "This chart could not be read.", ...answer.error.code ? { sqlstate: answer.error.code } : {} };
51188
50376
  }
51189
50377
  const rows = answer.data.rows.filter((r) => by ? r.kind !== "total" : r.kind === "total").map((r) => {
51190
50378
  const groups = {};
@@ -51196,7 +50384,7 @@ function blockOfAnswer(answer, base, by) {
51196
50384
  for (const [k, v] of Object.entries(r.measures ?? {})) measuresOut[k] = typeof v === "number" ? v : v === null ? null : Number(v);
51197
50385
  return { groups, measures: measuresOut, row_count: Number(r.row_count) };
51198
50386
  });
51199
- return { ...base, rows };
50387
+ return { ...base2, rows };
51200
50388
  }
51201
50389
  function EntityChartBlock({ source, kind, by, measure, title, where, organization, centerValue, variant, className }) {
51202
50390
  const client = useRecordsClient99();
@@ -51204,9 +50392,9 @@ function EntityChartBlock({ source, kind, by, measure, title, where, organizatio
51204
50392
  const ask = JSON.stringify([source.token, by ?? null, m, where ?? null, organization ?? null]);
51205
50393
  const question = entityChartQuestion({ by, measure, where, organization });
51206
50394
  const measures = [m.op === "count" ? { op: "count" } : { op: m.op, key: m.of }];
51207
- const base = { title: title ?? "", kind, measures, group_by: by ? [by] : [] };
50395
+ const base2 = { title: title ?? "", kind, measures, group_by: by ? [by] : [] };
51208
50396
  const seeded = useSeededAnswerAt(`entity-chart:${ask}`, (c) => c.drillAsk({ source, question }));
51209
- const [block, setBlock] = useState139(() => seeded ? blockOfAnswer({ ok: true, data: seeded.data }, base, by) : null);
50397
+ const [block, setBlock] = useState139(() => seeded ? blockOfAnswer({ ok: true, data: seeded.data }, base2, by) : null);
51210
50398
  const seededFor = useRef63(seeded ? { ask: `${ask}|${kind}|${title ?? ""}`, at: seeded.at } : null);
51211
50399
  useEffect118(() => {
51212
50400
  const held = seededFor.current;
@@ -51215,7 +50403,7 @@ function EntityChartBlock({ source, kind, by, measure, title, where, organizatio
51215
50403
  let cancelled = false;
51216
50404
  void client.drillAsk({ source, question }).then((answer) => {
51217
50405
  if (cancelled) return;
51218
- setBlock(blockOfAnswer(answer, base, by));
50406
+ setBlock(blockOfAnswer(answer, base2, by));
51219
50407
  });
51220
50408
  return () => {
51221
50409
  cancelled = true;
@@ -51493,7 +50681,7 @@ function BindingDetails({
51493
50681
  }, [disabled, shape, binding, fields.loading, fieldList, table.data, onChange]);
51494
50682
  const selectShape = (next) => {
51495
50683
  if (next === shape) return;
51496
- const base = {
50684
+ const base2 = {
51497
50685
  kind: "merge_field",
51498
50686
  source: "record",
51499
50687
  semantic_type: next,
@@ -51501,21 +50689,21 @@ function BindingDetails({
51501
50689
  missing: binding.missing,
51502
50690
  override_policy: "shown_locked"
51503
50691
  };
51504
- if (next !== "collection" && binding.record_id) base.record_id = binding.record_id;
51505
- if (next === "value" && binding.field_key) base.field_key = binding.field_key;
50692
+ if (next !== "collection" && binding.record_id) base2.record_id = binding.record_id;
50693
+ if (next === "value" && binding.field_key) base2.field_key = binding.field_key;
51506
50694
  if (next === "collection") {
51507
50695
  const limit = binding.limit ?? defaultRowLimit;
51508
- if (limit) base.limit = limit;
50696
+ if (limit) base2.limit = limit;
51509
50697
  }
51510
50698
  if (next !== "value" && binding.transform) {
51511
- base.transform = {
50699
+ base2.transform = {
51512
50700
  name: "list",
51513
50701
  template: binding.transform.template,
51514
50702
  ...binding.transform.join !== void 0 ? { join: binding.transform.join } : {},
51515
- ...next === "collection" && base.limit !== void 0 ? { max: base.limit } : {}
50703
+ ...next === "collection" && base2.limit !== void 0 ? { max: base2.limit } : {}
51516
50704
  };
51517
50705
  }
51518
- onChange(base);
50706
+ onChange(base2);
51519
50707
  };
51520
50708
  const fieldOptions = fieldList.map((f) => ({ value: f.key, label: fieldName(f) }));
51521
50709
  const template = binding.transform?.template ?? "";
@@ -51829,10 +51017,21 @@ function PreviewForms({ preview, booking }) {
51829
51017
  ] }, p.id)) : null
51830
51018
  ] });
51831
51019
  }
51020
+ var export_QUESTION_OPS = question_exports.QUESTION_OPS;
51021
+ var export_QUESTION_SURFACE = question_exports.QUESTION_SURFACE;
51832
51022
  var export_asRefusal = refusals_exports.asRefusal;
51023
+ var export_askQuestion = question_exports.askQuestion;
51024
+ var export_flatWhere = question_exports.flatWhere;
51025
+ var export_measurableFields = question_exports.measurableFields;
51026
+ var export_newQuestion = question_exports.newQuestion;
51027
+ var export_questionArchive = question_exports.questionArchive;
51028
+ var export_questionFromDefinition = question_exports.questionFromDefinition;
51029
+ var export_questionSave = question_exports.questionSave;
51030
+ var export_questionsOf = question_exports.questionsOf;
51833
51031
  var export_refusal = refusals_exports.refusal;
51834
51032
  var export_refusalFromThrown = refusals_exports.refusalFromThrown;
51835
51033
  var export_refusalOr = refusals_exports.refusalOr;
51034
+ var export_unreadableKeys = question_exports.unreadableKeys;
51836
51035
  export {
51837
51036
  ABSENCE_WORD_LABEL,
51838
51037
  ABSENCE_WORD_VALUES,
@@ -52006,8 +51205,8 @@ export {
52006
51205
  ProvenanceBadge,
52007
51206
  PublicPicturePicker,
52008
51207
  PublicViewPage,
52009
- QUESTION_OPS,
52010
- QUESTION_SURFACE,
51208
+ export_QUESTION_OPS as QUESTION_OPS,
51209
+ export_QUESTION_SURFACE as QUESTION_SURFACE,
52011
51210
  QuestionAnswerView,
52012
51211
  QuestionPanel,
52013
51212
  RECORDS_GRID_ROW_PX,
@@ -52045,8 +51244,8 @@ export {
52045
51244
  STANDARD_VERBS,
52046
51245
  STORE_ANSWERS_THESE,
52047
51246
  STORE_DECIDES_REASON,
52048
- STORE_KEEPS_TIMELINE,
52049
- STORE_KEPT_LAYOUTS,
51247
+ STORE_KEEPS_TIMELINE2 as STORE_KEEPS_TIMELINE,
51248
+ STORE_KEPT_LAYOUTS2 as STORE_KEPT_LAYOUTS,
52050
51249
  STRIP_FEATURE_ROWS,
52051
51250
  SUBSCRIPTION_CADENCES,
52052
51251
  SUBSCRIPTION_CADENCE_LABEL,
@@ -52120,7 +51319,7 @@ export {
52120
51319
  archivedRowLine,
52121
51320
  export_asRefusal as asRefusal,
52122
51321
  askExampleFor,
52123
- askQuestion,
51322
+ export_askQuestion as askQuestion,
52124
51323
  askableFields,
52125
51324
  bindingPlaceholdersFor,
52126
51325
  blockFromSpec,
@@ -52204,7 +51403,7 @@ export {
52204
51403
  fieldTypeLabel,
52205
51404
  fieldsForNewColumns,
52206
51405
  filterTargets,
52207
- flatWhere,
51406
+ export_flatWhere as flatWhere,
52208
51407
  footerOf,
52209
51408
  formDeclareArgs2 as formDeclareArgs,
52210
51409
  formEmbedSnippet2 as formEmbedSnippet,
@@ -52263,10 +51462,10 @@ export {
52263
51462
  looksLikeId,
52264
51463
  machineIdentityIn,
52265
51464
  mayNotRestoreLine,
52266
- measurableFields,
51465
+ export_measurableFields as measurableFields,
52267
51466
  memberName,
52268
51467
  moveRecordValue,
52269
- newQuestion,
51468
+ export_newQuestion as newQuestion,
52270
51469
  nextInWords,
52271
51470
  nextSummaryAt,
52272
51471
  notAChoiceSentence,
@@ -52292,11 +51491,11 @@ export {
52292
51491
  previewLine,
52293
51492
  previewWords,
52294
51493
  publiclyAnswerable,
52295
- questionArchive,
52296
- questionFromDefinition,
51494
+ export_questionArchive as questionArchive,
51495
+ export_questionFromDefinition as questionFromDefinition,
52297
51496
  questionFromWords,
52298
- questionSave,
52299
- questionsOf,
51497
+ export_questionSave as questionSave,
51498
+ export_questionsOf as questionsOf,
52300
51499
  railFromParam,
52301
51500
  readLooks,
52302
51501
  readTableShape,
@@ -52347,7 +51546,7 @@ export {
52347
51546
  starterPageBlocks,
52348
51547
  stepFromAgent,
52349
51548
  storeDecidesRights,
52350
- storeKeepsLayout,
51549
+ storeKeepsLayout2 as storeKeepsLayout,
52351
51550
  storePublishesKind,
52352
51551
  styleFromDecorations,
52353
51552
  submissionStamp2 as submissionStamp,
@@ -52366,7 +51565,7 @@ export {
52366
51565
  tokenFor,
52367
51566
  unknownRailLine,
52368
51567
  unknownViewLine,
52369
- unreadableKeys,
51568
+ export_unreadableKeys as unreadableKeys,
52370
51569
  useAddressDrill,
52371
51570
  useCanShare,
52372
51571
  useChoiceNudge,