@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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.115.38
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/records-ui/v0.115.37..npm/records-ui/v0.115.38 -- apps/shared/records-ui`).
7
+ No source changes intended and no consumer action required.
8
+
3
9
  ## 0.115.36
4
10
 
5
11
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/dist/index.cjs CHANGED
@@ -13867,7 +13867,7 @@ function SplitRecordDialog({ tableId, record, document: document2, open, onOpenC
13867
13867
  let madeName = recordNameIn(table.data ?? null, madeDoc, "New record");
13868
13868
  if (titleKey !== null && !titleHeld) {
13869
13869
  const named = `${record.name} (split)`;
13870
- const renamed = await client.recordUpdate({ record_id: created, patch: { [titleKey]: named } });
13870
+ const renamed = await (0, recordVersions_exports.updateRecordAt)(client, { record_id: created, patch: { [titleKey]: named }, version: await (0, recordVersions_exports.readVersionNow)(client, created) });
13871
13871
  if (renamed.ok) {
13872
13872
  madeName = named;
13873
13873
  onChanged?.();
@@ -19386,7 +19386,8 @@ function useGridDrillQuestion(args) {
19386
19386
  const source = (0, import_react112.useMemo)(() => ({ kind: "table", id: tableId }), [tableId]);
19387
19387
  const saved = (0, import_react112.useMemo)(() => questionFromGrouping(presentation.grouping), [presentation.grouping]);
19388
19388
  const url = (0, import_data_table14.useDrillUrlState)({ fallback: saved });
19389
- 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
19389
+ const requested = args.enabled && // Up to three levels are ROWS under nested headers on the merged grid (Airtable's group levels).
19390
+ (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
19390
19391
  // yet has them UNDEFINED, and `undefined !== null` asked for drill metadata on every plain grid.
19391
19392
  url.question.window != null || url.question.compare != null);
19392
19393
  const { def } = useDrillDefinition(requested ? source : null);
@@ -25059,10 +25060,17 @@ function GridBody({
25059
25060
  return viewSorts[0]?.field === seatedSort.id ? (0, import_first_page8.thenSortsOf)(viewSorts, list, seatedSort.id, unsortable) : [];
25060
25061
  }, [seatedSort, manual, fields.data, heldThen, viewSorts]);
25061
25062
  const thenKey = JSON.stringify(thenSorts);
25063
+ const groupThenKeys = rowGroupKey ? (presentation.grouping?.then ?? []).map((t) => t.field).join("|") : "";
25062
25064
  const pageSort = (0, import_react140.useMemo)(
25063
- () => storePaged ? (0, import_first_page6.groupedPageSort)(fields.data ?? [], rowGroupKey, (0, import_first_page8.pageSortsFor)(fields.data ?? [], seatedSort, thenSorts)) : [],
25065
+ () => {
25066
+ if (!storePaged) return [];
25067
+ const sorted = (0, import_first_page6.groupedPageSort)(fields.data ?? [], rowGroupKey, (0, import_first_page8.pageSortsFor)(fields.data ?? [], seatedSort, thenSorts));
25068
+ if (!rowGroupKey || groupThenKeys === "") return sorted;
25069
+ const inner2 = groupThenKeys.split("|").flatMap((key) => (0, import_first_page8.pageSortFor)(fields.data ?? [], { id: key, direction: "asc" }));
25070
+ return [...sorted.slice(0, 1), ...inner2, ...sorted.slice(1).filter((s) => !inner2.some((i) => i.field === s.field))];
25071
+ },
25064
25072
  // eslint-disable-next-line react-hooks/exhaustive-deps -- thenKey stands for thenSorts
25065
- [storePaged, fields.data, seatedSort, rowGroupKey, thenKey]
25073
+ [storePaged, fields.data, seatedSort, rowGroupKey, thenKey, groupThenKeys]
25066
25074
  );
25067
25075
  const fullSorts = (0, import_react140.useMemo)(
25068
25076
  () => seatedSort ? [{ field: seatedSort.id, direction: seatedSort.direction }, ...thenSorts] : [],
@@ -26265,12 +26273,15 @@ function GridBody({
26265
26273
  if (field2 === null && !onPresentationChange) return null;
26266
26274
  const rowsGrouped = merged;
26267
26275
  const aggregates = rowsGrouped ? void 0 : view && Object.keys(view.aggregates ?? {}).length > 0 ? view.aggregates : field2 ? { [field2]: { kind: "count" } } : void 0;
26268
- const facts = rowsGrouped ? groupFactsFor(groupFacts, fields.data ?? [], chosenSummaries) : void 0;
26276
+ const topFacts = rowsGrouped ? groupFactsFor(groupFacts, fields.data ?? [], chosenSummaries) : void 0;
26277
+ const facts = topFacts ? (group) => group.ancestors ? void 0 : topFacts(group) : void 0;
26278
+ const thenKeys = rowsGrouped ? (view?.then ?? []).map((t) => t.field) : [];
26269
26279
  return {
26270
26280
  columnId: field2,
26271
26281
  rowNoun: "record",
26282
+ ...thenKeys.length > 0 ? { thenColumnIds: thenKeys } : {},
26272
26283
  ...aggregates ? { aggregates } : {},
26273
- ...rowsGrouped ? { renderLabel: groupLabel2, order: "first-seen", emptyLabel: "No value" } : {},
26284
+ ...rowsGrouped ? { renderLabel: (group) => group.ancestors ? void 0 : groupLabel2(group), order: "first-seen", emptyLabel: "No value" } : {},
26274
26285
  ...facts ? { groupFacts: facts } : {},
26275
26286
  ...!rowsGrouped && view?.order ? { order: view.order } : {},
26276
26287
  ...view?.collapsed ? { collapsed: view.collapsed } : {},
@@ -26291,6 +26302,15 @@ function GridBody({
26291
26302
  }
26292
26303
  });
26293
26304
  },
26305
+ // NESTED GROUPS: the second and third level are the view's `grouping.then` (the store allows three levels).
26306
+ ...rowsGrouped ? {
26307
+ onThenColumnIdsChange: (ids) => {
26308
+ const current = presentation.grouping;
26309
+ if (!current) return;
26310
+ const { then: _was, collapsed: _shut, ...rest } = current;
26311
+ writeLook({ ...presentation, grouping: ids.length > 0 ? { ...rest, then: ids.slice(0, 2).map((field3) => ({ field: field3 })) } : rest });
26312
+ }
26313
+ } : {},
26294
26314
  onCollapsedChange: (collapsed) => {
26295
26315
  const current = presentation.grouping;
26296
26316
  if (!current) return;
@@ -35002,6 +35022,9 @@ function packRows(bars) {
35002
35022
  return { ...bar, row };
35003
35023
  });
35004
35024
  }
35025
+ function shortDay(day2) {
35026
+ return dayAt(day2).toLocaleDateString(void 0, { month: "short", day: "numeric" });
35027
+ }
35005
35028
  function windowStart(anchor, zoom, firstDay) {
35006
35029
  const from = dayAt(addDays(anchor, -WINDOW[zoom].lead));
35007
35030
  if (zoom === "day" || zoom === "week") from.setDate(from.getDate() - daysSinceWeekStart(from.getDay(), firstDay));
@@ -35339,7 +35362,7 @@ function TimelineView({
35339
35362
  try {
35340
35363
  const make = async (current, key, label) => {
35341
35364
  if (current) return current.key;
35342
- const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label, type: "date" } });
35365
+ const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label, type: "datetime", kind: "date" } });
35343
35366
  if (!made.ok) {
35344
35367
  moves.say(refusalSentence(made.error));
35345
35368
  return null;
@@ -35860,8 +35883,8 @@ function TimelineView({
35860
35883
  const slip = slipDays(baselineOf(b.p.row)?.last ?? null, at.last);
35861
35884
  return /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("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: [
35862
35885
  /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("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) }),
35863
- /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 tabular-nums text-muted-foreground", children: calendarDayLabel(at.first) }),
35864
- /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 tabular-nums text-muted-foreground", children: calendarDayLabel(at.last) }),
35886
+ /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: shortDay(at.first) }),
35887
+ /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: shortDay(at.last) }),
35865
35888
  /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("span", { className: "w-14 shrink-0 text-right tabular-nums", title: slip !== null ? slipWords(slip) : void 0, children: [
35866
35889
  daysBetween(at.first, at.last) + 1,
35867
35890
  "d",
@@ -39110,6 +39133,7 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39110
39133
  return (initialViews.find((v) => v.id === activeViewId) ?? (0, import_views2.defaultViewOf)(initialViews) ?? initialViews[0]).id;
39111
39134
  });
39112
39135
  const readOnMount = (0, import_react230.useRef)(initialViews === void 0);
39136
+ const pendingPick = (0, import_react230.useRef)(null);
39113
39137
  const [naming, setNaming] = (0, import_react230.useState)(false);
39114
39138
  const [draftName, setDraftName] = (0, import_react230.useState)("");
39115
39139
  const [open, setOpen] = (0, import_react230.useState)(false);
@@ -39186,7 +39210,9 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39186
39210
  }, [load]);
39187
39211
  (0, import_react230.useEffect)(() => {
39188
39212
  if (!views || views.length === 0) return;
39189
- const chosen = views.find((v) => v.id === (activeViewId ?? active)) ?? (0, import_views2.defaultViewOf)(views) ?? views[0];
39213
+ const wanted = pendingPick.current;
39214
+ pendingPick.current = null;
39215
+ const chosen = views.find((v) => v.id === (wanted ?? activeViewId ?? active)) ?? (0, import_views2.defaultViewOf)(views) ?? views[0];
39190
39216
  if (chosen.id !== active) setActive(chosen.id);
39191
39217
  onActiveView?.(chosen);
39192
39218
  }, [views, activeViewId]);
@@ -39201,6 +39227,7 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39201
39227
  setNamingPersonal(false);
39202
39228
  setDraftName("");
39203
39229
  setActive(written.data);
39230
+ pendingPick.current = written.data;
39204
39231
  await load();
39205
39232
  }
39206
39233
  async function rename(view, name) {
@@ -39271,6 +39298,7 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39271
39298
  return;
39272
39299
  }
39273
39300
  setActive(written.data);
39301
+ pendingPick.current = written.data;
39274
39302
  await load();
39275
39303
  }
39276
39304
  async function archive(view) {