@ai-matrx/records-ui 0.113.31 → 0.113.32

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,8 @@ 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";
952
954
  function sortRefusal(f) {
953
955
  if (!computedOnRead(f)) return null;
954
956
  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,23 +963,6 @@ function computedOnRead(f) {
961
963
  const kind = String(editorKindFor(f));
962
964
  return (f.type === "formula" || kind === "formula" || kind === "lookup" || kind === "rollup") && String(f.compute_on ?? "read") === "read";
963
965
  }
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
966
  function containsPattern(text) {
982
967
  return `(?i)${text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`;
983
968
  }
@@ -1076,12 +1061,12 @@ function dayWindow(day, holdsDays) {
1076
1061
  const ymd = (t) => `${t.getUTCFullYear()}-${String(t.getUTCMonth() + 1).padStart(2, "0")}-${String(t.getUTCDate()).padStart(2, "0")}`;
1077
1062
  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
1063
  }
1079
- function storeQuestion(fields, base, columnFilters, now = /* @__PURE__ */ new Date()) {
1064
+ function storeQuestion(fields, base2, columnFilters, now = /* @__PURE__ */ new Date()) {
1080
1065
  const refused = [];
1081
1066
  const flat = {};
1082
1067
  const rules = [];
1083
- if (base && isRuleFilter(base)) rules.push(base);
1084
- else if (base) Object.assign(flat, base);
1068
+ if (base2 && isRuleFilter(base2)) rules.push(base2);
1069
+ else if (base2) Object.assign(flat, base2);
1085
1070
  for (const [key, value] of Object.entries(columnFilters)) {
1086
1071
  if (!value) continue;
1087
1072
  const f = fields.find((candidate) => candidate.key === key);
@@ -1622,32 +1607,7 @@ function useLabelWait(field2) {
1622
1607
  }
1623
1608
 
1624
1609
  // 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
- }
1610
+ import { defaultSortOf } from "@ai-matrx/records/first-page";
1651
1611
  var ROW_HEIGHT_PX = {
1652
1612
  compact: 28,
1653
1613
  normal: void 0,
@@ -2005,7 +1965,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
2005
1965
  const [to, setTo] = useState4(null);
2006
1966
  const [preview, setPreview] = useState4(null);
2007
1967
  const [asking, setAsking] = useState4(false);
2008
- const [refusal4, setRefusal] = useState4(null);
1968
+ const [refusal3, setRefusal] = useState4(null);
2009
1969
  const [busy, setBusy] = useState4(false);
2010
1970
  const [said2, setSaid] = useState4(null);
2011
1971
  const name = fieldName(field2);
@@ -2103,7 +2063,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
2103
2063
  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
2064
  preview.partial ? ". Counted over the first 1,000 different values." : "."
2105
2065
  ] }) : null,
2106
- refusal4 ? /* @__PURE__ */ jsx6(RefusalNotice, { error: refusal4 }) : null,
2066
+ refusal3 ? /* @__PURE__ */ jsx6(RefusalNotice, { error: refusal3 }) : null,
2107
2067
  said2 ? /* @__PURE__ */ jsx6("p", { role: "status", className: "text-[11px] text-muted-foreground", "data-records-retype-done": "", children: said2 }) : null
2108
2068
  ] });
2109
2069
  }
@@ -2879,10 +2839,10 @@ function TableDetails({
2879
2839
  if (slots.details.current === slot) slots.details.current = null;
2880
2840
  };
2881
2841
  }, [slots]);
