@ai-matrx/records-ui 0.93.142 → 0.93.146

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.
@@ -42,12 +42,18 @@ declare function whatYouMayDoWithTable(table: Table | null | undefined, level: P
42
42
 
43
43
  /**
44
44
  * A Lucide icon NAME, kebab-case — the same currency `Table.icon` already uses.
45
- * Closed on purpose: each renderer maps every member to its own component, and a
45
+ * Closed on purpose: each renderer maps every member to its own glyph, and a
46
46
  * new member fails that renderer's typecheck until it is mapped.
47
47
  */
48
48
  type ObjectActionIcon = "folder-open" | "external-link" | "link" | "pencil" | "copy" | "folder-input" | "star" | "star-off" | "share-2" | "download" | "upload" | "columns-3" | "settings" | "history" | "blocks" | "file-text" | "calendar-clock" | "list-checks" | "bell" | "door-open" | "inbox" | "layout-dashboard" | "archive-restore" | "archive" | "link-2" | "layout-grid";
49
49
  /** The groups, in their one order. Separators fall out of group boundaries. */
50
50
  type ObjectActionGroup = "open" | "organize" | "share" | "manage" | "built-on" | "danger";
51
+ /**
52
+ * THE STANDARD VERBS every object's menu shares — what the icon strip draws. One
53
+ * per meaning; an object maps its action onto the verb, never a second "share".
54
+ */
55
+ type StandardVerbId = "open" | "open-new-tab" | "copy-link" | "rename" | "duplicate" | "move" | "favorite" | "share" | "export" | "import" | "settings" | "history" | "archive";
56
+ declare const STANDARD_VERBS: readonly StandardVerbId[];
51
57
  interface ObjectActionGroupDef {
52
58
  id: ObjectActionGroup;
53
59
  /** Present only on a group that renders as a submenu. */
@@ -64,6 +70,10 @@ interface ObjectAction {
64
70
  label: string;
65
71
  icon: ObjectActionIcon;
66
72
  group: ObjectActionGroup;
73
+ /** The standard verb this action IS (a strip icon). Absent = a feature row. */
74
+ verb?: StandardVerbId;
75
+ /** A feature row's place among the rows, 1 first. Ignored when `verb` is set. */
76
+ rank?: number;
67
77
  /** Display-only hint ("⌘D"). */
68
78
  shortcut?: string;
69
79
  destructive?: boolean;
@@ -101,14 +111,26 @@ interface TableActionHost {
101
111
  addColumn?: Handler;
102
112
  settings?: Handler;
103
113
  history?: Handler;
114
+ /** Make the layout on screen the table's default. Leave out when it already is. */
115
+ makeDefault?: Handler;
116
+ /** The layout on screen, for "Make Kanban the default". */
117
+ layoutLabel?: string;
104
118
  /** The "Built on it" destinations, one handler for all eight. */
105
119
  openBuiltOn?: (destination: BuiltOnDestination, table: TableActionSubject) => void;
106
120
  archive?: Handler;
107
121
  /**
108
- * ANOTHER LANE'S ENTRIES ("Link a record…", a hub tile's verbs). Return the
109
- * same ids whatever `rights` say — express rights as `disabledReason`. Each
110
- * entry lands at the END of its named group, in the order returned; `danger`
111
- * is refused (Archive is always last) and so is an id already in the list.
122
+ * Why an action whose handler is left out is unavailable here, by action id
123
+ * (≤ 60 chars) — e.g. `make-default: "Already the default"`. Unnamed ids say
124
+ * "Not available here". Never used when rights already refuse.
125
+ */
126
+ unavailableReasons?: Readonly<Record<string, string>>;
127
+ /**
128
+ * ANOTHER LANE'S ENTRIES ("Link a record…", a hub tile's verbs, a feature's own
129
+ * row such as "When a row changes, run an agent…"). Return the same ids whatever
130
+ * `rights` say — express rights as `disabledReason`. Each entry lands at the END
131
+ * of its named group, in the order returned. Refused, loudly: the `danger` group
132
+ * (Archive is always last), a group that does not exist, and an id already in
133
+ * the list.
112
134
  */
113
135
  extend?: (table: TableActionSubject, rights: WhatYouMayDo) => readonly ObjectAction[];
114
136
  }
@@ -127,14 +149,15 @@ declare const ACTION_PLATFORM_TABLE_REASON = "Platform tables can't be changed h
127
149
  /** Why `rights` refuse `what`, in one short line — or null when they allow it. */
128
150
  declare function rightsReason(rights: WhatYouMayDo, what: Capability, table?: TableActionSubject): string | null;
129
151
  /**
130
- * THE TABLE'S ACTIONS, in the one order. Same ids, same order, for every seat
131
- * and every host — only `disabledReason` varies.
152
+ * THE TABLE'S ACTIONS, in the one order. Same ids, same order, same verbs and
153
+ * ranks, for every seat and every host — only `disabledReason` varies.
132
154
  */
133
155
  declare function tableActions(input: TableActionsInput): ObjectAction[];
134
156
  /**
135
157
  * Another lane's entries, placed deterministically: each at the end of its
136
- * group, in the order given. Loud on the two mistakes that would break the
137
- * invariants — a `danger` entry (Archive must stay last) and a duplicate id.
158
+ * group, in the order given. Loud on every mistake that would break the
159
+ * invariants — a `danger` entry (Archive must stay last), a group that does not
160
+ * exist (it would be dropped by every renderer) and a duplicate id.
138
161
  */
139
162
  declare function withExtensions(base: readonly ObjectAction[], extra: readonly ObjectAction[]): ObjectAction[];
140
163
  /** A run of actions that renders together: a plain section, or one submenu. */
@@ -162,7 +185,25 @@ type ObjectActionDropdownEntry = {
162
185
  actions: ObjectAction[];
163
186
  };
164
187
  declare function toDropdownEntries(actions: readonly ObjectAction[]): ObjectActionDropdownEntry[];
165
- /** The action ids a dropdown draws, in order — what G1 compares. */
188
+ /** The actions a dropdown draws, in order — what G1 compares. */
189
+ declare function dropdownActions(entries: readonly ObjectActionDropdownEntry[]): ObjectAction[];
190
+ /** The action ids a dropdown draws, in order. */
166
191
  declare function dropdownActionIds(entries: readonly ObjectActionDropdownEntry[]): string[];
192
+ /** The icon-strip menu: standard verbs as icons, then the first feature rows, then the rest. */
193
+ interface StripAndRows {
194
+ /** Every action with a `verb`, in the list's order. */
195
+ strip: ObjectAction[];
196
+ /** The first `rowCount` feature actions by rank (ties keep list order). */
197
+ rows: ObjectAction[];
198
+ /** The remaining feature actions, behind "More … options", same ordering. */
199
+ more: ObjectAction[];
200
+ }
201
+ declare const STRIP_FEATURE_ROWS = 4;
202
+ /**
203
+ * THE STRIP RENDERER'S SPLIT of the same list. Nothing is added or dropped: every
204
+ * id lands in exactly one of strip / rows / more (G1). Unranked feature actions
205
+ * (an extension that gave none) follow every ranked one.
206
+ */
207
+ declare function toStripAndRows(actions: readonly ObjectAction[], rowCount?: number): StripAndRows;
167
208
 
168
- export { ACTION_CHECKING_ACCESS_REASON as A, type BuiltOnDestination as B, type Capability as C, DEFAULT_ACTION_ORIGIN as D, KERNEL_REASON as K, LEVEL_WORD as L, NOT_ANSWERED_YET as N, type ObjectAction as O, type TableActionHost as T, type WhatYouMayDo as W, ACTION_NOT_HERE_REASON as a, ACTION_NO_ACCESS_REASON as b, ACTION_PLATFORM_TABLE_REASON as c, OBJECT_ACTION_GROUPS as d, type ObjectActionDropdownEntry as e, type ObjectActionGroup as f, type ObjectActionGroupDef as g, type ObjectActionIcon as h, type ObjectActionSection as i, type TableActionSubject as j, type TableActionsInput as k, dropdownActionIds as l, groupObjectActions as m, levelNeededFor as n, tableLink as o, toDropdownEntries as p, whatYouMayDoWithTable as q, rightsReason as r, withExtensions as s, tableActions as t, whatYouMayDo as w };
209
+ export { ACTION_CHECKING_ACCESS_REASON as A, type BuiltOnDestination as B, type Capability as C, DEFAULT_ACTION_ORIGIN as D, KERNEL_REASON as K, LEVEL_WORD as L, NOT_ANSWERED_YET as N, type ObjectAction as O, STANDARD_VERBS as S, type TableActionHost as T, type WhatYouMayDo as W, type ObjectActionIcon as a, ACTION_NOT_HERE_REASON as b, ACTION_NO_ACCESS_REASON as c, ACTION_PLATFORM_TABLE_REASON as d, OBJECT_ACTION_GROUPS as e, type ObjectActionDropdownEntry as f, type ObjectActionGroup as g, type ObjectActionGroupDef as h, type ObjectActionSection as i, STRIP_FEATURE_ROWS as j, type StandardVerbId as k, type StripAndRows as l, type TableActionSubject as m, type TableActionsInput as n, dropdownActionIds as o, dropdownActions as p, groupObjectActions as q, levelNeededFor as r, rightsReason as s, tableActions as t, tableLink as u, toDropdownEntries as v, toStripAndRows as w, whatYouMayDo as x, whatYouMayDoWithTable as y, withExtensions as z };
package/dist/pickers.cjs CHANGED
@@ -26,6 +26,7 @@ __export(pickers_exports, {
26
26
  DATA_BINDING_MISSING: () => DATA_BINDING_MISSING,
27
27
  DATA_BINDING_SHAPES: () => DATA_BINDING_SHAPES,
28
28
  DataBindingPicker: () => DataBindingPicker,
29
+ HeldChangeDecision: () => HeldChangeDecision,
29
30
  RecordNameText: () => RecordNameText,
30
31
  RecordPicker: () => RecordPicker,
31
32
  TableNameText: () => TableNameText,
@@ -458,6 +459,7 @@ function rowNameIn(table, row, fallback = "Untitled") {
458
459
  return recordName(row?.document, table?.title_field ?? null, fallback);
459
460
  }
460
461
  var WITHHELD_RECORD_LABEL = "A record you have not been given access to";
462
+ var UNREAD_RECORD_LABEL = "Couldn't load this name";
461
463
 
462
464
  // src/RelationPicker.tsx
463
465
  var import_react3 = require("react");
@@ -940,7 +942,7 @@ function RelationPicker({ field, value, onChange, disabled, id, className, allow
940
942
  const learned = {};
941
943
  for (const id2 of wanted) {
942
944
  const said = result.ok ? result.data[id2] : void 0;
943
- learned[id2] = typeof said === "string" && said !== "" ? said : WITHHELD_RECORD_LABEL;
945
+ learned[id2] = !result.ok ? UNREAD_RECORD_LABEL : typeof said === "string" && said !== "" ? said : WITHHELD_RECORD_LABEL;
944
946
  }
945
947
  setWords((current) => ({ ...current, ...learned }));
946
948
  });
@@ -1535,7 +1537,7 @@ function RecordLabelProvider({ children }) {
1535
1537
  });
1536
1538
  for (const id of wanted) {
1537
1539
  const words = result.ok ? result.data[id] : void 0;
1538
- learned[id] = typeof words === "string" && words !== "" ? words : WITHHELD_RECORD_LABEL;
1540
+ learned[id] = !result.ok ? UNREAD_RECORD_LABEL : typeof words === "string" && words !== "" ? words : WITHHELD_RECORD_LABEL;
1539
1541
  }
1540
1542
  if (result.ok) for (const id of result.archived ?? []) archivedNow[`${field.id}:${id}`] = true;
1541
1543
  })
@@ -4481,6 +4483,7 @@ function TableNameText({ dataSource, tableId }) {
4481
4483
  const tables = useTablesAnywhere(dataSource);
4482
4484
  if (!tableId) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "\u2014" });
4483
4485
  if (tables.loading) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "\u2026" });
