@ai-matrx/records-ui 0.115.36 → 0.115.38

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
@@ -13399,7 +13399,7 @@ function SplitRecordDialog({ tableId, record, document: document2, open, onOpenC
13399
13399
  let madeName = recordNameIn(table.data ?? null, madeDoc, "New record");
13400
13400
  if (titleKey !== null && !titleHeld) {
13401
13401
  const named = `${record.name} (split)`;
13402
- const renamed = await client.recordUpdate({ record_id: created, patch: { [titleKey]: named } });
13402
+ const renamed = await (0, recordVersions_exports.updateRecordAt)(client, { record_id: created, patch: { [titleKey]: named }, version: await (0, recordVersions_exports.readVersionNow)(client, created) });
13403
13403
  if (renamed.ok) {
13404
13404
  madeName = named;
13405
13405
  onChanged?.();
@@ -19036,7 +19036,8 @@ function useGridDrillQuestion(args) {
19036
19036
  const source = useMemo28(() => ({ kind: "table", id: tableId }), [tableId]);
19037
19037
  const saved = useMemo28(() => questionFromGrouping(presentation.grouping), [presentation.grouping]);
19038
19038
  const url = useDrillUrlState({ fallback: saved });
19039
- const requested = args.enabled && (url.question.by.length > (args.plainGroupingIsRows ? 1 : 0) || url.question.across !== null || url.question.where.length > 0 || // `!= null`: a question read by a design-system that does not know the window or the comparison
19039
+ const requested = args.enabled && // Up to three levels are ROWS under nested headers on the merged grid (Airtable's group levels).
19040
+ (url.question.by.length > (args.plainGroupingIsRows ? 3 : 0) || url.question.across !== null || url.question.where.length > 0 || // `!= null`: a question read by a design-system that does not know the window or the comparison
19040
19041
  // yet has them UNDEFINED, and `undefined !== null` asked for drill metadata on every plain grid.
19041
19042
  url.question.window != null || url.question.compare != null);
19042
19043
  const { def } = useDrillDefinition(requested ? source : null);
@@ -23005,7 +23006,7 @@ function SortPanel({
23005
23006
  }
23006
23007
 
23007
23008
  // src/Grid.tsx
23008
- import { pageSortsFor, thenSortsOf } from "@ai-matrx/records/first-page";
23009
+ import { pageSortFor as pageSortFor2, pageSortsFor, thenSortsOf } from "@ai-matrx/records/first-page";
23009
23010
 
23010
23011
  // src/gridValueFilter.ts
23011
23012
  import { useMemo as useMemo32, useRef as useRef31 } from "react";
@@ -24788,10 +24789,17 @@ function GridBody({
24788
24789
  return viewSorts[0]?.field === seatedSort.id ? thenSortsOf(viewSorts, list, seatedSort.id, unsortable) : [];
24789
24790
  }, [seatedSort, manual, fields.data, heldThen, viewSorts]);
24790
24791
  const thenKey = JSON.stringify(thenSorts);
24792
+ const groupThenKeys = rowGroupKey ? (presentation.grouping?.then ?? []).map((t) => t.field).join("|") : "";
24791
24793
  const pageSort = useMemo38(
24792
- () => storePaged ? groupedPageSort(fields.data ?? [], rowGroupKey, pageSortsFor(fields.data ?? [], seatedSort, thenSorts)) : [],
24794
+ () => {
24795
+ if (!storePaged) return [];
24796
+ const sorted = groupedPageSort(fields.data ?? [], rowGroupKey, pageSortsFor(fields.data ?? [], seatedSort, thenSorts));
24797
+ if (!rowGroupKey || groupThenKeys === "") return sorted;
24798
+ const inner2 = groupThenKeys.split("|").flatMap((key) => pageSortFor2(fields.data ?? [], { id: key, direction: "asc" }));
24799
+ return [...sorted.slice(0, 1), ...inner2, ...sorted.slice(1).filter((s) => !inner2.some((i) => i.field === s.field))];
24800
+ },
24793
24801
  // eslint-disable-next-line react-hooks/exhaustive-deps -- thenKey stands for thenSorts
24794
- [storePaged, fields.data, seatedSort, rowGroupKey, thenKey]
24802
+ [storePaged, fields.data, seatedSort, rowGroupKey, thenKey, groupThenKeys]
24795
24803
  );
24796
24804
  const fullSorts = useMemo38(
24797
24805
  () => seatedSort ? [{ field: seatedSort.id, direction: seatedSort.direction }, ...thenSorts] : [],
@@ -25994,12 +26002,15 @@ function GridBody({
25994
26002
  if (field2 === null && !onPresentationChange) return null;
25995
26003
  const rowsGrouped = merged;
25996
26004
  const aggregates = rowsGrouped ? void 0 : view && Object.keys(view.aggregates ?? {}).length > 0 ? view.aggregates : field2 ? { [field2]: { kind: "count" } } : void 0;
25997
- const facts = rowsGrouped ? groupFactsFor(groupFacts, fields.data ?? [], chosenSummaries) : void 0;
26005
+ const topFacts = rowsGrouped ? groupFactsFor(groupFacts, fields.data ?? [], chosenSummaries) : void 0;
26006
+ const facts = topFacts ? (group) => group.ancestors ? void 0 : topFacts(group) : void 0;
26007
+ const thenKeys = rowsGrouped ? (view?.then ?? []).map((t) => t.field) : [];
25998
26008
  return {
25999
26009
  columnId: field2,
26000
26010
  rowNoun: "record",
26011
+ ...thenKeys.length > 0 ? { thenColumnIds: thenKeys } : {},
26001
26012
  ...aggregates ? { aggregates } : {},
26002
- ...rowsGrouped ? { renderLabel: groupLabel2, order: "first-seen", emptyLabel: "No value" } : {},
26013
+ ...rowsGrouped ? { renderLabel: (group) => group.ancestors ? void 0 : groupLabel2(group), order: "first-seen", emptyLabel: "No value" } : {},
26003
26014
  ...facts ? { groupFacts: facts } : {},
26004
26015
  ...!rowsGrouped && view?.order ? { order: view.order } : {},
26005
26016
  ...view?.collapsed ? { collapsed: view.collapsed } : {},
@@ -26020,6 +26031,15 @@ function GridBody({
26020
26031
  }
26021
26032
  });
26022
26033
  },
26034
+ // NESTED GROUPS: the second and third level are the view's `grouping.then` (the store allows three levels).
26035
+ ...rowsGrouped ? {
26036
+ onThenColumnIdsChange: (ids) => {
26037
+ const current = presentation.grouping;
26038
+ if (!current) return;
26039
+ const { then: _was, collapsed: _shut, ...rest } = current;
26040
+ writeLook({ ...presentation, grouping: ids.length > 0 ? { ...rest, then: ids.slice(0, 2).map((field3) => ({ field: field3 })) } : rest });
26041
+ }
26042
+ } : {},
26023
26043
  onCollapsedChange: (collapsed) => {
26024
26044
  const current = presentation.grouping;
26025
26045
  if (!current) return;
@@ -34842,6 +34862,9 @@ function packRows(bars) {
34842
34862
  return { ...bar, row };
34843
34863
  });
34844
34864
  }
34865
+ function shortDay(day2) {
34866
+ return dayAt(day2).toLocaleDateString(void 0, { month: "short", day: "numeric" });
34867
+ }
34845
34868
  function windowStart(anchor, zoom, firstDay) {
34846
34869
  const from = dayAt(addDays(anchor, -WINDOW[zoom].lead));
34847
34870
  if (zoom === "day" || zoom === "week") from.setDate(from.getDate() - daysSinceWeekStart(from.getDay(), firstDay));
@@ -35179,7 +35202,7 @@ function TimelineView({
35179
35202
  try {
35180
35203
  const make = async (current, key, label) => {
35181
35204
  if (current) return current.key;
35182
- const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label, type: "date" } });
35205
+ const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label, type: "datetime", kind: "date" } });
35183
35206
  if (!made.ok) {
35184
35207
  moves.say(refusalSentence(made.error));
35185
35208
  return null;
@@ -35700,8 +35723,8 @@ function TimelineView({
35700
35723
  const slip = slipDays(baselineOf(b.p.row)?.last ?? null, at.last);
35701
35724
  return /* @__PURE__ */ jsxs109("div", { "data-timeline-list-row": b.p.row.id, className: "flex items-center gap-1 px-1.5 text-xs", style: { height: ROW_PX }, children: [
35702
35725
  /* @__PURE__ */ jsx120("button", { type: "button", className: "min-w-0 flex-1 truncate text-left hover:underline", onClick: () => onOpenRecord?.(b.p.row.id), children: titleOf(b.p.row) }),
35703
- /* @__PURE__ */ jsx120("span", { className: "w-12 shrink-0 tabular-nums text-muted-foreground", children: calendarDayLabel(at.first) }),
35704
- /* @__PURE__ */ jsx120("span", { className: "w-12 shrink-0 tabular-nums text-muted-foreground", children: calendarDayLabel(at.last) }),
35726
+ /* @__PURE__ */ jsx120("span", { className: "w-12 shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: shortDay(at.first) }),
35727
+ /* @__PURE__ */ jsx120("span", { className: "w-12 shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: shortDay(at.last) }),
35705
35728
  /* @__PURE__ */ jsxs109("span", { className: "w-14 shrink-0 text-right tabular-nums", title: slip !== null ? slipWords(slip) : void 0, children: [
35706
35729
  daysBetween(at.first, at.last) + 1,
35707
35730
  "d",
@@ -38982,6 +39005,7 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
38982
39005
  return (initialViews.find((v) => v.id === activeViewId) ?? defaultViewOf(initialViews) ?? initialViews[0]).id;
38983
39006
  });
38984
39007
  const readOnMount = useRef50(initialViews === void 0);
39008
+ const pendingPick = useRef50(null);
38985
39009
  const [naming, setNaming] = useState109(false);
38986
39010
  const [draftName, setDraftName] = useState109("");
38987
39011
  const [open, setOpen] = useState109(false);
@@ -39058,7 +39082,9 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39058
39082
  }, [load]);
39059
39083
  useEffect89(() => {
39060
39084
  if (!views || views.length === 0) return;
39061
- const chosen = views.find((v) => v.id === (activeViewId ?? active)) ?? defaultViewOf(views) ?? views[0];
39085
+ const wanted = pendingPick.current;
39086
+ pendingPick.current = null;
39087
+ const chosen = views.find((v) => v.id === (wanted ?? activeViewId ?? active)) ?? defaultViewOf(views) ?? views[0];
39062
39088
  if (chosen.id !== active) setActive(chosen.id);
39063
39089
  onActiveView?.(chosen);
39064
39090
  }, [views, activeViewId]);
@@ -39073,6 +39099,7 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39073
39099
  setNamingPersonal(false);
39074
39100
  setDraftName("");
39075
39101
  setActive(written.data);
39102
+ pendingPick.current = written.data;
39076
39103
  await load();
39077
39104
  }
39078
39105
  async function rename(view, name) {
@@ -39143,6 +39170,7 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39143
39170
  return;
39144
39171
  }
39145
39172
  setActive(written.data);
39173
+ pendingPick.current = written.data;
39146
39174
  await load();
39147
39175
  }
39148
39176
  async function archive(view) {