2882
- const write = async (patch, base) => {
2842
+ const write = async (patch, base2) => {
2883
2843
  setBusy(true);
2884
2844
  setRefused(null);
2885
- const written = await (0, writeOnTheWinningVersion_exports.updateOnTheWinningVersion)(client, tableId, patch, await (0, recordVersions_exports.readTableVersionNow)(client, tableId), base);
2845
+ const written = await (0, writeOnTheWinningVersion_exports.updateOnTheWinningVersion)(client, tableId, patch, await (0, recordVersions_exports.readTableVersionNow)(client, tableId), base2);
2886
2846
  setBusy(false);
2887
2847
  if (!written.ok) {
2888
2848
  setRefused(refusalSentence(written.error));
@@ -3981,13 +3941,13 @@ function styleFromDecorations(decorations, fields) {
3981
3941
  return style;
3982
3942
  }
3983
3943
  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;
3944
+ const base2 = styleFromDecorations(decorations, fields);
3945
+ if (!viewStyle) return base2;
3946
+ const colorBy = viewStyle.colorBy ?? base2.colorBy;
3947
+ const rules = viewStyle.rules ?? base2.rules;
3948
+ const rows = viewStyle.rows ?? base2.rows;
3949
+ const columns = viewStyle.columns ?? base2.columns;
3950
+ const cells = viewStyle.cells ?? base2.cells;
3991
3951
  return {
3992
3952
  version: 1,
3993
3953
  ...colorBy !== void 0 ? { colorBy } : {},
@@ -4406,7 +4366,7 @@ function RelationPicker({ field: field2, value, onChange, disabled, id, classNam
4406
4366
  const client = useOptionalRecordsClient3();
4407
4367
  const [rows, setRows] = useState12(null);
4408
4368
  const [words2, setWords] = useState12({});
4409
- const [refusal4, setRefusal] = useState12(null);
4369
+ const [refusal3, setRefusal] = useState12(null);
4410
4370
  const [search, setSearch] = useState12("");
4411
4371
  const [open, setOpenState] = useState12(autoOpen === true);
4412
4372
  const onCloseRef = useRef7(onClose);
@@ -4590,8 +4550,8 @@ function RelationPicker({ field: field2, value, onChange, disabled, id, classNam
4590
4550
  })),
4591
4551
  onPick: toggle,
4592
4552
  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,
4553
+ refusal3 ? /* @__PURE__ */ jsx15(RefusalLine, { error: refusal3, className: "p-2" }) : null,
4554
+ !rows && !refusal3 ? /* @__PURE__ */ jsx15("p", { className: "p-2 text-xs text-muted-foreground", children: "Reading\u2026" }) : null,
4595
4555
  full ? /* @__PURE__ */ jsxs13("p", { className: "p-2 text-xs text-muted-foreground", children: [
4596
4556
  fieldName(field2),
4597
4557
  " can point at ",
@@ -5029,500 +4989,35 @@ import { Badge as Badge5, cn as cn19 } from "@ai-matrx/design-system";
5029
4989
  import { createContext as createContext4, useContext as useContext4 } from "react";
5030
4990
 
5031
4991
  // 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;
4992
+ import { bindFirstPageCodec } from "@ai-matrx/records/first-page";
5049
4993
 
5050
4994
  // 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"
4995
+ import * as base from "@ai-matrx/records/views";
4996
+ import {
4997
+ STORE_KEEPS_TIMELINE,
4998
+ STORE_KEPT_LAYOUTS,
4999
+ VIEW_KEYS,
5000
+ storeKeepsLayout,
5001
+ viewKeysFor,
5002
+ viewSettingsFor
5003
+ } from "@ai-matrx/records/views";
5004
+ var gridPresentationCodec = {
5005
+ parse: parseGridPresentation,
5006
+ isEmpty: presentationIsEmpty,
5007
+ toDocument: (presentation) => JSON.parse(presentationDocument(presentation))
5507
5008
  };
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
- }
5009
+ var boundViews = base.bindViewCodec(gridPresentationCodec);
5010
+ var { viewSettings, viewSettingsPatch } = boundViews;
5523
5011
 
5524
5012
  // src/firstPage.ts
5525
- var EMBEDDED_PAGE_SIZE = 50;
5013
+ import {
5014
+ EMBEDDED_PAGE_SIZE,
5015
+ TABLE_PAGE_SIZE,
5016
+ firstGridPageArgs,
5017
+ serverRowsOf,
5018
+ viewFilterOf
5019
+ } from "@ai-matrx/records/first-page";
5020
+ var { firstGridPageRequest, askTablePageSeed } = bindFirstPageCodec(gridPresentationCodec);
5526
5021
 
5527
5022
  // src/embeddedLook.tsx
5528
5023
  var EMBEDDED_LOOK = { blankEmpty: true, choiceDot: true, plainRelation: true };
@@ -6777,7 +6272,7 @@ function RetiredValues({
6777
6272
  }) {
6778
6273
  const client = useRecordsClient7();
6779
6274
  const [busy, setBusy] = useState20(null);
6780
- const [refusal4, setRefusal] = useState20(null);
6275
+ const [refusal3, setRefusal] = useState20(null);
6781
6276
  const [said2, setSaid] = useState20(null);
6782
6277
  const [missing, setMissing] = useState20(null);
6783
6278
  const kept = retiredValuesOf(document2);
@@ -6826,7 +6321,7 @@ function RetiredValues({
6826
6321
  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
6322
  ] }),
6828
6323
  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,
6324
+ refusal3?.key === id ? /* @__PURE__ */ jsx26(RefusalNotice, { error: refusal3.error }) : null,
6830
6325
  missing === id ? /* @__PURE__ */ jsxs23("p", { className: "text-[11px] text-muted-foreground", children: [
6831
6326
  "No earlier version of ",
6832
6327
  name,
@@ -7681,7 +7176,7 @@ function ruleWords(rules) {
7681
7176
  function rulesChanged(was, now) {
7682
7177
  return ruleWords(was) !== ruleWords(now);
7683
7178
  }
7684
- function holdsNumbers2(field2) {
7179
+ function holdsNumbers3(field2) {
7685
7180
  return field2.type === "range";
7686
7181
  }
7687
7182
  function groupValue(value, numbers) {
@@ -7692,7 +7187,7 @@ function groupValue(value, numbers) {
7692
7187
  function FieldRulePreview({ field: field2, tableId, rules }) {
7693
7188
  const client = useRecordsClient9();
7694
7189
  const [preview, setPreview] = useState23(null);
7695
- const [refusal4, setRefusal] = useState23(null);
7190
+ const [refusal3, setRefusal] = useState23(null);
7696
7191
  const key = useMemo11(() => ruleWords(rules), [rules]);
7697
7192
  const latest = useRef13(rules);
7698
7193
  latest.current = rules;
@@ -7708,7 +7203,7 @@ function FieldRulePreview({ field: field2, tableId, rules }) {
7708
7203
  setRefusal(answer.error);
7709
7204
  return;
7710
7205
  }
7711
- const numbers = holdsNumbers2(field2);
7206
+ const numbers = holdsNumbers3(field2);
7712
7207
  const groups = answer.data.map((row) => ({ value: groupValue(row.groups[field2.key] ?? null, numbers), count: row.row_count }));
7713
7208
  setPreview(previewRuleChange(latest.current, groups, answer.data.length >= PREVIEW_GROUPS2));
7714
7209
  });
@@ -7718,7 +7213,7 @@ function FieldRulePreview({ field: field2, tableId, rules }) {
7718
7213
  clearTimeout(timer);
7719
7214
  };
7720
7215
  }, [client, tableId, field2.key, key]);
7721
- if (refusal4) return /* @__PURE__ */ jsx31(RefusalNotice, { error: refusal4 });
7216
+ if (refusal3) return /* @__PURE__ */ jsx31(RefusalNotice, { error: refusal3 });
7722
7217
  if (!preview) {
7723
7218
  return /* @__PURE__ */ jsxs27("p", { className: "text-[11px] text-muted-foreground", "data-records-rule-preview": "counting", children: [
7724
7219
  "Counting ",
@@ -7779,9 +7274,9 @@ function choiceDisplayPatch(field2, rows) {
7779
7274
  }
7780
7275
  function lookFollowsRenames(field2, look, renames) {
7781
7276
  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;
7277
+ const base2 = look ?? displayFormatOf(field2);
7278
+ const choices = base2 && Array.isArray(base2.options["choices"]) ? base2.options["choices"] : null;
7279
+ if (!base2 || !choices) return look;
7785
7280
  let moved = false;
7786
7281
  const next = choices.map((c) => {
7787
7282
  const was = typeof c["value"] === "string" ? c["value"] : null;
@@ -7791,11 +7286,11 @@ function lookFollowsRenames(field2, look, renames) {
7791
7286
  return { ...c, value: now };
7792
7287
  });
7793
7288
  if (!moved) return look;
7794
- return { id: base.id, options: { ...base.options, choices: next } };
7289
+ return { id: base2.id, options: { ...base2.options, choices: next } };
7795
7290
  }
7796
7291
  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) => {
7292
+ const base2 = startingChoiceColors(field2, start.map((r) => r.words.trim()).filter((w) => w !== ""));
7293
+ const colorRows = base2.map((row) => {
7799
7294
  const was = start.find((r) => choiceWord(r.words) === choiceWord(row.value));
7800
7295
  const now = was?.id ? rows.find((r) => r.id === was.id) : void 0;
7801
7296
  return now ? { value: row.value, color: now.color ?? null } : row;
@@ -8248,9 +7743,9 @@ function storageOf(field2) {
8248
7743
  }
8249
7744
  }
8250
7745
  function formatMenu(field2) {
8251
- const base = storageOf(field2);
8252
- if (base === null) return { groups: [], otherKinds: [] };
8253
- if (base === "formula") {
7746
+ const base2 = storageOf(field2);
7747
+ if (base2 === null) return { groups: [], otherKinds: [] };
7748
+ if (base2 === "formula") {
8254
7749
  const groups2 = [];
8255
7750
  for (const def of FIELD_FORMAT_LIST) {
8256
7751
  if (neverALook(def) || KIND_WORD[def.id] || def.id === "boolean") continue;
@@ -8260,7 +7755,7 @@ function formatMenu(field2) {
8260
7755
  }
8261
7756
  return { groups: groups2, otherKinds: [] };
8262
7757
  }
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);
7758
+ 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
7759
  const own3 = new Set(groups.flatMap((g) => g.formats.map((d) => d.id)));
8265
7760
  const otherKinds = [];
8266
7761
  for (const def of FIELD_FORMAT_LIST) {
@@ -10832,7 +10327,7 @@ function FieldControl({ field: field2, value, onChange, disabled, id, autoOpen,
10832
10327
  }
10833
10328
  function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
10834
10329
  const [text, setText] = useState32(() => openingText(field2, value));
10835
- const [refusal4, setRefusal] = useState32(null);
10330
+ const [refusal3, setRefusal] = useState32(null);
10836
10331
  const [why, setWhy] = useState32(void 0);
10837
10332
  const sent = useRef18(value);
10838
10333
  useEffect22(() => {
@@ -10863,11 +10358,11 @@ function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
10863
10358
  value: text,
10864
10359
  disabled,
10865
10360
  autoComplete: "off",
10866
- "aria-invalid": refusal4 ? true : void 0,
10361
+ "aria-invalid": refusal3 ? true : void 0,
10867
10362
  placeholder: helper ? typedDatePlaceholder(helper) : void 0,
10868
10363
  onChange: (e) => retype(e.target.value),
10869
10364
  onBlur: () => {
10870
- if (!refusal4) return;
10365
+ if (!refusal3) return;
10871
10366
  setText(openingText(field2, sent.current));
10872
10367
  setRefusal(null);
10873
10368
  }
@@ -10875,7 +10370,7 @@ function TypedWordsControl({ field: field2, value, onChange, disabled, id }) {
10875
10370
  ),
10876
10371
  helper && !disabled ? /* @__PURE__ */ jsx42(TypedDateHelper, { kind: helper, text, onText: retype, label: fieldName(field2) }) : null
10877
10372
  ] }),
10878
- refusal4 ? /* @__PURE__ */ jsx42(FloatingRefusal, { text: refusal4, why }) : null
10373
+ refusal3 ? /* @__PURE__ */ jsx42(FloatingRefusal, { text: refusal3, why }) : null
10879
10374
  ] });
10880
10375
  }
10881
10376
  function typedDatePlaceholder(helper) {
@@ -10979,7 +10474,7 @@ function inTheStoresOrder(options) {
10979
10474
  function OptionControl({ field: field2, value, onChange, disabled, id, autoOpen, onClose, onCancel, addsChoices, initialSearch, asForm, onChosen }) {
10980
10475
  const client = useOptionalRecordsClient10();
10981
10476
  const [options, setOptions] = useState32(null);
10982
- const [refusal4, setRefusal] = useState32(null);
10477
+ const [refusal3, setRefusal] = useState32(null);
10983
10478
  const [reread, setReread] = useState32(0);
10984
10479
  useEffect22(() => {
10985
10480
  if (!client) return;
@@ -11011,8 +10506,8 @@ function OptionControl({ field: field2, value, onChange, disabled, id, autoOpen,
11011
10506
  /* @__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
10507
  ] });
11013
10508
  }
11014
- if (refusal4)
11015
- return /* @__PURE__ */ jsx42("div", { id, children: /* @__PURE__ */ jsx42(RefusalLine, { error: refusal4 }) });
10509
+ if (refusal3)
10510
+ return /* @__PURE__ */ jsx42("div", { id, children: /* @__PURE__ */ jsx42(RefusalLine, { error: refusal3 }) });
11016
10511
  if (!options) return /* @__PURE__ */ jsx42("p", { id, className: "text-xs text-muted-foreground", children: "Reading this field's choices\u2026" });
11017
10512
  if (asForm && options.length > 0) {
11018
10513
  const titled = (option) => recordName(option.data, null, "Unnamed choice");
@@ -11751,7 +11246,7 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11751
11246
  startedFrom.current = null;
11752
11247
  }, []);
11753
11248
  const writeCellNow = useCallback10(
11754
- async (rowId, key, value, base, resent = false) => {
11249
+ async (rowId, key, value, base2, resent = false) => {
11755
11250
  const id = cellKey(rowId, key);
11756
11251
  const adding = isChoiceAddition(value) ? value : null;
11757
11252
  const shown4 = adding ? adding.value : value;
@@ -11768,7 +11263,7 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11768
11263
  let version = await versionOf(source, versions.current, versionReads.current, rowId);
11769
11264
  const drawnNow = await source.seen(rowId);
11770
11265
  const storedNow = rowsNow.current.find((r) => r.id === rowId)?.document?.[key];
11771
- if (drawnNow !== null && (version === null || drawnNow > version) && sameValue(storedNow, base)) {
11266
+ if (drawnNow !== null && (version === null || drawnNow > version) && sameValue(storedNow, base2)) {
11772
11267
  version = drawnNow;
11773
11268
  rememberVersion(versions.current, rowId, drawnNow);
11774
11269
  }
@@ -11797,13 +11292,13 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11797
11292
  if (written.ok) {
11798
11293
  rememberVersion(versions.current, rowId, written.data);
11799
11294
  source.wrote(rowId, written.data);
11800
- settling.current.set(id, base);
11801
- writtenRef.current?.({ rowId, key, before: base, after: shown4, version: written.data });
11295
+ settling.current.set(id, base2);
11296
+ writtenRef.current?.({ rowId, key, before: base2, after: shown4, version: written.data });
11802
11297
  afterWrite();
11803
11298
  return;
11804
11299
  }
11805
11300
  if (isUnsentWrite(written.error)) {
11806
- setRefusals((held) => ({ ...held, [id]: { error: written.error, conflict: null, attempted: value, unsent: true, base } }));
11301
+ setRefusals((held) => ({ ...held, [id]: { error: written.error, conflict: null, attempted: value, unsent: true, base: base2 } }));
11807
11302
  return;
11808
11303
  }
11809
11304
  setOptimistic((held) => {
@@ -11815,8 +11310,8 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11815
11310
  if (written.error.code === "stale_write") {
11816
11311
  if (conflict) rememberVersion(versions.current, rowId, conflict.current_version);
11817
11312
  else versions.current.delete(rowId);
11818
- if (conflict && !resent && sameValue(conflict.contested_fields[key], base)) {
11819
- await writeCellNow(rowId, key, value, base, true);
11313
+ if (conflict && !resent && sameValue(conflict.contested_fields[key], base2)) {
11314
+ await writeCellNow(rowId, key, value, base2, true);
11820
11315
  return;
11821
11316
  }
11822
11317
  }
@@ -11833,9 +11328,9 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11833
11328
  [client, reload, afterWrite, source]
11834
11329
  );
11835
11330
  const writeCell = useCallback10(
11836
- (rowId, key, value, base) => {
11331
+ (rowId, key, value, base2) => {
11837
11332
  const behind = queues.current.get(rowId) ?? Promise.resolve();
11838
- const next = behind.then(() => writeCellNow(rowId, key, value, base));
11333
+ const next = behind.then(() => writeCellNow(rowId, key, value, base2));
11839
11334
  queues.current.set(
11840
11335
  rowId,
11841
11336
  next.then(
@@ -12188,7 +11683,7 @@ function GridCell({
12188
11683
  };
12189
11684
  const value = editing ? editing.valueFor(row, field2) : row.document?.[field2.key];
12190
11685
  const state = editing ? editing.stateOf(row.id, field2.key) : null;
12191
- const refusal4 = editing ? editing.refusalOf(row.id, field2.key) : null;
11686
+ const refusal3 = editing ? editing.refusalOf(row.id, field2.key) : null;
12192
11687
  const editable = Boolean(editing) && canWrite && fieldIsEditable(field2);
12193
11688
  if (open && editing) {
12194
11689
  return /* @__PURE__ */ jsxs39("span", { "data-records-open-cell": "", className: "relative block w-full min-w-0", children: [
@@ -12225,10 +11720,10 @@ function GridCell({
12225
11720
  // state they are in, so only Discard is offered. It is INSIDE the open
12226
11721
  // cell, so pressing Discard is not "focus left the cell" — which would
12227
11722
  // commit the refused value one more time on its way out.
12228
- refusal4 && !refusal4.conflict ? /* @__PURE__ */ jsx44(
11723
+ refusal3 && !refusal3.conflict ? /* @__PURE__ */ jsx44(
12229
11724
  RefusalNotice,
12230
11725
  {
12231
- error: refusal4.error,
11726
+ error: refusal3.error,
12232
11727
  className: "py-1.5 text-left",
12233
11728
  onDiscard: () => editing.discard(row.id, field2.key)
12234
11729
  }
@@ -12253,14 +11748,14 @@ function GridCell({
12253
11748
  }
12254
11749
  ),
12255
11750
  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
11751
+ refusal3 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: false }) : null
12257
11752
  ] });
12258
11753
  }
12259
11754
  if (editable && format?.id === "rating") {
12260
11755
  return /* @__PURE__ */ jsxs39("span", { "data-matrx-cell-control": "", className: "relative flex h-full w-full flex-wrap items-center gap-1.5", children: [
12261
11756
  /* @__PURE__ */ jsx44(FormattedValue, { value, format, onRate: (next) => editing?.setCell(row.id, field2.key, next), selectFirst: true }),
12262
11757
  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
11758
+ refusal3 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: false }) : null
12264
11759
  ] });
12265
11760
  }
12266
11761
  const openThisCell = (event) => {
@@ -12382,40 +11877,40 @@ function GridCell({
12382
11877
  ) : null
12383
11878
  ] }),
12384
11879
  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
11880
+ refusal3 ? /* @__PURE__ */ jsx44(CellRefusalNotice, { refusal: refusal3, field: field2, row, editing, typed: true }) : null
12386
11881
  ]
12387
11882
  }
12388
11883
  )
12389
11884
  );
12390
11885
  }
12391
11886
  function CellRefusalNotice({
12392
- refusal: refusal4,
11887
+ refusal: refusal3,
12393
11888
  field: field2,
12394
11889
  row,
12395
11890
  editing,
12396
11891
  typed: typed2
12397
11892
  }) {
12398
11893
  const [open, setOpen] = useState34(true);
12399
- const line = refusal4.unsent ? UNSENT_LINE : refusalLineForAPerson(refusal4.error);
12400
- const notice = refusal4.unsent ? (
11894
+ const line = refusal3.unsent ? UNSENT_LINE : refusalLineForAPerson(refusal3.error);
11895
+ const notice = refusal3.unsent ? (
12401
11896
  // NOT SENT, NOT REFUSED: what was typed is still in the cell; it goes again once online.
12402
11897
  /* @__PURE__ */ jsxs39("div", { className: "flex flex-col gap-1.5 px-3 py-2 text-xs", "data-records-cell-unsent": "", children: [
12403
11898
  /* @__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) }),
11899
+ /* @__PURE__ */ jsx44("span", { className: "max-w-[16rem] truncate text-muted-foreground", title: valueInALine(refusal3.attempted), children: valueInALine(refusal3.attempted) }),
12405
11900
  /* @__PURE__ */ jsxs39("span", { className: "flex flex-wrap gap-1", children: [
12406
11901
  /* @__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
11902
  /* @__PURE__ */ jsx44(Button19, { size: "sm", variant: "ghost", className: "h-6", "data-records-cell-discard": "", onClick: () => editing?.discard(row.id, field2.key), children: "Discard" })
12408
11903
  ] })
12409
11904
  ] })
12410
- ) : refusal4.conflict ? /* @__PURE__ */ jsx44(
11905
+ ) : refusal3.conflict ? /* @__PURE__ */ jsx44(
12411
11906
  RefusalNotice,
12412
11907
  {
12413
- error: refusal4.error,
11908
+ error: refusal3.error,
12414
11909
  className: "py-1.5 text-left",
12415
11910
  actions: /* @__PURE__ */ jsxs39("span", { className: "flex flex-col gap-1", "data-refusal-conflict": "", children: [
12416
11911
  /* @__PURE__ */ jsxs39("span", { className: "text-[11px]", children: [
12417
11912
  "Theirs: ",
12418
- /* @__PURE__ */ jsx44("strong", { children: formatTheirs(refusal4.conflict, field2.key) })
11913
+ /* @__PURE__ */ jsx44("strong", { children: formatTheirs(refusal3.conflict, field2.key) })
12419
11914
  ] }),
12420
11915
  /* @__PURE__ */ jsxs39("span", { className: "flex flex-wrap gap-1", children: [
12421
11916
  /* @__PURE__ */ jsx44(Button19, { size: "sm", variant: "outline", onClick: () => editing?.retry(row.id, field2.key), children: "Try again" }),
@@ -12426,7 +11921,7 @@ function CellRefusalNotice({
12426
11921
  ) : /* @__PURE__ */ jsx44(
12427
11922
  RefusalNotice,
12428
11923
  {
12429
- error: refusal4.error,
11924
+ error: refusal3.error,
12430
11925
  className: "py-1.5 text-left",
12431
11926
  ...typed2 ? { onKeepEditing: () => editing?.keepEditing(row.id, field2.key) } : {},
12432
11927
  onDiscard: () => editing?.discard(row.id, field2.key)
@@ -12440,8 +11935,8 @@ function CellRefusalNotice({
12440
11935
  "data-records-cell-refusal-line": "",
12441
11936
  title: line,
12442
11937
  "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"}`,
11938
+ "data-records-cell-unsent-mark": refusal3.unsent ? "" : void 0,
11939
+ 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
11940
  children: "!"
12446
11941
  }
12447
11942
  ) }),
@@ -13090,7 +12585,7 @@ function MergeRecordDialog({ tableId, record, open, onOpenChange, onMerged }) {
13090
12585
  const records = useRecords3(tableId, { pageSize: 200 });
13091
12586
  const [other, setOther] = useState37(null);
13092
12587
  const [busy, setBusy] = useState37(false);
13093
- const [refusal4, setRefusal] = useState37(null);
12588
+ const [refusal3, setRefusal] = useState37(null);
13094
12589
  const options = useMemo15(
13095
12590
  () => (records.data?.rows ?? []).filter((row) => row.id !== record.id).map((row) => ({ value: row.id, label: rowNameIn(table.data ?? null, row) })),
13096
12591
  [records.data, record.id, table.data]
@@ -13160,7 +12655,7 @@ function MergeRecordDialog({ tableId, record, open, onOpenChange, onMerged }) {
13160
12655
  ariaLabel: "Record to merge"
13161
12656
  }
13162
12657
  ),
13163
- refusal4 ? /* @__PURE__ */ jsx47(RefusalNotice, { error: refusal4 }) : null,
12658
+ refusal3 ? /* @__PURE__ */ jsx47(RefusalNotice, { error: refusal3 }) : null,
13164
12659
  /* @__PURE__ */ jsxs42(DialogFooter, { children: [
13165
12660
  /* @__PURE__ */ jsx47(Button21, { variant: "ghost", size: "sm", onClick: () => close(false), disabled: busy, children: "Cancel" }),
13166
12661
  /* @__PURE__ */ jsx47(Button21, { size: "sm", onClick: () => void merge(), disabled: !other || busy, "data-records-merge-go": "", children: busy ? "Merging\u2026" : "Merge" })
@@ -13344,7 +12839,7 @@ function useGridColours(args) {
13344
12839
  [client, tableId, decorations, notify]
13345
12840
  );
13346
12841
  const idOf = useCallback12((key) => fields.find((f) => f.key === key), [fields]);
13347
- const refusal4 = mayColour ? void 0 : whyNot;
12842
+ const refusal3 = mayColour ? void 0 : whyNot;
13348
12843
  const headerItem = useCallback12(
13349
12844
  (columnKey) => {
13350
12845
  if (!enabled) return null;
@@ -13359,7 +12854,7 @@ function useGridColours(args) {
13359
12854
  id: "col-colour",
13360
12855
  label: "Colour by\u2026",
13361
12856
  icon: "palette",
13362
- disabledReason: refusal4,
12857
+ disabledReason: refusal3,
13363
12858
  submenu: [
13364
12859
  byThis ? {
13365
12860
  id: "col-colour-off",
@@ -13395,7 +12890,7 @@ function useGridColours(args) {
13395
12890
  ]
13396
12891
  };
13397
12892
  },
13398
- [enabled, idOf, decorations.data, refusal4, write]
12893
+ [enabled, idOf, decorations.data, refusal3, write]
13399
12894
  );
13400
12895
  const cellItem = useCallback12(
13401
12896
  (rowId, columnKey) => {
@@ -13407,7 +12902,7 @@ function useGridColours(args) {
13407
12902
  id: "cell-highlight",
13408
12903
  label: "Highlight cell",
13409
12904
  icon: "palette",
13410
- disabledReason: refusal4,
12905
+ disabledReason: refusal3,
13411
12906
  submenu: swatches(
13412
12907
  "cell-highlight",
13413
12908
  current,
@@ -13415,7 +12910,7 @@ function useGridColours(args) {
13415
12910
  )
13416
12911
  };
13417
12912
  },
13418
- [enabled, idOf, decorations.data, refusal4, write]
12913
+ [enabled, idOf, decorations.data, refusal3, write]
13419
12914
  );
13420
12915
  const cellsItem = useCallback12(
13421
12916
  (cells) => {
@@ -13425,7 +12920,7 @@ function useGridColours(args) {
13425
12920
  id: "sel-highlight",
13426
12921
  label: `Highlight ${n} cells`,
13427
12922
  icon: "palette",
13428
- disabledReason: refusal4,
12923
+ disabledReason: refusal3,
13429
12924
  submenu: swatches("sel-highlight", void 0, (color) => {
13430
12925
  void (async () => {
13431
12926
  let kept = 0;
@@ -13445,7 +12940,7 @@ function useGridColours(args) {
13445
12940
  })
13446
12941
  };
13447
12942
  },
13448
- [enabled, idOf, refusal4, client, tableId, decorations, notify]
12943
+ [enabled, idOf, refusal3, client, tableId, decorations, notify]
13449
12944
  );
13450
12945
  const rowItem = useCallback12(
13451
12946
  (rowId) => {
@@ -13455,7 +12950,7 @@ function useGridColours(args) {
13455
12950
  id: "row-highlight",
13456
12951
  label: "Highlight row",
13457
12952
  icon: "palette",
13458
- disabledReason: refusal4,
12953
+ disabledReason: refusal3,
13459
12954
  submenu: swatches(
13460
12955
  "row-highlight",
13461
12956
  current,
@@ -13463,7 +12958,7 @@ function useGridColours(args) {
13463
12958
  )
13464
12959
  };
13465
12960
  },
13466
- [enabled, decorations.data, refusal4, write]
12961
+ [enabled, decorations.data, refusal3, write]
13467
12962
  );
13468
12963
  const dialogs = enabled ? /* @__PURE__ */ jsx48(
13469
12964
  ColourRulesDialog,
@@ -14235,7 +13730,7 @@ function stepOf(step2, original) {
14235
13730
  return { field: field2, set: "value", value: step2.value };
14236
13731
  }
14237
13732
  function actionOf(draft, original) {
14238
- const base = {
13733
+ const base2 = {
14239
13734
  ...draft.id ? { id: draft.id } : {},
14240
13735
  name: draft.name.trim(),
14241
13736
  kind: draft.kind,
@@ -14243,9 +13738,9 @@ function actionOf(draft, original) {
14243
13738
  ...draft.color ? { color: draft.color } : {},
14244
13739
  ...draft.icon ? { icon: draft.icon } : {}
14245
13740
  };
14246
- if (draft.kind === "agent") return { ...base, prompt: draft.prompt };
13741
+ if (draft.kind === "agent") return { ...base2, prompt: draft.prompt };
14247
13742
  return {
14248
- ...base,
13743
+ ...base2,
14249
13744
  steps: draft.steps.map((s, i) => stepOf(s, original?.steps?.[i]))
14250
13745
  };
14251
13746
  }
@@ -15511,19 +15006,19 @@ function planPastedBlock(args) {
15511
15006
  accepted[key] = judged.value;
15512
15007
  }
15513
15008
  const predicted = predictValueRefusals(args.fields, accepted);
15514
- for (const refusal4 of predicted) {
15515
- const key = refusal4.field_key;
15009
+ for (const refusal3 of predicted) {
15010
+ const key = refusal3.field_key;
15516
15011
  if (key === void 0) continue;
15517
15012
  const cell2 = built.find((b) => b.key === key && b.refusal === null);
15518
15013
  if (!cell2) continue;
15519
- cell2.refusal = refusal4.message;
15014
+ cell2.refusal = refusal3.message;
15520
15015
  cell2.value = null;
15521
15016
  delete accepted[key];
15522
15017
  refusals.push({
15523
15018
  fromLine,
15524
15019
  column: fieldName(byKey.get(key) ?? { key }),
15525
15020
  raw: cell2.raw,
15526
- why: refusal4.message
15021
+ why: refusal3.message
15527
15022
  });
15528
15023
  }
15529
15024
  cells += Object.keys(accepted).length;
@@ -15727,8 +15222,8 @@ function useMergedGridControls(args) {
15727
15222
  setHeld(null);
15728
15223
  }, [keptKey]);
15729
15224
  const order = useMemo21(() => {
15730
- const base = held?.order ?? columnsInKeptOrder(fieldKeys, keptOrder);
15731
- const known = columnsInKeptOrder(fieldKeys, base);
15225
+ const base2 = held?.order ?? columnsInKeptOrder(fieldKeys, keptOrder);
15226
+ const known = columnsInKeptOrder(fieldKeys, base2);
15732
15227
  if (frozenKeys.size === 0) return known;
15733
15228
  return [...known.filter((k) => frozenKeys.has(k)), ...known.filter((k) => !frozenKeys.has(k))];
15734
15229
  }, [held, fieldKeys, keptOrder, frozenKeys]);
@@ -15784,10 +15279,10 @@ function useMergedGridControls(args) {
15784
15279
  return;
15785
15280
  }
15786
15281
  let cancelled = false;
15787
- const [keys, filters, base, searched] = JSON.parse(countQuestionKey);
15282
+ const [keys, filters, base2, searched] = JSON.parse(countQuestionKey);
15788
15283
  for (const key of keys) {
15789
15284
  const { [key]: _own, ...others } = filters;
15790
- const asked2 = storeQuestion(fieldsRef.current, base ?? void 0, others);
15285
+ const asked2 = storeQuestion(fieldsRef.current, base2 ?? void 0, others);
15791
15286
  void (0, askOnce_exports.askOnce)(
15792
15287
  client,
15793
15288
  `value_counts:${tableId}:${key}:${searched}:${JSON.stringify(asked2.filter ?? null)}`,
@@ -16403,9 +15898,9 @@ function readersThrough(fields, key) {
16403
15898
  });
16404
15899
  }
16405
15900
  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}`;
15901
+ 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.`;
15902
+ if (readers.length === 0) return base2;
15903
+ return `${readersSentence(readers.length, tableName2)} ${base2}`;
16409
15904
  }
16410
15905
  function afterMenuLayerCloses(next) {
16411
15906
  if (typeof window === "undefined") return next();
@@ -17744,8 +17239,8 @@ function useDrillDefinition(source) {
17744
17239
  }, [client, key]);
17745
17240
  return state.key === key ? { def: state.def, error: state.error } : { def: null, error: null };
17746
17241
  }
17747
- function drillWhere(base, trail, booleans) {
17748
- const where = { ...base ?? {} };
17242
+ function drillWhere(base2, trail, booleans) {
17243
+ const where = { ...base2 ?? {} };
17749
17244
  for (const w of trail) {
17750
17245
  const { key, grain } = parseDimensionRef2(w.dim);
17751
17246
  if (grain) where[w.dim] = w.value;
@@ -17924,10 +17419,10 @@ function useDrill(args) {
17924
17419
  const booleans = useMemo25(() => new Set((def?.dimensions ?? []).filter((d) => d.kind === "boolean").map((d) => d.key)), [def]);
17925
17420
  const baseKey = JSON.stringify(args.base ?? []);
17926
17421
  const filter = useMemo25(() => {
17927
- const base = JSON.parse(baseKey);
17928
- if (base.length === 0) return args.filter;
17422
+ const base2 = JSON.parse(baseKey);
17423
+ if (base2.length === 0) return args.filter;
17929
17424
  const out = { ...args.filter ?? {} };
17930
- for (const b of base) out[b.key] = b.value;
17425
+ for (const b of base2) out[b.key] = b.value;
17931
17426
  return out;
17932
17427
  }, [args.filter, baseKey]);
17933
17428
  const where = useMemo25(() => drillWhere(filter, question.where, booleans), [filter, question.where, booleans]);
@@ -18056,17 +17551,17 @@ function trailClause(fields, w) {
18056
17551
  }
18057
17552
  return { key, value: w.value, field: field2 };
18058
17553
  }
18059
- function filterWithTrail(fields, base, trail) {
18060
- if (trail.length === 0) return base;
18061
- if (!base || !isRuleFilter2(base)) {
18062
- const flat = { ...base ?? {} };
17554
+ function filterWithTrail(fields, base2, trail) {
17555
+ if (trail.length === 0) return base2;
17556
+ if (!base2 || !isRuleFilter2(base2)) {
17557
+ const flat = { ...base2 ?? {} };
18063
17558
  for (const w of trail) {
18064
17559
  const clause = trailClause(fields, w);
18065
17560
  flat[clause.key] = clause.value;
18066
17561
  }
18067
17562
  return flat;
18068
17563
  }
18069
- const args = [base];
17564
+ const args = [base2];
18070
17565
  for (const w of trail) {
18071
17566
  const clause = trailClause(fields, w);
18072
17567
  if (!clause.field) continue;
@@ -18080,14 +17575,14 @@ function filterWithTrail(fields, base, trail) {
18080
17575
  }
18081
17576
  return { op: "and", args };
18082
17577
  }
18083
- function filterWithWindow(fields, base, key, range) {
18084
- if (!base || !isRuleFilter2(base)) return { ...base ?? {}, [key]: { from: range.from, to: range.to } };
17578
+ function filterWithWindow(fields, base2, key, range) {
17579
+ if (!base2 || !isRuleFilter2(base2)) return { ...base2 ?? {}, [key]: { from: range.from, to: range.to } };
18085
17580
  const field2 = fields.find((f) => f.key === key);
18086
- if (!field2) return base;
17581
+ if (!field2) return base2;
18087
17582
  const ref = { field: field2.id };
18088
17583
  return {
18089
17584
  op: "and",
18090
- args: [base, { op: "gte", args: [ref, { const: range.from }] }, { op: "lt", args: [ref, { const: range.to }] }]
17585
+ args: [base2, { op: "gte", args: [ref, { const: range.from }] }, { op: "lt", args: [ref, { const: range.to }] }]
18091
17586
  };
18092
17587
  }
18093
17588
  function useGridDrillQuestion(args) {
@@ -18769,7 +18264,7 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
18769
18264
  ...look?.frozen ? { frozen: true, width: Math.max(FROZEN_COLUMN_WIDTH, defaultColumnWidth(field2)) } : { width: defaultColumnWidth(field2) },
18770
18265
  // A column that holds numbers filters as numbers (=, <, >, between) — the record number too,
18771
18266
  // 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",
18267
+ filter: filterRefusal(field2) !== null ? false : editorKindFor(field2) === "select" || editorKindFor(field2) === "multi_select" ? "select" : holdsNumbers2(field2) ? "number" : "auto",
18773
18268
  // THE MENU'S VALUE LIST WEARS THE CHOICES' COLOURS (lane CELL-EDITORS, night walk 2026-10-06): the
18774
18269
  // same chip the cell draws, never bare words beside a coloured column.
18775
18270
  ...editorKindFor(field2) === "select" || editorKindFor(field2) === "multi_select" ? { filterValueClass: (value, label) => choiceChipLookOf(field2, value, label).className } : {},
@@ -18896,6 +18391,18 @@ function withTypeMark(field2, header) {
18896
18391
  // src/ReverseColumns.tsx
18897
18392
  import { useCallback as useCallback20, useEffect as useEffect44, useMemo as useMemo27, useRef as useRef29, useState as useState55, useSyncExternalStore as useSyncExternalStore3 } from "react";
18898
18393
  import { isReverseField } from "@ai-matrx/records";
18394
+
18395
+ // src/groupReads.ts
18396
+ import {
18397
+ REVERSE_CELL_CHIPS,
18398
+ choiceFieldKeys,
18399
+ groupFactMeasures,
18400
+ groupedPageSort,
18401
+ isPlainGrouping,
18402
+ summaryBarMeasures
18403
+ } from "@ai-matrx/records/first-page";
18404
+
18405
+ // src/ReverseColumns.tsx
18899
18406
  import { useFields as useFields6, useOptionalRecordsClient as useOptionalRecordsClient11, useReverseColumns as useReverseColumns3, useReverseLinks, useTable as useTable4 } from "@ai-matrx/records/react";
18900
18407
  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
18408
  import { Fragment as Fragment19, jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
@@ -19356,10 +18863,10 @@ function PastePreview({
19356
18863
  /* @__PURE__ */ jsx67(PlanTable, { plan }),
19357
18864
  plan.refusals.length > 0 ? /* @__PURE__ */ jsxs62("div", { "data-matrx-paste-refusals": true, className: "flex flex-col gap-1", children: [
19358
18865
  /* @__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 }),
18866
+ /* @__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: [
18867
+ /* @__PURE__ */ jsx67("span", { className: "font-medium", children: refusal3.fromLine > 0 ? `Row ${refusal3.fromLine}, ${refusal3.column}` : refusal3.column }),
19361
18868
  " \u2014 ",
19362
- refusal4.why
18869
+ refusal3.why
19363
18870
  ] }, index)) }),
19364
18871
  plan.refusals.length > 12 ? /* @__PURE__ */ jsxs62("p", { className: "text-xs text-muted-foreground", children: [
19365
18872
  plan.refusals.length - 12,
@@ -19836,8 +19343,8 @@ function offerDownload(name, text, type = "text/csv") {
19836
19343
  return true;
19837
19344
  }
19838
19345
  function refusedFileName(sourceName) {
19839
- const base = (sourceName ?? "import").replace(/\.(csv|xlsx)$/i, "");
19840
- return `${base} \u2014 rows not added.csv`;
19346
+ const base2 = (sourceName ?? "import").replace(/\.(csv|xlsx)$/i, "");
19347
+ return `${base2} \u2014 rows not added.csv`;
19841
19348
  }
19842
19349
 
19843
19350
  // src/ImportWizard.tsx
@@ -21291,11 +20798,11 @@ function cellWords(raw) {
21291
20798
  function uniqueLabels(raw) {
21292
20799
  const seen = /* @__PURE__ */ new Map();
21293
20800
  return raw.map((label, index) => {
21294
- const base = label.trim() || `Column ${index + 1}`;
21295
- const key = base.toLowerCase();
20801
+ const base2 = label.trim() || `Column ${index + 1}`;
20802
+ const key = base2.toLowerCase();
21296
20803
  const count = (seen.get(key) ?? 0) + 1;
21297
20804
  seen.set(key, count);
21298
- return count === 1 ? base : `${base} ${count}`;
20805
+ return count === 1 ? base2 : `${base2} ${count}`;
21299
20806
  });
21300
20807
  }
21301
20808
  function rowsOf(headers, matrix) {
@@ -21356,7 +20863,7 @@ function recordsFromPairs(pairs) {
21356
20863
  if (current.size > 0) records.push(current);
21357
20864
  return records;
21358
20865
  }
21359
- function shapeFromRecords(records, base, from) {
20866
+ function shapeFromRecords(records, base2, from) {
21360
20867
  const order = [];
21361
20868
  for (const r of records) for (const k of r.keys()) if (!order.some((o) => o.toLowerCase() === k.toLowerCase())) order.push(k);
21362
20869
  const headers = uniqueLabels(order);
@@ -21369,7 +20876,7 @@ function shapeFromRecords(records, base, from) {
21369
20876
  return row;
21370
20877
  });
21371
20878
  return {
21372
- ...base,
20879
+ ...base2,
21373
20880
  kind: "key_value",
21374
20881
  headers,
21375
20882
  rows,
@@ -21948,7 +21455,7 @@ function valueListKind(field2) {
21948
21455
  if (kind === "text" || kind === "long_text" || kind === "email" || kind === "phone" || kind === "url") return "words";
21949
21456
  if (kind === "datetime" || kind === "date") return "days";
21950
21457
  if (kind === "checkbox") return "yesno";
21951
- if (holdsNumbers(field2) || kind === "rating") return "numbers";
21458
+ if (holdsNumbers2(field2) || kind === "rating") return "numbers";
21952
21459
  return "loaded";
21953
21460
  }
21954
21461
  function noValueList(columnId2) {
@@ -22214,35 +21721,35 @@ function useGridUndo(args) {
22214
21721
  if (!step2) return;
22215
21722
  setBusy(true);
22216
21723
  const changes = changesFor(step2, direction, known.current);
22217
- let refusal4 = null;
21724
+ let refusal3 = null;
22218
21725
  if (direction === "redo" && (step2.created?.length ?? 0) > 0) {
22219
21726
  const answers = await Promise.all((step2.created ?? []).map((id) => client.recordRestore({ record_id: id })));
22220
21727
  const failed = answers.find((a) => !a.ok);
22221
- if (failed && !failed.ok) refusal4 = failed.error;
21728
+ if (failed && !failed.ok) refusal3 = failed.error;
22222
21729
  }
22223
- if (!refusal4 && step2.retiredField) {
21730
+ if (!refusal3 && step2.retiredField) {
22224
21731
  const fieldId = step2.retiredField.fieldId;
22225
21732
  const done = direction === "undo" ? await client.fieldRestore({ field_id: fieldId }) : await client.fieldRetire({ field_id: fieldId });
22226
- if (!done.ok) refusal4 = done.error;
21733
+ if (!done.ok) refusal3 = done.error;
22227
21734
  else tableShapeChanged6(tableId);
22228
21735
  }
22229
- if (!refusal4 && changes.length > 0) {
21736
+ if (!refusal3 && changes.length > 0) {
22230
21737
  const done = await (0, recordVersions_exports.changeRecordsAt)(client, { table_id: tableId, changes });
22231
- if (!done.ok) refusal4 = done.error;
21738
+ if (!done.ok) refusal3 = done.error;
22232
21739
  else {
22233
21740
  for (const result of done.data ?? []) if (result.op === "update") known.current.set(result.id, result.version);
22234
21741
  onVersions?.((done.data ?? []).flatMap((r) => r.op === "update" ? [{ id: r.id, version: r.version }] : []));
22235
21742
  }
22236
21743
  }
22237
- if (!refusal4 && direction === "undo" && (step2.archived?.length ?? 0) > 0) {
21744
+ if (!refusal3 && direction === "undo" && (step2.archived?.length ?? 0) > 0) {
22238
21745
  const answers = await Promise.all((step2.archived ?? []).map((id) => client.recordRestore({ record_id: id })));
22239
21746
  const failed = answers.find((a) => !a.ok);
22240
- if (failed && !failed.ok) refusal4 = failed.error;
21747
+ if (failed && !failed.ok) refusal3 = failed.error;
22241
21748
  }
22242
21749
  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();
21750
+ if (refusal3) {
21751
+ setNotice({ says: `${direction === "undo" ? "Undo" : "Redo"} changed nothing: ${refusalSentence(refusal3)}`, refusal: refusal3, canUndo: false });
21752
+ if ((0, recordVersions_exports.isChangedElsewhere)(refusal3)) reload();
22246
21753
  return;
22247
21754
  }
22248
21755
  forget(step2.cells.map((c) => ({ rowId: c.rowId, key: c.key })));
@@ -22973,7 +22480,7 @@ function useGridBulk(args) {
22973
22480
  const client = useRecordsClient37();
22974
22481
  const { tableId, rows, fields, noun, nounPlural, reload, forget, pushUndo: pushUndo2, versions } = args;
22975
22482
  const [busy, setBusy] = useState62(false);
22976
- const [refusal4, setRefusal] = useState62(null);
22483
+ const [refusal3, setRefusal] = useState62(null);
22977
22484
  const send = useCallback26(
22978
22485
  async (changes) => {
22979
22486
  setBusy(true);
@@ -23037,7 +22544,7 @@ function useGridBulk(args) {
23037
22544
  },
23038
22545
  [send, rows, pushUndo2, reload, noun, nounPlural]
23039
22546
  );
23040
- return { busy, refusal: refusal4, clearRefusal: () => setRefusal(null), apply, duplicate, archive };
22547
+ return { busy, refusal: refusal3, clearRefusal: () => setRefusal(null), apply, duplicate, archive };
23041
22548
  }
23042
22549
  function BulkActions({
23043
22550
  ids,
@@ -23158,6 +22665,31 @@ import { useEffect as useEffect52, useMemo as useMemo34, useRef as useRef35, use
23158
22665
  import { useRecordsClient as useRecordsClient38 } from "@ai-matrx/records/react";
23159
22666
  import { stableFilterKey as stableFilterKey2 } from "@ai-matrx/records";
23160
22667
  import { Button as Button43, ConfirmDialog as ConfirmDialog4, Popover as Popover9, PopoverContent as PopoverContent9, PopoverTrigger as PopoverTrigger9, cn as cn38 } from "@ai-matrx/design-system";
22668
+
22669
+ // src/views.ts
22670
+ import {
22671
+ STORE_KEEPS_TIMELINE as STORE_KEEPS_TIMELINE2,
22672
+ STORE_KEPT_LAYOUTS as STORE_KEPT_LAYOUTS2,
22673
+ storeKeepsLayout as storeKeepsLayout2,
22674
+ VIEW_LAYOUTS,
22675
+ LAYOUT_LABEL,
22676
+ wordsList,
22677
+ VIEW_NEEDS,
22678
+ freeColumnName,
22679
+ viewOrderOf,
22680
+ defaultViewOf,
22681
+ LAYOUT_FIELD_KIND,
22682
+ PAGE_VIEWS,
22683
+ PAGE_VIEW_LABEL,
22684
+ pageViewFromParam,
22685
+ unknownViewLine,
22686
+ makeDefaultLabel,
22687
+ designateView,
22688
+ viewPatchFor
22689
+ } from "@ai-matrx/records/views";
22690
+ var { viewDocument, viewFromRow, declareView, saveViewPatch, viewPatchDocument } = boundViews;
22691
+
22692
+ // src/handOrder.tsx
23161
22693
  import { jsx as jsx76, jsxs as jsxs69 } from "react/jsx-runtime";
23162
22694
  function sortArrow(direction) {
23163
22695
  return direction === "asc" ? "\u2191" : "\u2193";
@@ -25716,6 +25248,11 @@ import {
25716
25248
  useEntityWrite,
25717
25249
  useOptionalEntityScope
25718
25250
  } from "@ai-matrx/records/entity/react";
25251
+
25252
+ // src/entityQuery.ts
25253
+ import { entityChartQuestion, entityTableQuery } from "@ai-matrx/records/first-page";
25254
+
25255
+ // src/entityTable.tsx
25719
25256
  import { Fragment as Fragment27, jsx as jsx78 } from "react/jsx-runtime";
25720
25257
  function EntityDataScope({ children }) {
25721
25258
  const above = useOptionalEntityScope();
@@ -26446,19 +25983,19 @@ function fieldsForNewColumns(columns) {
26446
25983
  let key = tokenFor(column.label) || `column_${i + 1}`;
26447
25984
  while (keys.has(key)) key = `${key}_${i + 1}`;
26448
25985
  keys.add(key);
26449
- const base = { key, label: column.label, sort: (i + 1) * 10, required: false };
25986
+ const base2 = { key, label: column.label, sort: (i + 1) * 10, required: false };
26450
25987
  switch (column.type) {
26451
25988
  case "date":
26452
- return { ...base, type: "datetime", kind: "date" };
25989
+ return { ...base2, type: "datetime", kind: "date" };
26453
25990
  case "datetime":
26454
- return { ...base, type: "datetime", kind: "datetime" };
25991
+ return { ...base2, type: "datetime", kind: "datetime" };
26455
25992
  case "currency":
26456
- return { ...base, type: "currency", unit: "$" };
25993
+ return { ...base2, type: "currency", unit: "$" };
26457
25994
  case "select":
26458
25995
  case "multi_select":
26459
- return { ...base, type: column.type, multi: column.type === "multi_select", options: column.options ?? [] };
25996
+ return { ...base2, type: column.type, multi: column.type === "multi_select", options: column.options ?? [] };
26460
25997
  default:
26461
- return { ...base, type: column.type };
25998
+ return { ...base2, type: column.type };
26462
25999
  }
26463
26000
  });
26464
26001
  }
@@ -27124,15 +26661,15 @@ function objectActionForKey(actions, event) {
27124
26661
  const id = Object.keys(TABLE_ACTION_KEYS).find((k) => TABLE_ACTION_KEYS[k].code === event.code);
27125
26662
  return id ? actions.find((a) => a.id === id) ?? null : null;
27126
26663
  }
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 };
26664
+ function action(base2, needs, input, perform) {
26665
+ const chord = TABLE_ACTION_KEYS[base2.id];
26666
+ if (chord && base2.shortcut === void 0) base2 = { ...base2, shortcut: chord.label };
27130
26667
  const refused = rightsReason(input.rights, needs, input.table);
27131
- if (refused !== null) return { ...base, disabledReason: refused, run: NOOP };
26668
+ if (refused !== null) return { ...base2, disabledReason: refused, run: NOOP };
27132
26669
  if (perform === void 0) {
27133
- return { ...base, disabledReason: input.host.unavailableReasons?.[base.id] ?? ACTION_NOT_HERE_REASON, run: NOOP };
26670
+ return { ...base2, disabledReason: input.host.unavailableReasons?.[base2.id] ?? ACTION_NOT_HERE_REASON, run: NOOP };
27134
26671
  }
27135
- return { ...base, run: perform };
26672
+ return { ...base2, run: perform };
27136
26673
  }
27137
26674
  function bind(handler, table) {
27138
26675
  return handler ? () => handler(table) : void 0;
@@ -27203,9 +26740,9 @@ function tableActions(input) {
27203
26740
  ];
27204
26741
  return withExtensions(built, host.extend ? host.extend(table, input.rights) : []);
27205
26742
  }
27206
- function withExtensions(base, extra) {
27207
- if (extra.length === 0) return [...base];
27208
- const seen = new Set(base.map((a) => a.id));
26743
+ function withExtensions(base2, extra) {
26744
+ if (extra.length === 0) return [...base2];
26745
+ const seen = new Set(base2.map((a) => a.id));
27209
26746
  for (const entry of extra) {
27210
26747
  if (entry.group === "danger") {
27211
26748
  throw new Error(`Object action "${entry.id}": the danger group is closed to extensions.`);
@@ -27220,7 +26757,7 @@ function withExtensions(base, extra) {
27220
26757
  }
27221
26758
  const out = [];
27222
26759
  for (const group of OBJECT_ACTION_GROUPS) {
27223
- out.push(...base.filter((a) => a.group === group.id), ...extra.filter((a) => a.group === group.id));
26760
+ out.push(...base2.filter((a) => a.group === group.id), ...extra.filter((a) => a.group === group.id));
27224
26761
  }
27225
26762
  return out;
27226
26763
  }
@@ -27426,7 +26963,7 @@ function ArchivedBuiltOn({ tableId, onRestored }) {
27426
26963
  const [things, setThings] = useState68(null);
27427
26964
  const [error, setError] = useState68(null);
27428
26965
  const [restoring, setRestoring] = useState68(null);
27429
- const [refusal4, setRefusal] = useState68(null);
26966
+ const [refusal3, setRefusal] = useState68(null);
27430
26967
  const [said2, setSaid] = useState68(null);
27431
26968
  const read = useCallback30(async () => {
27432
26969
  const [forms, checklists] = await Promise.all([
@@ -27479,7 +27016,7 @@ function ArchivedBuiltOn({ tableId, onRestored }) {
27479
27016
  " \xB7 archived ",
27480
27017
  archivedWhen(thing.archivedAt)
27481
27018
  ] }),
27482
- refusal4 && refusal4.id === thing.id ? /* @__PURE__ */ jsx87(RefusalNotice, { error: refusal4.error, className: "mt-2" }) : null
27019
+ refusal3 && refusal3.id === thing.id ? /* @__PURE__ */ jsx87(RefusalNotice, { error: refusal3.error, className: "mt-2" }) : null
27483
27020
  ] }),
27484
27021
  thing.whyNot ? /* @__PURE__ */ jsx87("span", { className: "text-xs text-muted-foreground", children: thing.whyNot }) : /* @__PURE__ */ jsx87(
27485
27022
  Button50,
@@ -28323,20 +27860,20 @@ function draftsFor(headers, rows) {
28323
27860
  function keysFor(labels) {
28324
27861
  const used = /* @__PURE__ */ new Set();
28325
27862
  return labels.map((label, i) => {
28326
- const base = tokenFor(label) === "table" && !/table/i.test(label) ? `column_${i + 1}` : tokenFor(label);
28327
- let key = base;
27863
+ const base2 = tokenFor(label) === "table" && !/table/i.test(label) ? `column_${i + 1}` : tokenFor(label);
27864
+ let key = base2;
28328
27865
  let n = 2;
28329
- while (used.has(key)) key = `${base}_${n++}`;
27866
+ while (used.has(key)) key = `${base2}_${n++}`;
28330
27867
  used.add(key);
28331
27868
  return key;
28332
27869
  });
28333
27870
  }
28334
27871
  function freeName(name, taken) {
28335
27872
  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()}`;
27873
+ const base2 = name.trim() || "Saved table";
27874
+ if (!lower.has(base2.toLowerCase())) return base2;
27875
+ for (let n = 2; n < 100; n += 1) if (!lower.has(`${base2} ${n}`.toLowerCase())) return `${base2} ${n}`;
27876
+ return `${base2} ${Date.now()}`;
28340
27877
  }
28341
27878
  async function sha256Text(text) {
28342
27879
  const subtle = globalThis.crypto?.subtle;
@@ -29256,11 +28793,11 @@ import { Badge as Badge14, Button as Button61, Separator as Separator8, cn as cn
29256
28793
  var TableRestoreRefused = class extends Error {
29257
28794
  refusal;
29258
28795
  sentence;
29259
- constructor(refusal4) {
29260
- const sentence2 = refusalSentence(refusal4);
28796
+ constructor(refusal3) {
28797
+ const sentence2 = refusalSentence(refusal3);
29261
28798
  super(sentence2);
29262
28799
  this.name = "TableRestoreRefused";
29263
- this.refusal = refusal4;
28800
+ this.refusal = refusal3;
29264
28801
  this.sentence = sentence2;
29265
28802
  }
29266
28803
  };
@@ -30778,6 +30315,22 @@ function usePlatformTable(spec) {
30778
30315
  return state;
30779
30316
  }
30780
30317
 
30318
+ // src/viewLook.ts
30319
+ import { applyLook, lookDiffers, lookPart, saveToViewPlan } from "@ai-matrx/records/views";
30320
+ var { lookDocument, lookFromDocument, readLooks, keepLook } = boundViews;
30321
+ var LOOK_WORDS = {
30322
+ /** The reason, for a tooltip or a screen reader — never a line on the page (interface-text). */
30323
+ yours: "You changed how this view looks. Only you see it.",
30324
+ /** The visible label for the same fact. */
30325
+ yoursLabel: "Only you see this",
30326
+ saveToView: "Save to view",
30327
+ saveAsNew: "Save as new view",
30328
+ reset: "Reset to view",
30329
+ /** The one button your look's doors fold into when the toolbar row has no room for three. */
30330
+ folded: "Your look",
30331
+ newName: "Name for the new view"
30332
+ };
30333
+
30781
30334
  // src/ViewSwitcher.tsx
30782
30335
  import { useEffect as useEffect79, useMemo as useMemo55, useState as useState93 } from "react";
30783
30336
  import { mayDrag as mayDrag4, useFields as useFields18, useRecordPage as useRecordPage2, useRecordsClient as useRecordsClient65, useTable as useTable18 } from "@ai-matrx/records/react";
@@ -31072,13 +30625,13 @@ function recordLink(tableId, recordId, origin = DEFAULT_ACTION_ORIGIN) {
31072
30625
  }
31073
30626
  var NOOP2 = () => {
31074
30627
  };
31075
- function action2(base, needs, input, perform) {
30628
+ function action2(base2, needs, input, perform) {
31076
30629
  const refused = rightsReason(input.rights, needs);
31077
- if (refused !== null) return { ...base, disabledReason: refused, run: NOOP2 };
30630
+ if (refused !== null) return { ...base2, disabledReason: refused, run: NOOP2 };
31078
30631
  if (perform === void 0) {
31079
- return { ...base, disabledReason: input.host.unavailableReasons?.[base.id] ?? ACTION_NOT_HERE_REASON, run: NOOP2 };
30632
+ return { ...base2, disabledReason: input.host.unavailableReasons?.[base2.id] ?? ACTION_NOT_HERE_REASON, run: NOOP2 };
31080
30633
  }
31081
- return { ...base, run: perform };
30634
+ return { ...base2, run: perform };
31082
30635
  }
31083
30636
  function bind2(handler, record) {
31084
30637
  return handler ? () => handler(record) : void 0;
@@ -33845,12 +33398,12 @@ function viewNeedFor(layout) {
33845
33398
  return VIEW_NEEDS[layout];
33846
33399
  }
33847
33400
  function columnDeclarationFor(need, label, options, fields) {
33848
- const base = { label: label.trim(), sort: nextFieldSort(fields) };
33401
+ const base2 = { label: label.trim(), sort: nextFieldSort(fields) };
33849
33402
  if (need.starter.type === "select") {
33850
- return { ...base, parity_type: "select", options: options.map((o) => o.trim()).filter((o) => o !== "") };
33403
+ return { ...base2, parity_type: "select", options: options.map((o) => o.trim()).filter((o) => o !== "") };
33851
33404
  }
33852
- if (need.starter.type === "datetime") return { ...base, parity_type: "datetime", kind: "date" };
33853
- return { ...base, parity_type: "attachment" };
33405
+ if (need.starter.type === "datetime") return { ...base2, parity_type: "datetime", kind: "date" };
33406
+ return { ...base2, parity_type: "attachment" };
33854
33407
  }
33855
33408
  var askedFor = /* @__PURE__ */ new Map();
33856
33409
  var askKey = (tableId, layout) => `${tableId}:${layout}`;
@@ -34730,10 +34283,10 @@ function Board({
34730
34283
  ...view.endField ? { endKey: view.endField } : {},
34731
34284
  groupKey: view.groupField ?? null,
34732
34285
  ...view.presentation?.style?.colorBy !== void 0 ? { colorKey: view.presentation.style.colorBy?.field ?? null } : {},
34733
- layoutKept: remembered && STORE_KEEPS_TIMELINE,
34286
+ layoutKept: remembered && STORE_KEEPS_TIMELINE2,
34734
34287
  onSettingsChange: (patch) => {
34735
34288
  if (patch.startKey !== void 0) {
34736
- onChange({ startField: patch.startKey, ...STORE_KEEPS_TIMELINE ? {} : { dateField: patch.startKey } });
34289
+ onChange({ startField: patch.startKey, ...STORE_KEEPS_TIMELINE2 ? {} : { dateField: patch.startKey } });
34737
34290
  }
34738
34291
  if (patch.endKey !== void 0) onChange({ endField: patch.endKey });
34739
34292
  if (patch.groupKey !== void 0) onChange({ groupField: patch.groupKey });
@@ -35333,7 +34886,7 @@ function ArchivedView({
35333
34886
  const [loading, setLoading] = useState94(true);
35334
34887
  const [error, setError] = useState94(null);
35335
34888
  const [restoring, setRestoring] = useState94(null);
35336
- const [refusal4, setRefusal] = useState94(null);
34889
+ const [refusal3, setRefusal] = useState94(null);
35337
34890
  useEffect80(() => {
35338
34891
  if (laneFromHost) setLane(laneFromHost);
35339
34892
  }, [laneFromHost]);
@@ -35410,7 +34963,7 @@ function ArchivedView({
35410
34963
  /* @__PURE__ */ jsxs106("div", { className: "flex min-w-0 flex-1 flex-col", children: [
35411
34964
  /* @__PURE__ */ jsx116("span", { className: "truncate text-sm", children: recordName(row.document, titleKey) }),
35412
34965
  /* @__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
34966
+ refusal3 && refusal3.recordId === row.id ? /* @__PURE__ */ jsx116(RefusalNotice, { error: refusal3.error, className: "mt-2" }) : null
35414
34967
  ] }),
35415
34968
  mayRestore ? /* @__PURE__ */ jsx116(
35416
34969
  Button71,
@@ -35439,7 +34992,7 @@ function RetiredColumns({ tableId, mayRestore, whyNot }) {
35439
34992
  const [rows, setRows] = useState94(null);
35440
34993
  const [error, setError] = useState94(null);
35441
34994
  const [restoring, setRestoring] = useState94(null);
35442
- const [refusal4, setRefusal] = useState94(null);
34995
+ const [refusal3, setRefusal] = useState94(null);
35443
34996
  const read = useCallback40(async () => {
35444
34997
  const answer = await client.fieldsRetired({ table_id: tableId });
35445
34998
  if (answer.ok) {
@@ -35483,7 +35036,7 @@ function RetiredColumns({ tableId, mayRestore, whyNot }) {
35483
35036
  /* @__PURE__ */ jsxs106("div", { className: "flex min-w-0 flex-1 flex-col", children: [
35484
35037
  /* @__PURE__ */ jsx116("span", { className: "truncate text-sm", children: name }),
35485
35038
  /* @__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
35039
+ refusal3 && refusal3.fieldId === row.id ? /* @__PURE__ */ jsx116(RefusalNotice, { error: refusal3.error, className: "mt-2" }) : null
35487
35040
  ] }),
35488
35041
  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
35042
  ]
@@ -35552,7 +35105,7 @@ function ArchivedPortals({
35552
35105
  const [confirming, setConfirming] = useState95(null);
35553
35106
  const [typed2, setTyped] = useState95("");
35554
35107
  const [restoring, setRestoring] = useState95(null);
35555
- const [refusal4, setRefusal] = useState95(null);
35108
+ const [refusal3, setRefusal] = useState95(null);
35556
35109
  const [said2, setSaid] = useState95(null);
35557
35110
  const read = useCallback41(async () => {
35558
35111
  const answered = await client.listPortals({ archived: "archived" });
@@ -35668,7 +35221,7 @@ function ArchivedPortals({
35668
35221
  )
35669
35222
  ] })
35670
35223
  ] }) : null,
35671
- refusal4 && refusal4.portalId === portal.portal_id ? /* @__PURE__ */ jsx117(RefusalNotice, { error: refusal4.error }) : null
35224
+ refusal3 && refusal3.portalId === portal.portal_id ? /* @__PURE__ */ jsx117(RefusalNotice, { error: refusal3.error }) : null
35672
35225
  ]
35673
35226
  },
35674
35227
  portal.portal_id
@@ -35702,10 +35255,10 @@ import { useTable as useTable20 } from "@ai-matrx/records/react";
35702
35255
  var NOOP3 = () => {
35703
35256
  };
35704
35257
  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 };
35258
+ const one = (base2, run) => {
35259
+ if (whyNot !== null) return { ...base2, disabledReason: whyNot, run: NOOP3 };
35260
+ if (!run) return { ...base2, disabledReason: ACTION_NOT_HERE_REASON, run: NOOP3 };
35261
+ return { ...base2, run };
35709
35262
  };
35710
35263
  return [
35711
35264
  one({ id: "rename", label: "Rename view\u2026", icon: "pencil", group: "organize", verb: "rename" }, host.rename),
@@ -35717,8 +35270,8 @@ function viewActions(whyNot, host) {
35717
35270
  ];
35718
35271
  }
35719
35272
  function copyName(name, taken) {
35720
- const base = `${name} (copy)`;
35721
- if (!taken.includes(base)) return base;
35273
+ const base2 = `${name} (copy)`;
35274
+ if (!taken.includes(base2)) return base2;
35722
35275
  for (let n = 2; ; n += 1) {
35723
35276
  const next = `${name} (copy ${n})`;
35724
35277
  if (!taken.includes(next)) return next;
@@ -36490,7 +36043,7 @@ function MyChecklistSteps({
36490
36043
  }, [held, onSteps]);
36491
36044
  const steps = onlyIds ? held.filter((s) => onlyIds.has(s.step_id)) : held;
36492
36045
  const [busy, setBusy] = useState98(null);
36493
- const [refusal4, setRefusal] = useState98(null);
36046
+ const [refusal3, setRefusal] = useState98(null);
36494
36047
  const complete = useCallback44(
36495
36048
  async (step2, evidence) => {
36496
36049
  setBusy(step2.step_id);
@@ -36513,7 +36066,7 @@ function MyChecklistSteps({
36513
36066
  /* @__PURE__ */ jsx120("span", { className: "tabular-nums", children: steps.length })
36514
36067
  ] }),
36515
36068
  error ? /* @__PURE__ */ jsx120(RefusalNotice, { error }) : null,
36516
- refusal4 ? /* @__PURE__ */ jsx120(RefusalNotice, { error: refusal4 }) : null,
36069
+ refusal3 ? /* @__PURE__ */ jsx120(RefusalNotice, { error: refusal3 }) : null,
36517
36070
  /* @__PURE__ */ jsx120("ol", { className: "flex flex-col gap-1.5", children: steps.map(
36518
36071
  (step2) => actions ? /* @__PURE__ */ jsxs110("div", { className: "flex flex-col gap-0.5", "data-step-row": step2.step_id, children: [
36519
36072
  /* @__PURE__ */ jsx120(StepRow, { step: step2, busy: busy === step2.step_id, onComplete: (evidence) => void complete(step2, evidence) }),
@@ -36713,7 +36266,7 @@ function ChecklistTemplateEditor({
36713
36266
  const [saved, setSaved] = useState98(false);
36714
36267
  const [name, setName] = useState98("");
36715
36268
  const [rows, setRows] = useState98([{ ...EMPTY_ROW }]);
36716
- const [refusal4, setRefusal] = useState98(null);
36269
+ const [refusal3, setRefusal] = useState98(null);
36717
36270
  const [error, setError] = useState98(null);
36718
36271
  const [busy, setBusy] = useState98(false);
36719
36272
  const [loading, setLoading] = useState98(Boolean(templateId));
@@ -36889,10 +36442,10 @@ function ChecklistTemplateEditor({
36889
36442
  ] }, index)) }),
36890
36443
  /* @__PURE__ */ jsxs110("div", { className: "flex items-center gap-1.5", children: [
36891
36444
  /* @__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" }),
36445
+ /* @__PURE__ */ jsx120(Button75, { size: "sm", disabled: busy || refusal3 !== null || spec.steps.length === 0, onClick: () => void save(), children: busy ? "\u2026" : "Save" }),
36893
36446
  saved && !busy ? /* @__PURE__ */ jsx120("span", { className: "text-xs text-muted-foreground", "data-testid": "checklist-editor-saved", role: "status", children: "Saved" }) : null
36894
36447
  ] }),
36895
- refusal4 ? /* @__PURE__ */ jsx120("p", { className: "text-xs text-muted-foreground", "data-testid": "checklist-editor-refusal", children: refusal4 }) : null
36448
+ refusal3 ? /* @__PURE__ */ jsx120("p", { className: "text-xs text-muted-foreground", "data-testid": "checklist-editor-refusal", children: refusal3 }) : null
36896
36449
  ] });
36897
36450
  }
36898
36451
  function toStepSpec(row, index) {
@@ -42228,7 +41781,7 @@ function FormStage({
42228
41781
  const [answers, setAnswers] = useState114(() => ({ ...initialAnswers ?? {} }));
42229
41782
  const [at, setAt] = useState114(0);
42230
41783
  const [error, setError] = useState114(null);
42231
- const [refusal4, setRefusal] = useState114(null);
41784
+ const [refusal3, setRefusal] = useState114(null);
42232
41785
  const [writing, setWriting] = useState114(false);
42233
41786
  const [done, setDone] = useState114(null);
42234
41787
  const [hidden, setHidden] = useState114({});
@@ -42601,10 +42154,10 @@ function FormStage({
42601
42154
  ) : null,
42602
42155
  form.intro && index === 0 ? /* @__PURE__ */ jsx137("p", { className: "text-base text-muted-foreground", children: authored(host, form.intro, "form-intro") }) : null,
42603
42156
  error ? /* @__PURE__ */ jsx137(RefusalNotice, { error, className: "text-left" }) : null,
42604
- refusal4 ? /* @__PURE__ */ jsx137(
42157
+ refusal3 ? /* @__PURE__ */ jsx137(
42605
42158
  RefusalNotice,
42606
42159
  {
42607
- error: refusal4,
42160
+ error: refusal3,
42608
42161
  className: "text-left",
42609
42162
  onKeepEditing: () => {
42610
42163
  setRefusal(null);
@@ -42799,11 +42352,11 @@ import {
42799
42352
  formLookDocument
42800
42353
  } from "@ai-matrx/records/forms";
42801
42354
  import { Fragment as Fragment56, jsx as jsx138, jsxs as jsxs128 } from "react/jsx-runtime";
42802
- function freshFormName(base, taken) {
42355
+ function freshFormName(base2, taken) {
42803
42356
  const names = new Set(taken.map((n) => n.trim().toLowerCase()));
42804
- if (!names.has(base.toLowerCase())) return base;
42357
+ if (!names.has(base2.toLowerCase())) return base2;
42805
42358
  for (let n = 2; ; n += 1) {
42806
- const next = `${base} ${n}`;
42359
+ const next = `${base2} ${n}`;
42807
42360
  if (!names.has(next.toLowerCase())) return next;
42808
42361
  }
42809
42362
  }
@@ -43100,8 +42653,8 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
43100
42653
  return;
43101
42654
  }
43102
42655
  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(
42656
+ const base2 = table.data?.name?.trim() ? `${table.data.name.trim()} form` : "Form";
42657
+ void create(freshFormName(base2, forms.map((f) => f.name))).then(
43105
42658
  (made) => setMakeOnMount(made ? "made" : "not-made")
43106
42659
  );
43107
42660
  }, [createOnMount, makeOnMount, forms, fields.data, create, table.data, table.error]);
@@ -45063,7 +44616,7 @@ function AddChart({ subject, onAdd, onClose }) {
45063
44616
  const field2 = all.find((f) => f.key === key);
45064
44617
  return field2 ? scalarText(field2, value, labels) : String(value);
45065
44618
  };
45066
- const [measureKey5, setMeasureKey] = useState121("count");
44619
+ const [measureKey4, setMeasureKey] = useState121("count");
45067
44620
  const [splitKey, setSplitKey] = useState121("none");
45068
44621
  const [kind, setKind] = useState121("auto");
45069
44622
  const [filter, setFilter] = useState121({});
@@ -45071,7 +44624,7 @@ function AddChart({ subject, onAdd, onClose }) {
45071
44624
  const numbers = numberColumns(all);
45072
44625
  const choices = offerableFields(all, "choice");
45073
44626
  const dates = offerableFields(all, "date");
45074
- const measure = measureKey5 === "count" ? { op: "count" } : { op: measureKey5.split(":")[0], key: measureKey5.split(":")[1] };
44627
+ const measure = measureKey4 === "count" ? { op: "count" } : { op: measureKey4.split(":")[0], key: measureKey4.split(":")[1] };
45075
44628
  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
44629
  const shape = kind !== "auto" ? kind : split.kind === "period" ? "line" : split.kind === "column" ? "column" : "number";
45077
44630
  function pickTable(next) {
@@ -45089,7 +44642,7 @@ function AddChart({ subject, onAdd, onClose }) {
45089
44642
  return /* @__PURE__ */ jsxs135("div", { className: "flex flex-col gap-2 rounded border p-2 text-xs", role: "group", "aria-label": "Add chart", children: [
45090
44643
  /* @__PURE__ */ jsxs135("div", { className: "flex flex-wrap items-center gap-1", children: [
45091
44644
  /* @__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: [
44645
+ /* @__PURE__ */ jsxs135(Select17, { value: measureKey4, onValueChange: setMeasureKey, children: [
45093
44646
  /* @__PURE__ */ jsx146(SelectTrigger17, { size: "sm", "aria-label": "What the chart counts", className: "h-7 min-w-[8rem] text-xs", children: /* @__PURE__ */ jsx146(SelectValue17, {}) }),
45094
44647
  /* @__PURE__ */ jsxs135(SelectContent17, { children: [
45095
44648
  /* @__PURE__ */ jsx146(SelectItem17, { value: "count", children: "How many" }),
@@ -45185,14 +44738,14 @@ function filterTargets(filter, blocks) {
45185
44738
  if (filter.targets && filter.targets.length > 0) return filter.targets;
45186
44739
  return blocks.filter((b) => b.kind === "list" && b.table_id === filter.table_id).map((b) => b.id);
45187
44740
  }
45188
- function combineFilter(base, extra, fieldIdOf) {
44741
+ function combineFilter(base2, extra, fieldIdOf) {
45189
44742
  const extraKeys = Object.keys(extra);
45190
- if (!base || !isRuleFilter3(base) && Object.keys(base).length === 0) {
44743
+ if (!base2 || !isRuleFilter3(base2) && Object.keys(base2).length === 0) {
45191
44744
  return { filter: extraKeys.length > 0 ? { ...extra } : null, dropped: [] };
45192
44745
  }
45193
- if (!isRuleFilter3(base)) return { filter: { ...base, ...extra }, dropped: [] };
44746
+ if (!isRuleFilter3(base2)) return { filter: { ...base2, ...extra }, dropped: [] };
45194
44747
  const dropped = [];
45195
- let rule = base;
44748
+ let rule = base2;
45196
44749
  for (const key of extraKeys) {
45197
44750
  const id = fieldIdOf(key);
45198
44751
  if (!id) {
@@ -45848,372 +45401,9 @@ import { Badge as Badge24, BasicInput as BasicInput33, Button as Button97, Check
45848
45401
  import { useFields as useFields31, useRecordsClient as useRecordsClient88 } from "@ai-matrx/records/react";
45849
45402
 
45850
45403
  // 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
- }
45404
+ var question_exports = {};
45405
+ __reExport(question_exports, questions_star);
45406
+ import * as questions_star from "@ai-matrx/records/questions";
46217
45407
 
46218
45408
  // src/QuestionPanel.tsx
46219
45409
  import { Fragment as Fragment59, jsx as jsx148, jsxs as jsxs137 } from "react/jsx-runtime";
@@ -46269,12 +45459,12 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46269
45459
  }
46270
45460
  let live = true;
46271
45461
  void (async () => {
46272
- const mine2 = await unreadableKeys(client, tableId, all);
45462
+ const mine2 = await (0, question_exports.unreadableKeys)(client, tableId, all);
46273
45463
  const out = {};
46274
45464
  for (const rel of all.filter((f) => editorKindFor(f) === "relation" && f.relation_target && !mine2.has(f.key))) {
46275
45465
  const target = await client.fields({ table_id: rel.relation_target });
46276
45466
  if (!target.ok) continue;
46277
- const theirs = await unreadableKeys(client, rel.relation_target, target.data);
45467
+ const theirs = await (0, question_exports.unreadableKeys)(client, rel.relation_target, target.data);
46278
45468
  out[rel.key] = { relation: rel, fields: target.data.filter((f) => !theirs.has(f.key) && editorKindFor(f) !== "relation") };
46279
45469
  }
46280
45470
  if (!live) return;
@@ -46289,7 +45479,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46289
45479
  const [saved, setSaved] = useState123(null);
46290
45480
  const [savedEpoch, setSavedEpoch] = useState123(0);
46291
45481
  const [current, setCurrent] = useState123(null);
46292
- const [spec, setSpec] = useState123(newQuestion);
45482
+ const [spec, setSpec] = useState123(question_exports.newQuestion);
46293
45483
  const [name, setName] = useState123("");
46294
45484
  const [shared, setShared] = useState123(true);
46295
45485
  const [saveError, setSaveError] = useState123(null);
@@ -46298,7 +45488,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46298
45488
  const openedFromLink = useRef59(false);
46299
45489
  useEffect107(() => {
46300
45490
  let live = true;
46301
- void questionsOf(client, tableId).then((answer2) => {
45491
+ void (0, question_exports.questionsOf)(client, tableId).then((answer2) => {
46302
45492
  if (!live) return;
46303
45493
  setSaved(answer2.ok ? answer2.data : []);
46304
45494
  if (answer2.ok && activeQuestionId && !openedFromLink.current) {
@@ -46314,7 +45504,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46314
45504
  }, [client, tableId, savedEpoch, activeQuestionId]);
46315
45505
  const open = (q) => {
46316
45506
  setCurrent(q);
46317
- setSpec(q ? q.spec : newQuestion());
45507
+ setSpec(q ? q.spec : (0, question_exports.newQuestion)());
46318
45508
  setName(q ? q.name : "");
46319
45509
  setShared(q ? q.shared : true);
46320
45510
  setSaveError(null);
@@ -46333,7 +45523,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46333
45523
  let live = true;
46334
45524
  setAsking(true);
46335
45525
  const t = setTimeout(() => {
46336
- void askQuestion(client, tableId, spec, all).then((a) => {
45526
+ void (0, question_exports.askQuestion)(client, tableId, spec, all).then((a) => {
46337
45527
  if (!live) return;
46338
45528
  setAnswer(a);
46339
45529
  setAsking(false);
@@ -46349,7 +45539,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46349
45539
  setSaving(true);
46350
45540
  setSaveError(null);
46351
45541
  const editing = !asNew && current && mine;
46352
- const kept = await questionSave(client, {
45542
+ const kept = await (0, question_exports.questionSave)(client, {
46353
45543
  ...editing ? { id: current.id, expectedVersion: current.version } : {},
46354
45544
  tableId,
46355
45545
  name: asNew && current && name.trim() === current.name ? `${name.trim()} (copy)` : name,
@@ -46367,7 +45557,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46367
45557
  };
46368
45558
  const archive = async () => {
46369
45559
  if (!current) return;
46370
- const gone = await questionArchive(client, current.id, current.version);
45560
+ const gone = await (0, question_exports.questionArchive)(client, current.id, current.version);
46371
45561
  if (!gone.ok) return setSaveError(gone.error);
46372
45562
  open(null);
46373
45563
  setSavedEpoch((n) => n + 1);
@@ -46522,17 +45712,17 @@ function Measures({ measures, fields, onChange }) {
46522
45712
  const set = (i, next) => onChange(measures.map((m, j) => j === i ? next : m));
46523
45713
  return /* @__PURE__ */ jsxs137("div", { className: "flex flex-col gap-1", children: [
46524
45714
  measures.map((m, i) => {
46525
- const eligible = measurableFields(fields, m.op);
45715
+ const eligible = (0, question_exports.measurableFields)(fields, m.op);
46526
45716
  return /* @__PURE__ */ jsxs137("div", { className: "flex items-center gap-1", "data-testid": "question-measure", children: [
46527
45717
  /* @__PURE__ */ jsx148(
46528
45718
  PickOne,
46529
45719
  {
46530
45720
  label: "Measure",
46531
45721
  value: m.op,
46532
- options: QUESTION_OPS.map((op2) => ({ value: op2, label: OP_LABEL[op2] })),
45722
+ options: question_exports.QUESTION_OPS.map((op2) => ({ value: op2, label: OP_LABEL[op2] })),
46533
45723
  onChange: (op2) => {
46534
45724
  const nextOp = op2;
46535
- const keep = nextOp !== "count" && measurableFields(fields, nextOp).some((f) => f.key === m.key);
45725
+ const keep = nextOp !== "count" && (0, question_exports.measurableFields)(fields, nextOp).some((f) => f.key === m.key);
46536
45726
  set(i, nextOp === "count" ? { op: "count" } : { op: nextOp, ...keep ? { key: m.key } : {} });
46537
45727
  },
46538
45728
  className: "w-28",
@@ -46964,14 +46154,14 @@ function questionFromWords(text, fields, choices = {}) {
46964
46154
  const measured = head === "" ? null : columnNamed2(head, names);
46965
46155
  if (op2 === null) {
46966
46156
  if (head === "") op2 = "count";
46967
- else if (measured && measurableFields([...fields], "sum").some((f) => f.key === measured.key)) op2 = "sum";
46157
+ else if (measured && (0, question_exports.measurableFields)([...fields], "sum").some((f) => f.key === measured.key)) op2 = "sum";
46968
46158
  else return { ok: false, why: "Start with count, sum, average, smallest or largest" };
46969
46159
  }
46970
- const spec = { ...newQuestion(), group };
46160
+ const spec = { ...(0, question_exports.newQuestion)(), group };
46971
46161
  let measureReads = "Count";
46972
46162
  if (op2 !== "count") {
46973
46163
  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)) {
46164
+ if (!(0, question_exports.measurableFields)([...fields], op2).some((f) => f.key === measured.key)) {
46975
46165
  return { ok: false, why: `${fieldName(measured)} is not a number column` };
46976
46166
  }
46977
46167
  spec.measures = [{ op: op2, key: measured.key }];
@@ -47008,7 +46198,7 @@ function TableAsk({ tableId, onOpenInQuestions }) {
47008
46198
  const read = questionFromWords(words2, all, choices);
47009
46199
  if (!read.ok) return setSaid({ kind: "not-read", why: read.why });
47010
46200
  setSaid({ kind: "asking", reads: read.reads });
47011
- const answered = await askQuestion(client, tableId, read.spec, all);
46201
+ const answered = await (0, question_exports.askQuestion)(client, tableId, read.spec, all);
47012
46202
  setSaid(answered.ok ? { kind: "answer", reads: read.reads, spec: read.spec, answer: answered.data } : { kind: "refused", error: answered.error });
47013
46203
  };
47014
46204
  return /* @__PURE__ */ jsxs138(Popover14, { open, onOpenChange: setOpen, children: [
@@ -49608,16 +48798,16 @@ function toolbarFold(input) {
49608
48798
  };
49609
48799
  const withGap = (width) => width > 0 ? width + gap : 0;
49610
48800
  const shareNow = input.share ? withGap(input.share.now) : 0;
49611
- const base = pieces.reduce((rest, p) => rest - withGap(p.piece.now), needsNow - shareNow);
48801
+ const base2 = pieces.reduce((rest, p) => rest - withGap(p.piece.now), needsNow - shareNow);
49612
48802
  const stages = input.tools ? [0, 1, 2, 3] : [0, 1, 2];
49613
48803
  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));
48804
+ const needs = stages.map((fold) => pieces.reduce((sum, p) => sum + withGap(widthAt(p, fold)), base2 + shareOn));
49615
48805
  const fits = needs.findIndex((need) => need <= available + 0.5);
49616
48806
  if (fits >= 0) return stages[fits];
49617
48807
  const least = Math.min(...needs);
49618
48808
  const most = stages[needs.findIndex((need) => need <= least + 0.5)];
49619
48809
  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);
48810
+ const fixed = pieces.reduce((sum, p) => sum + withGap(p.stage === 3 ? SLOT_MIN : widthAt(p, 3)), base2 + shareOn);
49621
48811
  return fixed > available + 0.5 ? 4 : most;
49622
48812
  }
49623
48813
  function naturalWidth(el) {
@@ -49774,7 +48964,7 @@ function useSlotScroll(slot) {
49774
48964
  }
49775
48965
 
49776
48966
  // src/TablePage.tsx
49777
- import { isUuidShape as isUuidShape4 } from "@ai-matrx/kit/uuid";
48967
+ import { isUuidShape as isUuidShape3 } from "@ai-matrx/kit/uuid";
49778
48968
  import { Fragment as Fragment68, jsx as jsx163, jsxs as jsxs152 } from "react/jsx-runtime";
49779
48969
  var RAIL_TITLE = {
49780
48970
  settings: "Table settings",
@@ -49861,7 +49051,7 @@ function TableNotHere({
49861
49051
  const client = useRecordsClient98();
49862
49052
  const [archived, setArchived] = useState138({ phase: "asking" });
49863
49053
  const [restoring, setRestoring] = useState138(false);
49864
- const [refusal4, setRefusal] = useState138(null);
49054
+ const [refusal3, setRefusal] = useState138(null);
49865
49055
  useEffect117(() => {
49866
49056
  let alive = true;
49867
49057
  void client.tableArchived({ table_id: tableId }).then((answered) => {
@@ -49879,7 +49069,7 @@ function TableNotHere({
49879
49069
  /* @__PURE__ */ jsx163("p", { className: "text-sm font-medium", children: "This table is archived" }),
49880
49070
  /* @__PURE__ */ jsx163("p", { className: "max-w-prose text-xs text-muted-foreground", children: TABLE_IS_ARCHIVED }),
49881
49071
  /* @__PURE__ */ jsx163("p", { className: "text-xs text-muted-foreground", children: archivedByLine2(row) }),
49882
- refusal4 ? /* @__PURE__ */ jsx163(RefusalNotice, { error: refusal4 }) : null,
49072
+ refusal3 ? /* @__PURE__ */ jsx163(RefusalNotice, { error: refusal3 }) : null,
49883
49073
  /* @__PURE__ */ jsxs152("div", { className: "flex gap-2", children: [
49884
49074
  /* @__PURE__ */ jsx163(
49885
49075
  Button110,
@@ -49996,7 +49186,7 @@ function openingView(activeView, activeDashboardId) {
49996
49186
  }
49997
49187
  function savedViewFromParam(activeView) {
49998
49188
  const word = typeof activeView === "string" ? activeView.trim() : "";
49999
- return isUuidShape4(word) ? word.toLowerCase() : null;
49189
+ return isUuidShape3(word) ? word.toLowerCase() : null;
50000
49190
  }
50001
49191
  function addressForView(view, layout) {
50002
49192
  return view && !view.isDefault ? view.id : layout;
@@ -50368,7 +49558,7 @@ function TablePage({
50368
49558
  const [designateRefused, setDesignateRefused] = useState138(null);
50369
49559
  const opensAs = view?.isDefault ? view.layout : null;
50370
49560
  const canDesignate = Boolean(
50371
- rights.organise && view && layoutShowing && layoutShowing !== opensAs && storeKeepsLayout(layoutShowing)
49561
+ rights.organise && view && layoutShowing && layoutShowing !== opensAs && storeKeepsLayout2(layoutShowing)
50372
49562
  );
50373
49563
  const layoutShowingLabel = layoutShowing ? LAYOUT_LABEL[layoutShowing] : "";
50374
49564
  const designate = async () => {
@@ -50872,7 +50062,7 @@ function TablePage({
50872
50062
  QuestionPanel,
50873
50063
  {
50874
50064
  tableId,
50875
- activeQuestionId: questionsFromLink && activeItemId && isUuidShape4(activeItemId) ? activeItemId : null,
50065
+ activeQuestionId: questionsFromLink && activeItemId && isUuidShape3(activeItemId) ? activeItemId : null,
50876
50066
  draft: questionDraft
50877
50067
  }
50878
50068
  ) : main === "archived" ? (
@@ -51128,7 +50318,7 @@ function EntityBoard({ entity, groupBy, cardFields, onOpenRecord, className }) {
51128
50318
  const writable = !column.readOnly && entity.canUpdate;
51129
50319
  const placed = (row) => entityValueText(column, entityCellValue(row, column)) || null;
51130
50320
  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);
50321
+ const rowsOf2 = (key) => entity.rows.filter((r) => (placed(r) ?? "") === key);
51132
50322
  const drop = async (event, to) => {
51133
50323
  event.preventDefault();
51134
50324
  setOver(null);
@@ -51140,7 +50330,7 @@ function EntityBoard({ entity, groupBy, cardFields, onOpenRecord, className }) {
51140
50330
  if (says) setRefused({ to, says });
51141
50331
  };
51142
50332
  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);
50333
+ const cards = rowsOf2(lane.key);
51144
50334
  if (lane.key === "" && cards.length === 0) return null;
51145
50335
  return /* @__PURE__ */ jsxs153(
51146
50336
  "section",
@@ -51182,9 +50372,9 @@ function EntityBoard({ entity, groupBy, cardFields, onOpenRecord, className }) {
51182
50372
  );
51183
50373
  }) });
51184
50374
  }
51185
- function blockOfAnswer(answer, base, by) {
50375
+ function blockOfAnswer(answer, base2, by) {
51186
50376
  if (!answer.ok) {
51187
- return { ...base, refused: refusalSentence(answer.error) || "This chart could not be read.", ...answer.error.code ? { sqlstate: answer.error.code } : {} };
50377
+ return { ...base2, refused: refusalSentence(answer.error) || "This chart could not be read.", ...answer.error.code ? { sqlstate: answer.error.code } : {} };
51188
50378
  }
51189
50379
  const rows = answer.data.rows.filter((r) => by ? r.kind !== "total" : r.kind === "total").map((r) => {
51190
50380
  const groups = {};
@@ -51196,7 +50386,7 @@ function blockOfAnswer(answer, base, by) {
51196
50386
  for (const [k, v] of Object.entries(r.measures ?? {})) measuresOut[k] = typeof v === "number" ? v : v === null ? null : Number(v);
51197
50387
  return { groups, measures: measuresOut, row_count: Number(r.row_count) };
51198
50388
  });
51199
- return { ...base, rows };
50389
+ return { ...base2, rows };
51200
50390
  }
51201
50391
  function EntityChartBlock({ source, kind, by, measure, title, where, organization, centerValue, variant, className }) {
51202
50392
  const client = useRecordsClient99();
@@ -51204,9 +50394,9 @@ function EntityChartBlock({ source, kind, by, measure, title, where, organizatio
51204
50394
  const ask = JSON.stringify([source.token, by ?? null, m, where ?? null, organization ?? null]);
51205
50395
  const question = entityChartQuestion({ by, measure, where, organization });
51206
50396
  const measures = [m.op === "count" ? { op: "count" } : { op: m.op, key: m.of }];
51207
- const base = { title: title ?? "", kind, measures, group_by: by ? [by] : [] };
50397
+ const base2 = { title: title ?? "", kind, measures, group_by: by ? [by] : [] };
51208
50398
  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);
50399
+ const [block, setBlock] = useState139(() => seeded ? blockOfAnswer({ ok: true, data: seeded.data }, base2, by) : null);
51210
50400
  const seededFor = useRef63(seeded ? { ask: `${ask}|${kind}|${title ?? ""}`, at: seeded.at } : null);
51211
50401
  useEffect118(() => {
51212
50402
  const held = seededFor.current;
@@ -51215,7 +50405,7 @@ function EntityChartBlock({ source, kind, by, measure, title, where, organizatio
51215
50405
  let cancelled = false;
51216
50406
  void client.drillAsk({ source, question }).then((answer) => {
51217
50407
  if (cancelled) return;
51218
- setBlock(blockOfAnswer(answer, base, by));
50408
+ setBlock(blockOfAnswer(answer, base2, by));
51219
50409
  });
51220
50410
  return () => {
51221
50411
  cancelled = true;
@@ -51493,7 +50683,7 @@ function BindingDetails({
51493
50683
  }, [disabled, shape, binding, fields.loading, fieldList, table.data, onChange]);
51494
50684
  const selectShape = (next) => {
51495
50685
  if (next === shape) return;
51496
- const base = {
50686
+ const base2 = {
51497
50687
  kind: "merge_field",
51498
50688
  source: "record",
51499
50689
  semantic_type: next,
@@ -51501,21 +50691,21 @@ function BindingDetails({
51501
50691
  missing: binding.missing,
51502
50692
  override_policy: "shown_locked"
51503
50693
  };
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;
50694
+ if (next !== "collection" && binding.record_id) base2.record_id = binding.record_id;
50695
+ if (next === "value" && binding.field_key) base2.field_key = binding.field_key;
51506
50696
  if (next === "collection") {
51507
50697
  const limit = binding.limit ?? defaultRowLimit;
51508
- if (limit) base.limit = limit;
50698
+ if (limit) base2.limit = limit;
51509
50699
  }
51510
50700
  if (next !== "value" && binding.transform) {
51511
- base.transform = {
50701
+ base2.transform = {
51512
50702
  name: "list",
51513
50703
  template: binding.transform.template,
51514
50704
  ...binding.transform.join !== void 0 ? { join: binding.transform.join } : {},
51515
- ...next === "collection" && base.limit !== void 0 ? { max: base.limit } : {}
50705
+ ...next === "collection" && base2.limit !== void 0 ? { max: base2.limit } : {}
51516
50706
  };
51517
50707
  }
51518
- onChange(base);
50708
+ onChange(base2);
51519
50709
  };
51520
50710
  const fieldOptions = fieldList.map((f) => ({ value: f.key, label: fieldName(f) }));
51521
50711
  const template = binding.transform?.template ?? "";
@@ -51829,10 +51019,21 @@ function PreviewForms({ preview, booking }) {
51829
51019
  ] }, p.id)) : null
51830
51020
  ] });
51831
51021
  }
51022
+ var export_QUESTION_OPS = question_exports.QUESTION_OPS;
51023
+ var export_QUESTION_SURFACE = question_exports.QUESTION_SURFACE;
51832
51024
  var export_asRefusal = refusals_exports.asRefusal;
51025
+ var export_askQuestion = question_exports.askQuestion;
51026
+ var export_flatWhere = question_exports.flatWhere;
51027
+ var export_measurableFields = question_exports.measurableFields;
51028
+ var export_newQuestion = question_exports.newQuestion;
51029
+ var export_questionArchive = question_exports.questionArchive;
51030
+ var export_questionFromDefinition = question_exports.questionFromDefinition;
51031
+ var export_questionSave = question_exports.questionSave;
51032
+ var export_questionsOf = question_exports.questionsOf;
51833
51033
  var export_refusal = refusals_exports.refusal;
51834
51034
  var export_refusalFromThrown = refusals_exports.refusalFromThrown;
51835
51035
  var export_refusalOr = refusals_exports.refusalOr;
51036
+ var export_unreadableKeys = question_exports.unreadableKeys;
51836
51037
  export {
51837
51038
  ABSENCE_WORD_LABEL,
51838
51039
  ABSENCE_WORD_VALUES,
@@ -52006,8 +51207,8 @@ export {
52006
51207
  ProvenanceBadge,
52007
51208
  PublicPicturePicker,
52008
51209
  PublicViewPage,
52009
- QUESTION_OPS,
52010
- QUESTION_SURFACE,
51210
+ export_QUESTION_OPS as QUESTION_OPS,
51211
+ export_QUESTION_SURFACE as QUESTION_SURFACE,
52011
51212
  QuestionAnswerView,
52012
51213
  QuestionPanel,
52013
51214
  RECORDS_GRID_ROW_PX,
@@ -52045,8 +51246,8 @@ export {
52045
51246
  STANDARD_VERBS,
52046
51247
  STORE_ANSWERS_THESE,
52047
51248
  STORE_DECIDES_REASON,
52048
- STORE_KEEPS_TIMELINE,
52049
- STORE_KEPT_LAYOUTS,
51249
+ STORE_KEEPS_TIMELINE2 as STORE_KEEPS_TIMELINE,
51250
+ STORE_KEPT_LAYOUTS2 as STORE_KEPT_LAYOUTS,
52050
51251
  STRIP_FEATURE_ROWS,
52051
51252
  SUBSCRIPTION_CADENCES,
52052
51253
  SUBSCRIPTION_CADENCE_LABEL,
@@ -52120,7 +51321,7 @@ export {
52120
51321
  archivedRowLine,
52121
51322
  export_asRefusal as asRefusal,
52122
51323
  askExampleFor,
52123
- askQuestion,
51324
+ export_askQuestion as askQuestion,
52124
51325
  askableFields,
52125
51326
  bindingPlaceholdersFor,
52126
51327
  blockFromSpec,
@@ -52204,7 +51405,7 @@ export {
52204
51405
  fieldTypeLabel,
52205
51406
  fieldsForNewColumns,
52206
51407
  filterTargets,
52207
- flatWhere,
51408
+ export_flatWhere as flatWhere,
52208
51409
  footerOf,
52209
51410
  formDeclareArgs2 as formDeclareArgs,
52210
51411
  formEmbedSnippet2 as formEmbedSnippet,
@@ -52263,10 +51464,10 @@ export {
52263
51464
  looksLikeId,
52264
51465
  machineIdentityIn,
52265
51466
  mayNotRestoreLine,
52266
- measurableFields,
51467
+ export_measurableFields as measurableFields,
52267
51468
  memberName,
52268
51469
  moveRecordValue,
52269
- newQuestion,
51470
+ export_newQuestion as newQuestion,
52270
51471
  nextInWords,
52271
51472
  nextSummaryAt,
52272
51473
  notAChoiceSentence,
@@ -52292,11 +51493,11 @@ export {
52292
51493
  previewLine,
52293
51494
  previewWords,
52294
51495
  publiclyAnswerable,
52295
- questionArchive,
52296
- questionFromDefinition,
51496
+ export_questionArchive as questionArchive,
51497
+ export_questionFromDefinition as questionFromDefinition,
52297
51498
  questionFromWords,
52298
- questionSave,
52299
- questionsOf,
51499
+ export_questionSave as questionSave,
51500
+ export_questionsOf as questionsOf,
52300
51501
  railFromParam,
52301
51502
  readLooks,
52302
51503
  readTableShape,
@@ -52347,7 +51548,7 @@ export {
52347
51548
  starterPageBlocks,
52348
51549
  stepFromAgent,
52349
51550
  storeDecidesRights,
52350
- storeKeepsLayout,
51551
+ storeKeepsLayout2 as storeKeepsLayout,
52351
51552
  storePublishesKind,
52352
51553
  styleFromDecorations,
52353
51554
  submissionStamp2 as submissionStamp,
@@ -52366,7 +51567,7 @@ export {
52366
51567
  tokenFor,
52367
51568
  unknownRailLine,
52368
51569
  unknownViewLine,
52369
- unreadableKeys,
51570
+ export_unreadableKeys as unreadableKeys,
52370
51571
  useAddressDrill,
52371
51572
  useCanShare,
52372
51573
  useChoiceNudge,