4486
+ if (tables.error) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "Couldn't load the table's name" });
4484
4487
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: tables.rows.find((t) => t.table_id === tableId)?.table_name ?? "\u2014" });
4485
4488
  }
4486
4489
  function ColumnValuesText({
@@ -4496,8 +4499,10 @@ function ColumnValuesWords({ tableId, value }) {
4496
4499
  const fields = (0, import_react33.useFields)(tableId);
4497
4500
  const labels = useRecordLabels(fields.data ?? void 0);
4498
4501
  if (fields.loading) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "\u2026" });
4502
+ if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "Couldn't load this table's columns" });
4499
4503
  const parts = [];
4500
4504
  for (const [key, stored] of Object.entries(value)) {
4505
+ if (key.startsWith("_")) continue;
4501
4506
  const field = (fields.data ?? []).find((f) => f.key === key);
4502
4507
  if (parts.length) parts.push(/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: ", " }, `${key}-sep`));
4503
4508
  parts.push(
@@ -4523,7 +4528,53 @@ function RecordNameWords({ tableId, recordId }) {
4523
4528
  const table = (0, import_react33.useTable)(tableId);
4524
4529
  const record = (0, import_react33.useRecord)(recordId);
4525
4530
  if (record.loading || table.loading) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "\u2026" });
