@ai-matrx/records-ui 0.104.2 → 0.105.1

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.d.cts CHANGED
@@ -3,8 +3,8 @@ import { ReactNode, KeyboardEvent, ReactElement, ComponentType, RefObject, SVGAt
3
3
  import * as _ai_matrx_records from '@ai-matrx/records';
4
4
  import { Uuid, RowAction, Field, RowActionStep, RecordScopeContext, EnrichCell, RecordsError, RecordDocument, Table, ReadRow, RecordRead, PermissionLevel, AggregateFilter, RelationDisplay, WriteConflict, RecordsErrorCode, TableDecorations, RecordFilter, RuleExpression, RecordsResult, SavedViewRow, StoreFilter as StoreFilter$1, ImportRun, DeclarableFieldKind, NewerFieldKind, ParityFieldType, NewFieldDeclaration, ChoiceRehome, FieldOptionEdit, StoredRecord, ChoiceNudge, HiddenFieldNotice, ValueEnvelope, ChecklistRequirementKind, ContextPolicy, WorkDueState, FieldSensitivity, StageRuleOnFail, SubscriptionCadence, WorkApprovalState, WorkInboxKind, FieldKind, ArchiveLane, ArchivedRow, WorkInboxView, WorkInboxItem, PortalAccent, FormSummary, PortalCard, PortalPrincipal, PortalPreviewRow, PublicPicture, PortalStyle, MySubscription, DashboardBlockKind, AggregateBucket, AggregateMeasure, AggregateCompare, DashboardTarget, DashboardBlock, DashboardSummary, AggregateGroupValue, DocTemplateRow, DocRenderRow, QuietHours, DashboardBlockResult, ChecklistRunStep, BookingSummary, CaptureSheetFace, CaptureField, AnonTokenBinding, RecordsConfig, RecordsActor, RecordsDataSource, TableDuplicated, HistoryActor, FieldHistoryEntry, DrillDefinition, DrillSource, TableDuplicateProgress, TableArchiveProgress } from '@ai-matrx/records';
5
5
  import { ReversibleAnnouncement } from '@ai-matrx/kit/reversible';
6
- import { W as WhatYouMayDo, T as TableActionHost, O as ObjectAction, a as ObjectActionIcon } from './objectActions-XkhxU-DP.cjs';
7
- export { A as ACTION_CHECKING_ACCESS_REASON, b as ACTION_NOT_HERE_REASON, c as ACTION_NO_ACCESS_REASON, d as ACTION_PLATFORM_TABLE_REASON, B as BuiltOnDestination, C as Capability, D as DEFAULT_ACTION_ORIGIN, K as KERNEL_REASON, L as LEVEL_WORD, N as NOT_ANSWERED_YET, e as OBJECT_ACTION_GROUPS, f as ObjectActionDropdownEntry, g as ObjectActionGroup, h as ObjectActionGroupDef, i as ObjectActionSection, S as STANDARD_VERBS, j as STRIP_FEATURE_ROWS, k as StandardVerbId, l as StripAndRows, m as TableActionSubject, n as TableActionsInput, o as dropdownActionIds, p as dropdownActions, q as groupObjectActions, r as levelNeededFor, s as rightsReason, t as tableActions, u as tableLink, v as toDropdownEntries, w as toStripAndRows, x as whatYouMayDo, y as whatYouMayDoWithTable, z as withExtensions } from './objectActions-XkhxU-DP.cjs';
6
+ import { W as WhatYouMayDo, T as TableActionHost, O as ObjectAction, a as ObjectActionIcon } from './objectActions-B7AUBkcl.cjs';
7
+ export { A as ACTION_CHECKING_ACCESS_REASON, b as ACTION_NOT_HERE_REASON, c as ACTION_NO_ACCESS_REASON, d as ACTION_PLATFORM_TABLE_REASON, B as BuiltOnDestination, C as Capability, D as DEFAULT_ACTION_ORIGIN, K as KERNEL_REASON, L as LEVEL_WORD, N as NOT_ANSWERED_YET, e as OBJECT_ACTION_GROUPS, f as ObjectActionDropdownEntry, g as ObjectActionGroup, h as ObjectActionGroupDef, i as ObjectActionSection, S as STANDARD_VERBS, j as STRIP_FEATURE_ROWS, k as StandardVerbId, l as StripAndRows, m as TableActionSubject, n as TableActionsInput, o as dropdownActionIds, p as dropdownActions, q as groupObjectActions, r as levelNeededFor, s as rightsReason, t as tableActions, u as tableLink, v as toDropdownEntries, w as toStripAndRows, x as whatYouMayDo, y as whatYouMayDoWithTable, z as withExtensions } from './objectActions-B7AUBkcl.cjs';
8
8
  import { Uuid as Uuid$1, Table as Table$1, Field as Field$1, ReadRow as ReadRow$1, StoreFilter, useRecordsClient } from '@ai-matrx/records/react';
9
9
  import { RecordsClient, ParsedImport, NewFieldSpec } from '@ai-matrx/records/core';
10
10
  export { DEFAULT_FIELDS, DeclareResult, NewFieldSpec, NewTableSpec, addFields, declareTable, fieldDeclarationFor, tokenFor } from '@ai-matrx/records/core';
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ import { ReactNode, KeyboardEvent, ReactElement, ComponentType, RefObject, SVGAt
3
3
  import * as _ai_matrx_records from '@ai-matrx/records';
4
4
  import { Uuid, RowAction, Field, RowActionStep, RecordScopeContext, EnrichCell, RecordsError, RecordDocument, Table, ReadRow, RecordRead, PermissionLevel, AggregateFilter, RelationDisplay, WriteConflict, RecordsErrorCode, TableDecorations, RecordFilter, RuleExpression, RecordsResult, SavedViewRow, StoreFilter as StoreFilter$1, ImportRun, DeclarableFieldKind, NewerFieldKind, ParityFieldType, NewFieldDeclaration, ChoiceRehome, FieldOptionEdit, StoredRecord, ChoiceNudge, HiddenFieldNotice, ValueEnvelope, ChecklistRequirementKind, ContextPolicy, WorkDueState, FieldSensitivity, StageRuleOnFail, SubscriptionCadence, WorkApprovalState, WorkInboxKind, FieldKind, ArchiveLane, ArchivedRow, WorkInboxView, WorkInboxItem, PortalAccent, FormSummary, PortalCard, PortalPrincipal, PortalPreviewRow, PublicPicture, PortalStyle, MySubscription, DashboardBlockKind, AggregateBucket, AggregateMeasure, AggregateCompare, DashboardTarget, DashboardBlock, DashboardSummary, AggregateGroupValue, DocTemplateRow, DocRenderRow, QuietHours, DashboardBlockResult, ChecklistRunStep, BookingSummary, CaptureSheetFace, CaptureField, AnonTokenBinding, RecordsConfig, RecordsActor, RecordsDataSource, TableDuplicated, HistoryActor, FieldHistoryEntry, DrillDefinition, DrillSource, TableDuplicateProgress, TableArchiveProgress } from '@ai-matrx/records';
5
5
  import { ReversibleAnnouncement } from '@ai-matrx/kit/reversible';
6
- import { W as WhatYouMayDo, T as TableActionHost, O as ObjectAction, a as ObjectActionIcon } from './objectActions-XkhxU-DP.js';
7
- export { A as ACTION_CHECKING_ACCESS_REASON, b as ACTION_NOT_HERE_REASON, c as ACTION_NO_ACCESS_REASON, d as ACTION_PLATFORM_TABLE_REASON, B as BuiltOnDestination, C as Capability, D as DEFAULT_ACTION_ORIGIN, K as KERNEL_REASON, L as LEVEL_WORD, N as NOT_ANSWERED_YET, e as OBJECT_ACTION_GROUPS, f as ObjectActionDropdownEntry, g as ObjectActionGroup, h as ObjectActionGroupDef, i as ObjectActionSection, S as STANDARD_VERBS, j as STRIP_FEATURE_ROWS, k as StandardVerbId, l as StripAndRows, m as TableActionSubject, n as TableActionsInput, o as dropdownActionIds, p as dropdownActions, q as groupObjectActions, r as levelNeededFor, s as rightsReason, t as tableActions, u as tableLink, v as toDropdownEntries, w as toStripAndRows, x as whatYouMayDo, y as whatYouMayDoWithTable, z as withExtensions } from './objectActions-XkhxU-DP.js';
6
+ import { W as WhatYouMayDo, T as TableActionHost, O as ObjectAction, a as ObjectActionIcon } from './objectActions-B7AUBkcl.js';
7
+ export { A as ACTION_CHECKING_ACCESS_REASON, b as ACTION_NOT_HERE_REASON, c as ACTION_NO_ACCESS_REASON, d as ACTION_PLATFORM_TABLE_REASON, B as BuiltOnDestination, C as Capability, D as DEFAULT_ACTION_ORIGIN, K as KERNEL_REASON, L as LEVEL_WORD, N as NOT_ANSWERED_YET, e as OBJECT_ACTION_GROUPS, f as ObjectActionDropdownEntry, g as ObjectActionGroup, h as ObjectActionGroupDef, i as ObjectActionSection, S as STANDARD_VERBS, j as STRIP_FEATURE_ROWS, k as StandardVerbId, l as StripAndRows, m as TableActionSubject, n as TableActionsInput, o as dropdownActionIds, p as dropdownActions, q as groupObjectActions, r as levelNeededFor, s as rightsReason, t as tableActions, u as tableLink, v as toDropdownEntries, w as toStripAndRows, x as whatYouMayDo, y as whatYouMayDoWithTable, z as withExtensions } from './objectActions-B7AUBkcl.js';
8
8
  import { Uuid as Uuid$1, Table as Table$1, Field as Field$1, ReadRow as ReadRow$1, StoreFilter, useRecordsClient } from '@ai-matrx/records/react';
9
9
  import { RecordsClient, ParsedImport, NewFieldSpec } from '@ai-matrx/records/core';
10
10
  export { DEFAULT_FIELDS, DeclareResult, NewFieldSpec, NewTableSpec, addFields, declareTable, fieldDeclarationFor, tokenFor } from '@ai-matrx/records/core';
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { atLeast } from "@ai-matrx/records";
9
9
  var LEVEL_WORD = {
10
10
  viewer: "Viewer",
11
11
  commenter: "Commenter",
12
+ edit_content: "Content editor",
12
13
  editor: "Editor",
13
14
  admin: "Admin"
14
15
  };
@@ -16,8 +17,12 @@ var NEEDS = {
16
17
  read: "viewer",
17
18
  // custom.io_comment_write
18
19
  comment: "commenter",
19
- // custom.record_update / custom.record_write
20
- write: "editor",
20
+ // custom.record_update / custom.record_write — `edit_content` changes rows and page content;
21
+ // columns, views and settings (structure) stay with admin below, and sharing with admin.
22
+ write: "edit_content",
23
+ // custom.view_designate / view_declare / migrate_merge / record_restore — all ask `editor`: more than
24
+ // changing content (`edit_content`), less than changing columns (`admin`).
25
+ organise: "editor",
21
26
  // custom.record_delete
22
27
  remove: "editor",
23
28
  // custom.share_grant — passing your access on is an administrator's right
@@ -38,6 +43,7 @@ function sentenceFor(what, level) {
38
43
  read: "open this",
39
44
  comment: "leave a comment",
40
45
  write: "change anything here",
46
+ organise: "organise this",
41
47
  remove: "delete this",
42
48
  share: "pass this on to somebody else",
43
49
  structure: "change the columns of this table"
@@ -52,6 +58,7 @@ function whatYouMayDo(level, known = true) {
52
58
  read: may("read"),
53
59
  comment: may("comment"),
54
60
  write: may("write"),
61
+ organise: may("organise"),
55
62
  remove: may("remove"),
56
63
  share: may("share"),
57
64
  structure: may("structure"),
@@ -24744,6 +24751,7 @@ function createEntityRealtime(options = {}) {
24744
24751
  }
24745
24752
 
24746
24753
  // ../entity-data/src/port/port.ts
24754
+ import { isUuidShape as isUuidShape3 } from "@ai-matrx/kit/uuid";
24747
24755
  import { mintOpId } from "@ai-matrx/records";
24748
24756
 
24749
24757
  // ../entity-data/src/core/wire.ts
@@ -24844,8 +24852,6 @@ function toColumns(wire) {
24844
24852
  }
24845
24853
 
24846
24854
  // ../entity-data/src/port/port.ts
24847
- var UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
24848
- var isUuidShape3 = (value) => typeof value === "string" && UUID_SHAPE.test(value);
24849
24855
  function toWireValue(value) {
24850
24856
  if (isRef(value)) return value.id;
24851
24857
  if (Array.isArray(value) && value.length > 0 && value.every(isRef)) {
@@ -25444,6 +25450,7 @@ import { useFields as useFields10, useRecords as useRecords6, useRecordsClient a
25444
25450
  import { exportCsv, exportXlsx, wholeValueOf as wholeValueOf5, withWholeValues } from "@ai-matrx/records/core";
25445
25451
 
25446
25452
  // src/viewExport.ts
25453
+ import { formatCount as formatCount3 } from "@ai-matrx/kit/format";
25447
25454
  var VIEW_EXPORT_PAGE = 500;
25448
25455
  var VIEW_EXPORT_CEILING = 5e3;
25449
25456
  function viewColumns(fields, presentation) {
@@ -25482,7 +25489,7 @@ async function readViewRows(client, tableId, fields, view, ceiling = VIEW_EXPORT
25482
25489
  }
25483
25490
  }
25484
25491
  function cutWords(written) {
25485
- return `First ${written.toLocaleString("en-US")} rows only`;
25492
+ return `First ${formatCount3(written, { locale: "en-US" })} rows only`;
25486
25493
  }
25487
25494
 
25488
25495
  // src/ExportMenu.tsx
@@ -26650,7 +26657,7 @@ function tableActions(input) {
26650
26657
  // custom.view_designate asks editor on the table — `canDesignate` in TablePage.
26651
26658
  action(
26652
26659
  { id: "make-default", label: makeDefaultWords(host.layoutLabel), icon: "layout-grid", group: "manage", rank: 4 },
26653
- "write",
26660
+ "organise",
26654
26661
  input,
26655
26662
  bind(host.makeDefault, table)
26656
26663
  ),
@@ -27829,7 +27836,7 @@ function SaveToTable({ source, shapeIndex = 0, onOpenTable, onSaved, onClose, cl
27829
27836
  const levels = useMyLevels3(own3.map((t) => t.id));
27830
27837
  const writable = own3.filter((t) => {
27831
27838
  const level = levels.data?.[t.id];
27832
- return level === "editor" || level === "admin";
27839
+ return level === "edit_content" || level === "editor" || level === "admin";
27833
27840
  }).sort((a, b) => a.name.localeCompare(b.name));
27834
27841
  const [tableId, setTableId] = useState68("");
27835
27842
  const proposedName = shape?.name ?? source.title ?? "Saved table";
@@ -30206,7 +30213,7 @@ import {
30206
30213
  resolveRowColor as resolveRowColor4,
30207
30214
  ROW_TINT_CLASS as ROW_TINT_CLASS3
30208
30215
  } from "@ai-matrx/design-system/data-table";
30209
- import { formatCount as formatCount3 } from "@ai-matrx/kit/format";
30216
+ import { formatCount as formatCount4 } from "@ai-matrx/kit/format";
30210
30217
 
30211
30218
  // src/recordMoves.tsx
30212
30219
  import { useCallback as useCallback36, useEffect as useEffect69, useMemo as useMemo49, useRef as useRef43, useState as useState81 } from "react";
@@ -30473,10 +30480,10 @@ function recordActions(input) {
30473
30480
  input,
30474
30481
  copyText13 ? () => copyText13(url, record) : void 0
30475
30482
  ),
30476
- action2({ id: "duplicate", label: "Duplicate", icon: "copy", group: "organize", verb: "duplicate" }, "write", input, bind2(host.duplicate, record)),
30483
+ action2({ id: "duplicate", label: "Duplicate", icon: "copy", group: "organize", verb: "duplicate" }, "organise", input, bind2(host.duplicate, record)),
30477
30484
  action2(
30478
30485
  { id: "merge", label: "Merge with\u2026", icon: "git-merge", group: "organize" },
30479
- "write",
30486
+ "organise",
30480
30487
  input,
30481
30488
  bind2(host.merge, record)
30482
30489
  ),
@@ -34111,9 +34118,9 @@ function ViewPager({ shown: shown4, total, onMore, step: step2 }) {
34111
34118
  return /* @__PURE__ */ jsxs99("p", { className: "flex items-center gap-2 text-xs text-muted-foreground", "data-view-pager": "", children: [
34112
34119
  /* @__PURE__ */ jsxs99("span", { children: [
34113
34120
  "Showing ",
34114
- formatCount3(shown4),
34121
+ formatCount4(shown4),
34115
34122
  " of ",
34116
- formatCount3(total),
34123
+ formatCount4(total),
34117
34124
  " records."
34118
34125
  ] }),
34119
34126
  /* @__PURE__ */ jsxs99(Button67, { size: "sm", variant: "outline", onClick: onMore, children: [
@@ -34590,8 +34597,8 @@ function ArchivedView({
34590
34597
  onRestored?.(recordId);
34591
34598
  };
34592
34599
  const titleKey = table.data?.title_field ?? null;
34593
- const mayRestore = rights.write;
34594
- const whyNot = mayRestore ? "" : mayNotRestoreLine(rights.why("write"));
34600
+ const mayRestore = rights.organise;
34601
+ const whyNot = mayRestore ? "" : mayNotRestoreLine(rights.why("organise"));
34595
34602
  return /* @__PURE__ */ jsxs100("div", { className: cn56("flex min-h-0 flex-col gap-2", className), "data-testid": "archived-view", children: [
34596
34603
  /* @__PURE__ */ jsxs100("div", { className: "flex flex-wrap items-center gap-2", children: [
34597
34604
  /* @__PURE__ */ jsx110("span", { className: "text-sm font-medium", children: "Archived" }),
@@ -37952,7 +37959,7 @@ import {
37952
37959
  } from "@ai-matrx/records";
37953
37960
  import { mapPgError as mapPgError3 } from "@ai-matrx/records/core";
37954
37961
  import { cn as cn66 } from "@ai-matrx/design-system";
37955
- import { formatCount as formatCount4 } from "@ai-matrx/kit/format";
37962
+ import { formatCount as formatCount5 } from "@ai-matrx/kit/format";
37956
37963
 
37957
37964
  // src/linkWords.ts
37958
37965
  import { useEffect as useEffect85, useMemo as useMemo60, useState as useState98 } from "react";
@@ -38565,7 +38572,7 @@ function BigNumber({
38565
38572
  /* @__PURE__ */ jsx120("span", { className: "text-2xl font-semibold tabular-nums", children: pretty(total) }),
38566
38573
  windows ? /* @__PURE__ */ jsx120(Trend, { pct: block.totals?.change_pct, aimingUp: !!target, className: "text-sm" }) : null
38567
38574
  ] }),
38568
- /* @__PURE__ */ jsx120("span", { className: "text-xs text-muted-foreground", children: windows && typeof priorTotal === "number" ? `${windowName(windows.window, windows.period)} \xB7 ${pretty(priorTotal)} in ${windowName(windows.prior_window, windows.period)}` : `from ${formatCount4(records)} ${records === 1 ? "record" : "records"}` })
38575
+ /* @__PURE__ */ jsx120("span", { className: "text-xs text-muted-foreground", children: windows && typeof priorTotal === "number" ? `${windowName(windows.window, windows.period)} \xB7 ${pretty(priorTotal)} in ${windowName(windows.prior_window, windows.period)}` : `from ${formatCount5(records)} ${records === 1 ? "record" : "records"}` })
38569
38576
  ] });
38570
38577
  const ring = target && typeof target.progress === "number" && typeof target.value === "number" ? /* @__PURE__ */ jsxs110("span", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
38571
38578
  /* @__PURE__ */ jsxs110("span", { className: "text-right text-xs text-muted-foreground", children: [
@@ -38684,7 +38691,7 @@ var HEIGHT = CHART_PLOT_PX;
38684
38691
  function compactTick(value) {
38685
38692
  if (typeof value !== "number" || !Number.isFinite(value)) return String(value ?? "");
38686
38693
  if (Math.abs(value) < 1e3 && !Number.isInteger(value)) return String(Math.round(value * 10) / 10);
38687
- return formatCount4(value, { style: "compact" });
38694
+ return formatCount5(value, { style: "compact" });
38688
38695
  }
38689
38696
  function Drawing({
38690
38697
  kind,
@@ -38823,9 +38830,7 @@ function onlyWholeNumbers(rows) {
38823
38830
 
38824
38831
  // src/FormResultsPanel.tsx
38825
38832
  import { jsx as jsx121, jsxs as jsxs111 } from "react/jsx-runtime";
38826
- function numberBlock(title, value) {
38827
- return { title, kind: "number", group_by: [], measures: [{ op: "count" }], rows: [{ groups: {}, measures: { count: value }, row_count: 1 }] };
38828
- }
38833
+ var CHARTED_KINDS = /* @__PURE__ */ new Set(["select", "multi_select", "checkbox", "number", "currency", "percent", "member", "relation"]);
38829
38834
  function dropOffBlock(results, label) {
38830
38835
  return {
38831
38836
  title: "Reached each question",
@@ -38867,6 +38872,13 @@ function FormResultsPanel({ form, className }) {
38867
38872
  cancelled = true;
38868
38873
  };
38869
38874
  }, [client, form.id, round]);
38875
+ const charted = useMemo62(() => {
38876
+ const byKey = new Map((fields.data ?? []).map((f) => [f.key, f]));
38877
+ return (key) => {
38878
+ const field2 = byKey.get(key);
38879
+ return field2 ? CHARTED_KINDS.has(editorKindFor(field2)) : false;
38880
+ };
38881
+ }, [fields.data]);
38870
38882
  const label = useMemo62(() => {
38871
38883
  const byKey = new Map((fields.data ?? []).map((f) => [f.key, f]));
38872
38884
  const asks = new Map((form.questions ?? []).map((q) => [q.field, q.ask]));
@@ -38880,12 +38892,15 @@ function FormResultsPanel({ form, className }) {
38880
38892
  /* @__PURE__ */ jsx121("span", { className: "text-sm font-medium", children: "Results" }),
38881
38893
  /* @__PURE__ */ jsx121(Button77, { size: "sm", variant: "ghost", className: "ml-auto", onClick: () => setRound((n) => n + 1), children: "Refresh" })
38882
38894
  ] }),
38883
- /* @__PURE__ */ jsxs111("div", { className: "grid grid-cols-2 gap-2 @xl:grid-cols-4", children: [
38884
- /* @__PURE__ */ jsx121(ChartBlock, { block: numberBlock("Views", results.views), subject: form.subject }),
38885
- /* @__PURE__ */ jsx121(ChartBlock, { block: numberBlock("Starts", results.starts), subject: form.subject }),
38886
- /* @__PURE__ */ jsx121(ChartBlock, { block: numberBlock("Completions", results.completions), subject: form.subject }),
38887
- /* @__PURE__ */ jsx121(ChartBlock, { block: numberBlock("Completion rate %", results.completion_rate), subject: form.subject })
38888
- ] }),
38895
+ /* @__PURE__ */ jsx121("dl", { className: "grid grid-cols-2 gap-2 @xl:grid-cols-4", "data-records-form-kpis": "", children: [
38896
+ ["Views", results.views],
38897
+ ["Starts", results.starts],
38898
+ ["Completions", results.completions],
38899
+ ["Completion rate", results.completion_rate === null ? null : `${results.completion_rate}%`]
38900
+ ].map(([name, value]) => /* @__PURE__ */ jsxs111("div", { className: "flex flex-col gap-1 rounded-md border px-3 py-2", children: [
38901
+ /* @__PURE__ */ jsx121("dt", { className: "text-xs text-muted-foreground", children: name }),
38902
+ /* @__PURE__ */ jsx121("dd", { className: "text-2xl font-semibold tabular-nums", children: value ?? "\u2014" })
38903
+ ] }, name)) }),
38889
38904
  results.questions.length > 0 ? /* @__PURE__ */ jsx121(ChartBlock, { block: dropOffBlock(results, label), subject: form.subject }) : null,
38890
38905
  /* @__PURE__ */ jsx121("ul", { className: "flex flex-col gap-1 text-xs", "data-records-form-dropoff": "", children: results.questions.map((q) => /* @__PURE__ */ jsxs111("li", { className: "flex items-center gap-2", children: [
38891
38906
  /* @__PURE__ */ jsx121("span", { className: "min-w-0 flex-1 truncate", children: label(q.field_key) }),
@@ -38924,7 +38939,16 @@ function FormResultsPanel({ form, className }) {
38924
38939
  /* @__PURE__ */ jsx121("span", { className: "flex-1 truncate", children: h.value }),
38925
38940
  /* @__PURE__ */ jsx121("span", { className: "tabular-nums text-muted-foreground", children: h.count })
38926
38941
  ] }, `${h.key}:${h.value}`)) }) : null,
38927
- results.questions.filter((q) => q.answers.length > 0).map((q) => /* @__PURE__ */ jsx121(ChartBlock, { block: answersBlock(q, label(q.field_key)), subject: form.subject }, q.field_key))
38942
+ results.questions.filter((q) => q.answers.length > 0).map(
38943
+ (q) => charted(q.field_key) ? /* @__PURE__ */ jsx121(ChartBlock, { block: answersBlock(q, label(q.field_key)), subject: form.subject }, q.field_key) : /* @__PURE__ */ jsxs111("section", { className: "flex flex-col gap-1 rounded-md border px-3 py-2 text-xs", "data-records-form-text-answers": q.field_key, children: [
38944
+ /* @__PURE__ */ jsx121("span", { className: "font-medium", children: label(q.field_key) }),
38945
+ /* @__PURE__ */ jsxs111("span", { className: "text-muted-foreground", children: [
38946
+ q.answered,
38947
+ " answered"
38948
+ ] }),
38949
+ /* @__PURE__ */ jsx121("ul", { className: "flex flex-col gap-0.5", children: q.answers.map((a) => /* @__PURE__ */ jsx121("li", { className: "truncate", children: a.value }, a.value)) })
38950
+ ] }, q.field_key)
38951
+ )
38928
38952
  ] });
38929
38953
  }
38930
38954
 
@@ -41384,8 +41408,9 @@ function QuestionLogic({
41384
41408
  const jumps = question.jumps ?? [];
41385
41409
  const targets = jumpTargets(questions, index, endings, label);
41386
41410
  const points = question.points ?? {};
41387
- const rawOptions = field2?.options;
41388
- const choices = Array.isArray(rawOptions) ? rawOptions.filter((o) => typeof o === "string") : [];
41411
+ const choiceFields = field2 && isChoiceField(field2) ? [field2] : [];
41412
+ const options = useChoiceOptions(choiceFields, choiceFields.map((f) => f.key));
41413
+ const choices = field2 ? (options.get(field2.key) ?? []).map((o) => ({ key: o.key, label: o.label })) : [];
41389
41414
  const [answer, setAnswer] = useState108("");
41390
41415
  const setJump = (i, part) => onChange({ jumps: jumps.map((j, k) => k === i ? { ...j, ...part } : j) });
41391
41416
  return /* @__PURE__ */ jsxs121("div", { className: "col-span-2 flex flex-col gap-1.5 text-xs", "data-records-form-logic": question.field, children: [
@@ -41409,25 +41434,25 @@ function QuestionLogic({
41409
41434
  /* @__PURE__ */ jsxs121("div", { className: "flex flex-wrap items-center gap-2", children: [
41410
41435
  targets.length > 0 ? /* @__PURE__ */ jsx131(Button84, { size: "sm", variant: "outline", onClick: () => onChange({ jumps: [...jumps, { when: null, to: targetOf(targets[0].value) }] }), children: "Add a jump" }) : null,
41411
41436
  /* @__PURE__ */ jsx131("span", { className: "text-muted-foreground", children: "Points:" }),
41412
- (choices.length > 0 ? choices : Object.keys(points)).map((choice) => /* @__PURE__ */ jsxs121("label", { className: "flex items-center gap-1", children: [
41413
- /* @__PURE__ */ jsx131("span", { children: choice }),
41437
+ (choices.length > 0 ? choices : Object.keys(points).map((k) => ({ key: k, label: k }))).map((choice) => /* @__PURE__ */ jsxs121("label", { className: "flex items-center gap-1", children: [
41438
+ /* @__PURE__ */ jsx131("span", { children: choice.label }),
41414
41439
  /* @__PURE__ */ jsx131(
41415
41440
  BasicInput27,
41416
41441
  {
41417
41442
  className: "h-7 w-14 text-xs",
41418
41443
  inputMode: "decimal",
41419
- "aria-label": `Points for ${choice}`,
41420
- value: points[choice] ?? "",
41444
+ "aria-label": `Points for ${choice.label}`,
41445
+ value: points[choice.key] ?? "",
41421
41446
  onChange: (e) => {
41422
41447
  const next = { ...points };
41423
41448
  const n = Number(e.target.value);
41424
- if (e.target.value.trim() === "" || Number.isNaN(n)) delete next[choice];
41425
- else next[choice] = n;
41449
+ if (e.target.value.trim() === "" || Number.isNaN(n)) delete next[choice.key];
41450
+ else next[choice.key] = n;
41426
41451
  onChange({ points: Object.keys(next).length > 0 ? next : null });
41427
41452
  }
41428
41453
  }
41429
41454
  )
41430
- ] }, choice)),
41455
+ ] }, choice.key)),
41431
41456
  choices.length === 0 ? /* @__PURE__ */ jsxs121("span", { className: "flex items-center gap-1", children: [
41432
41457
  /* @__PURE__ */ jsx131(BasicInput27, { className: "h-7 w-28 text-xs", "aria-label": "Answer worth points", placeholder: "An answer", value: answer, onChange: (e) => setAnswer(e.target.value) }),
41433
41458
  /* @__PURE__ */ jsx131(
@@ -43731,6 +43756,8 @@ function recordsDataSource(client, fallbackSchema = "custom") {
43731
43756
  function makeRecordsDataSource(client, fallbackSchema) {
43732
43757
  const supabase = client;
43733
43758
  return {
43759
+ // PAGE-BUNDLE: the real adapter opens a table page with one `custom.table_page_bundle` call.
43760
+ opensInOneCall: true,
43734
43761
  async rpc(fn, args, options) {
43735
43762
  const schema = options?.schema ?? fallbackSchema;
43736
43763
  if (schema === "custom" && supabase.auth?.getSession && !await hasSession(supabase.auth.getSession)) {
@@ -46050,7 +46077,7 @@ import {
46050
46077
  import { onRecordChanged } from "@ai-matrx/records/core";
46051
46078
  import { BasicInput as BasicInput34, Button as Button96, Checkbox as Checkbox17, Skeleton as Skeleton37, cn as cn86 } from "@ai-matrx/design-system";
46052
46079
  import { Fragment as Fragment59, jsx as jsx145, jsxs as jsxs134 } from "react/jsx-runtime";
46053
- var EDIT_LEVELS = /* @__PURE__ */ new Set(["editor", "admin", "owner"]);
46080
+ var EDIT_LEVELS = /* @__PURE__ */ new Set(["edit_content", "editor", "admin", "owner"]);
46054
46081
  function PageScreen({
46055
46082
  pageId,
46056
46083
  newOnTable,
@@ -48275,6 +48302,7 @@ function TableReferenceDialog({
48275
48302
  }
48276
48303
 
48277
48304
  // src/TableDuplicate.tsx
48305
+ import { formatCount as formatCount6 } from "@ai-matrx/kit/format";
48278
48306
  import { useState as useState130 } from "react";
48279
48307
  import { tableShapeChanged as tableShapeChanged12, useRecordsClient as useRecordsClient95 } from "@ai-matrx/records/react";
48280
48308
  import { Button as Button105, Dialog as Dialog16, DialogContent as DialogContent16, DialogFooter as DialogFooter11, DialogHeader as DialogHeader16, DialogTitle as DialogTitle16, ErrorBox as ErrorBox8, Input as Input10, Switch as Switch5 } from "@ai-matrx/design-system";
@@ -48283,7 +48311,7 @@ function copyNameFor(name) {
48283
48311
  return `${name.trim() || "Table"} (copy)`;
48284
48312
  }
48285
48313
  function duplicateProgressWords(p) {
48286
- if (p.records && p.records.total > 0) return `Copying records \xB7 ${p.records.done.toLocaleString()} of ${p.records.total.toLocaleString()}`;
48314
+ if (p.records && p.records.total > 0) return `Copying records \xB7 ${formatCount6(p.records.done)} of ${formatCount6(p.records.total)}`;
48287
48315
  if (p.views.total > 0 && p.step === "views") return `Copying views \xB7 ${p.views.done} of ${p.views.total}`;
48288
48316
  return "Copying columns\u2026";
48289
48317
  }
@@ -48339,7 +48367,7 @@ function TableDuplicateDialog({ tableId, name, open, onOpenChange, onDuplicated
48339
48367
  " columns, ",
48340
48368
  phase.copy.copied.views,
48341
48369
  " views",
48342
- phase.copy.copied.withRecords ? `, ${phase.copy.copied.records.toLocaleString()} records` : "",
48370
+ phase.copy.copied.withRecords ? `, ${formatCount6(phase.copy.copied.records)} records` : "",
48343
48371
  "."
48344
48372
  ] }),
48345
48373
  phase.copy.notCopied.length > 0 ? /* @__PURE__ */ jsxs144("p", { className: "text-xs text-muted-foreground", children: [
@@ -49296,7 +49324,7 @@ function TablePage({
49296
49324
  const [designateRefused, setDesignateRefused] = useState133(null);
49297
49325
  const opensAs = view?.isDefault ? view.layout : null;
49298
49326
  const canDesignate = Boolean(
49299
- rights.write && view && layoutShowing && layoutShowing !== opensAs && storeKeepsLayout(layoutShowing)
49327
+ rights.organise && view && layoutShowing && layoutShowing !== opensAs && storeKeepsLayout(layoutShowing)
49300
49328
  );
49301
49329
  const layoutShowingLabel = layoutShowing ? LAYOUT_LABEL[layoutShowing] : "";
49302
49330
  const designate = async () => {
@@ -50004,6 +50032,7 @@ function usePublicReadOnly(client, organizationId, tableId, table, rights) {
50004
50032
  }
50005
50033
 
50006
50034
  // src/entityViews.tsx
50035
+ import { formatCount as formatCount7 } from "@ai-matrx/kit/format";
50007
50036
  import { TapTargetSearchGroup as TapTargetSearchGroup2, TooltipProvider } from "@ai-matrx/design-system";
50008
50037
  import { MatrxTableCardShowMore as MatrxTableCardShowMore3 } from "@ai-matrx/design-system/data-table";
50009
50038
  import { useEffect as useEffect114, useMemo as useMemo79, useState as useState134 } from "react";
@@ -50194,7 +50223,7 @@ function EntityTablePageBody({
50194
50223
  return /* @__PURE__ */ jsxs148("div", { className: cn96("flex min-w-0 flex-col gap-2", className), "data-records-entity-page": source.token, children: [
50195
50224
  presentation === "page" || boardable || entity.creatable ? /* @__PURE__ */ jsxs148("div", { className: "flex min-w-0 items-center gap-2", children: [
50196
50225
  presentation === "page" ? /* @__PURE__ */ jsx159("h2", { className: "truncate text-base font-semibold", children: entity.label ?? (entity.loading ? "Loading\u2026" : "Table") }) : null,
50197
- presentation === "page" ? /* @__PURE__ */ jsx159("span", { className: "text-xs tabular-nums text-muted-foreground", children: entity.loading || entity.total === null ? "" : entity.total.toLocaleString() }) : null,
50226
+ presentation === "page" ? /* @__PURE__ */ jsx159("span", { className: "text-xs tabular-nums text-muted-foreground", children: entity.loading || entity.total === null ? "" : formatCount7(entity.total) }) : null,
50198
50227
  /* @__PURE__ */ jsxs148("span", { className: "ml-auto flex items-center gap-1", children: [
50199
50228
  boardable ? /* @__PURE__ */ jsxs148(Fragment67, { children: [
50200
50229
  /* @__PURE__ */ jsx159(Button108, { size: "sm", variant: layout === "grid" ? "secondary" : "ghost", "aria-pressed": layout === "grid", onClick: () => choose("grid"), children: "Table" }),