4531
+ if (record.error) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "Couldn't load this record" });
4526
4532
  if (!record.data) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: "A record you cannot open" });
4527
4533
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: recordName(record.data.document, table.data?.title_field ?? null) });
4528
4534
  }
4535
+
4536
+ // src/HeldChangeDecision.tsx
4537
+ var import_react34 = require("react");
4538
+ var import_react35 = require("@ai-matrx/records/react");
4539
+ var import_design_system20 = require("@ai-matrx/design-system");
4540
+ var import_jsx_runtime24 = require("react/jsx-runtime");
4541
+ function HeldChangeDecision({ dataSource, userId, organizationId, approvalId, onDecided }) {
4542
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react35.RecordsProvider, { config: { dataSource, actor: personActor(userId), organizationId }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Decision, { approvalId, onDecided }) });
4543
+ }
4544
+ function Decision({ approvalId, onDecided }) {
4545
+ const client = (0, import_react35.useRecordsClient)();
4546
+ const [may, setMay] = (0, import_react34.useState)(null);
4547
+ const [busy, setBusy] = (0, import_react34.useState)(null);
4548
+ const [error, setError] = (0, import_react34.useState)(null);
4549
+ (0, import_react34.useEffect)(() => {
4550
+ let live = true;
4551
+ void client.workApprovalMayDecide({ approval_id: approvalId }).then((res) => {
4552
+ if (!live) return;
4553
+ if (res.ok) setMay(res.data);
4554
+ else {
4555
+ setMay(false);
4556
+ setError(res.error);
4557
+ }
4558
+ });
4559
+ return () => {
4560
+ live = false;
4561
+ };
4562
+ }, [client, approvalId]);
4563
+ const decide = async (approve) => {
4564
+ setBusy(approve ? "approve" : "refuse");
4565
+ setError(null);
4566
+ const res = await client.workApprovalDecide({ approval_id: approvalId, approve });
4567
+ setBusy(null);
4568
+ if (res.ok) onDecided(approve);
4569
+ else setError(res.error);
4570
+ };
4571
+ if (may === null) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-xs text-muted-foreground", children: "Checking who can decide\u2026" });
4572
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
4573
+ may ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex gap-2", children: [
4574
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_design_system20.Button, { type: "button", size: "sm", disabled: busy !== null, onClick: () => void decide(true), children: busy === "approve" ? "Approving\u2026" : "Approve" }),
4575
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_design_system20.Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => void decide(false), children: busy === "refuse" ? "Refusing\u2026" : "Refuse" })
4576
+ ] }) : !error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-xs text-muted-foreground", children: "An owner or admin of this organization decides this." }),
4577
+ error ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RefusalLine, { error }) : null
4578
+ ] });
4579
+ }
4529
4580
  //# sourceMappingURL=pickers.cjs.map