@ai-matrx/records-ui 0.93.140 → 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.
@@ -134,4 +134,15 @@ declare function RecordNameText({ dataSource, userId, tableId, recordId, }: {
134
134
  recordId: string | null;
135
135
  }): react.JSX.Element;
136
136
 
137
- export { ColumnValuesEditor, type ColumnValuesEditorProps, ColumnValuesText, DATA_BINDING_MISSING, DATA_BINDING_SHAPES, type DataBinding, DataBindingPicker, type DataBindingPickerProps, type DataBindingShape, RecordNameText, RecordPicker, type RecordPickerProps, type TableAnywhere, TableNameText, TablePicker, type TablePickerProps, TableScope, type TableScopeProps, type TablesAnywhere, bindingPlaceholdersFor, defaultBindingTemplate, emptyDataBinding, isCompleteDataBinding, isDataBinding, useTablesAnywhere };
137
+ interface HeldChangeDecisionProps {
138
+ dataSource: RecordsDataSource;
139
+ userId: Uuid | null;
140
+ /** The organization the held change lives in (the marker's `organization_id`). */
141
+ organizationId: Uuid;
142
+ approvalId: Uuid;
143
+ /** Told once the store took the decision; `approved` says which way. */
144
+ onDecided: (approved: boolean) => void;
145
+ }
146
+ declare function HeldChangeDecision({ dataSource, userId, organizationId, approvalId, onDecided }: HeldChangeDecisionProps): react.JSX.Element;
147
+
148
+ export { ColumnValuesEditor, type ColumnValuesEditorProps, ColumnValuesText, DATA_BINDING_MISSING, DATA_BINDING_SHAPES, type DataBinding, DataBindingPicker, type DataBindingPickerProps, type DataBindingShape, HeldChangeDecision, type HeldChangeDecisionProps, RecordNameText, RecordPicker, type RecordPickerProps, type TableAnywhere, TableNameText, TablePicker, type TablePickerProps, TableScope, type TableScopeProps, type TablesAnywhere, bindingPlaceholdersFor, defaultBindingTemplate, emptyDataBinding, isCompleteDataBinding, isDataBinding, useTablesAnywhere };
package/dist/pickers.d.ts CHANGED
@@ -134,4 +134,15 @@ declare function RecordNameText({ dataSource, userId, tableId, recordId, }: {
134
134
  recordId: string | null;
135
135
  }): react.JSX.Element;
136
136
 
137
- export { ColumnValuesEditor, type ColumnValuesEditorProps, ColumnValuesText, DATA_BINDING_MISSING, DATA_BINDING_SHAPES, type DataBinding, DataBindingPicker, type DataBindingPickerProps, type DataBindingShape, RecordNameText, RecordPicker, type RecordPickerProps, type TableAnywhere, TableNameText, TablePicker, type TablePickerProps, TableScope, type TableScopeProps, type TablesAnywhere, bindingPlaceholdersFor, defaultBindingTemplate, emptyDataBinding, isCompleteDataBinding, isDataBinding, useTablesAnywhere };
137
+ interface HeldChangeDecisionProps {
138
+ dataSource: RecordsDataSource;
139
+ userId: Uuid | null;
140
+ /** The organization the held change lives in (the marker's `organization_id`). */
141
+ organizationId: Uuid;
142
+ approvalId: Uuid;
143
+ /** Told once the store took the decision; `approved` says which way. */
144
+ onDecided: (approved: boolean) => void;
145
+ }
146
+ declare function HeldChangeDecision({ dataSource, userId, organizationId, approvalId, onDecided }: HeldChangeDecisionProps): react.JSX.Element;
147
+
148
+ export { ColumnValuesEditor, type ColumnValuesEditorProps, ColumnValuesText, DATA_BINDING_MISSING, DATA_BINDING_SHAPES, type DataBinding, DataBindingPicker, type DataBindingPickerProps, type DataBindingShape, HeldChangeDecision, type HeldChangeDecisionProps, RecordNameText, RecordPicker, type RecordPickerProps, type TableAnywhere, TableNameText, TablePicker, type TablePickerProps, TableScope, type TableScopeProps, type TablesAnywhere, bindingPlaceholdersFor, defaultBindingTemplate, emptyDataBinding, isCompleteDataBinding, isDataBinding, useTablesAnywhere };
package/dist/pickers.js CHANGED
@@ -400,21 +400,35 @@ import {
400
400
  fieldKindFor,
401
401
  newerKindOf as newerKindOf2
402
402
  } from "@ai-matrx/records";
403
+ import { humanizeIdentifier } from "@ai-matrx/kit/text-case";
404
+
405
+ // src/docs.ts
406
+ function isSignatureField(field) {
407
+ return field.type === "text" && (field.format ?? "").toLowerCase() === "signature";
408
+ }
409
+
410
+ // src/parity.ts
411
+ var kernelId = (name) => KERNEL_TABLES.find((t) => t.name === name)?.id ?? "";
412
+ var KERNEL_FILE_TABLE = kernelId("File");
413
+ var KERNEL_PERSON_TABLE = kernelId("Person");
414
+ var PARITY_MADE_OF = Object.fromEntries(
415
+ PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of])
416
+ );
417
+ var KERNEL = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };
418
+ function editorKindFor(field) {
419
+ return fieldKindFor(field, KERNEL);
420
+ }
403
421
 
404
422
  // src/names.ts
405
423
  import { isUuidShape } from "@ai-matrx/kit/uuid";
406
- function humanize(token) {
407
- const words = token.replace(/[_\-.]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim();
408
- if (words === "") return token;
409
- return words.charAt(0).toUpperCase() + words.slice(1);
410
- }
424
+ import { humanizeIdentifier as humanizeIdentifier2 } from "@ai-matrx/kit/text-case";
411
425
  function fieldName(field) {
412
426
  const label = (field.label ?? "").trim();
413
- if (label !== "" && label === field.key && /^[a-z0-9]+(?:[_.-][a-z0-9]+)+$/.test(label)) return humanize(label);
427
+ if (label !== "" && label === field.key && /^[a-z0-9]+(?:[_.-][a-z0-9]+)+$/.test(label)) return humanizeIdentifier2(label);
414
428
  if (label !== "") return label;
415
429
  const name = (field.name ?? "").trim();
416
430
  if (name !== "") return name;
417
- return humanize(field.key);
431
+ return humanizeIdentifier2(field.key);
418
432
  }
419
433
  function recordName(document2, titleKey, fallback = "Untitled") {
420
434
  const data = document2 ?? {};
@@ -437,23 +451,7 @@ function rowNameIn(table, row, fallback = "Untitled") {
437
451
  return recordName(row?.document, table?.title_field ?? null, fallback);
438
452
  }
439
453
  var WITHHELD_RECORD_LABEL = "A record you have not been given access to";
440
-
441
- // src/docs.ts
442
- function isSignatureField(field) {
443
- return field.type === "text" && (field.format ?? "").toLowerCase() === "signature";
444
- }
445
-
446
- // src/parity.ts
447
- var kernelId = (name) => KERNEL_TABLES.find((t) => t.name === name)?.id ?? "";
448
- var KERNEL_FILE_TABLE = kernelId("File");
449
- var KERNEL_PERSON_TABLE = kernelId("Person");
450
- var PARITY_MADE_OF = Object.fromEntries(
451
- PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of])
452
- );
453
- var KERNEL = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };
454
- function editorKindFor(field) {
455
- return fieldKindFor(field, KERNEL);
456
- }
454
+ var UNREAD_RECORD_LABEL = "Couldn't load this name";
457
455
 
458
456
  // src/RelationPicker.tsx
459
457
  import { useEffect as useEffect3, useMemo, useState as useState3 } from "react";
@@ -932,7 +930,7 @@ function RelationPicker({ field, value, onChange, disabled, id, className, allow
932
930
  const learned = {};
933
931
  for (const id2 of wanted) {
934
932
  const said = result.ok ? result.data[id2] : void 0;
935
- learned[id2] = typeof said === "string" && said !== "" ? said : WITHHELD_RECORD_LABEL;
933
+ learned[id2] = !result.ok ? UNREAD_RECORD_LABEL : typeof said === "string" && said !== "" ? said : WITHHELD_RECORD_LABEL;
936
934
  }
937
935
  setWords((current) => ({ ...current, ...learned }));
938
936
  });
@@ -1531,7 +1529,7 @@ function RecordLabelProvider({ children }) {
1531
1529
  });
1532
1530
  for (const id of wanted) {
1533
1531
  const words = result.ok ? result.data[id] : void 0;
1534
- learned[id] = typeof words === "string" && words !== "" ? words : WITHHELD_RECORD_LABEL;
1532
+ learned[id] = !result.ok ? UNREAD_RECORD_LABEL : typeof words === "string" && words !== "" ? words : WITHHELD_RECORD_LABEL;
1535
1533
  }
1536
1534
  if (result.ok) for (const id of result.archived ?? []) archivedNow[`${field.id}:${id}`] = true;
1537
1535
  })
@@ -4199,6 +4197,7 @@ import { Badge as Badge4, cn as cn14 } from "@ai-matrx/design-system";
4199
4197
 
4200
4198
  // src/kindValues.ts
4201
4199
  import { tryDecodeDirective } from "@ai-matrx/content-ir/directives";
4200
+ import { humanizeIdentifier as humanizeIdentifier3 } from "@ai-matrx/kit/text-case";
4202
4201
  var KIND_KEY = "__kind";
4203
4202
  var WHOLE_FENCE = /^\s*```(?:matrx|json)?[ \t]*\r?\n?([\s\S]*?)\r?\n?[ \t]*```\s*$/;
4204
4203
  function asObject(value) {
@@ -4244,8 +4243,7 @@ function kindValueWords(kv) {
4244
4243
  return kindLabel(kv.kind);
4245
4244
  }
4246
4245
  function kindLabel(kind) {
4247
- const words = kind.replace(/^directive_v\d+_/, "").replace(/_v\d+$/, "").replace(/_/g, " ").trim();
4248
- return words ? words.charAt(0).toUpperCase() + words.slice(1) : "Structured value";
4246
+ return humanizeIdentifier3(kind.replace(/^directive_v\d+_/, "").replace(/_v\d+$/, "")) || "Structured value";
4249
4247
  }
4250
4248
 
4251
4249
  // src/ReferenceChips.tsx
@@ -4493,6 +4491,7 @@ function TableNameText({ dataSource, tableId }) {
4493
4491
  const tables = useTablesAnywhere(dataSource);
4494
4492
  if (!tableId) return /* @__PURE__ */ jsx23(Fragment7, { children: "\u2014" });
4495
4493
  if (tables.loading) return /* @__PURE__ */ jsx23(Fragment7, { children: "\u2026" });
4494
+ if (tables.error) return /* @__PURE__ */ jsx23(Fragment7, { children: "Couldn't load the table's name" });
4496
4495
  return /* @__PURE__ */ jsx23(Fragment7, { children: tables.rows.find((t) => t.table_id === tableId)?.table_name ?? "\u2014" });
4497
4496
  }
4498
4497
  function ColumnValuesText({
@@ -4508,8 +4507,10 @@ function ColumnValuesWords({ tableId, value }) {
4508
4507
  const fields = useFields3(tableId);
4509
4508
  const labels = useRecordLabels(fields.data ?? void 0);
4510
4509
  if (fields.loading) return /* @__PURE__ */ jsx23(Fragment7, { children: "\u2026" });
4510
+ if (fields.error) return /* @__PURE__ */ jsx23(Fragment7, { children: "Couldn't load this table's columns" });
4511
4511
  const parts = [];
4512
4512
  for (const [key, stored] of Object.entries(value)) {
4513
+ if (key.startsWith("_")) continue;
4513
4514
  const field = (fields.data ?? []).find((f) => f.key === key);
4514
4515
  if (parts.length) parts.push(/* @__PURE__ */ jsx23("span", { children: ", " }, `${key}-sep`));
4515
4516
  parts.push(
@@ -4535,15 +4536,62 @@ function RecordNameWords({ tableId, recordId }) {
4535
4536
  const table = useTable3(tableId);
4536
4537
  const record = useRecord(recordId);
4537
4538
  if (record.loading || table.loading) return /* @__PURE__ */ jsx23(Fragment7, { children: "\u2026" });
4539
+ if (record.error) return /* @__PURE__ */ jsx23(Fragment7, { children: "Couldn't load this record" });
4538
4540
  if (!record.data) return /* @__PURE__ */ jsx23(Fragment7, { children: "A record you cannot open" });
4539
4541
  return /* @__PURE__ */ jsx23(Fragment7, { children: recordName(record.data.document, table.data?.title_field ?? null) });
4540
4542
  }
4543
+
4544
+ // src/HeldChangeDecision.tsx
4545
+ import { useEffect as useEffect15, useState as useState17 } from "react";
4546
+ import { RecordsProvider as RecordsProvider3, useRecordsClient as useRecordsClient3 } from "@ai-matrx/records/react";
4547
+ import { Button as Button11 } from "@ai-matrx/design-system";
4548
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
4549
+ function HeldChangeDecision({ dataSource, userId, organizationId, approvalId, onDecided }) {
4550
+ return /* @__PURE__ */ jsx24(RecordsProvider3, { config: { dataSource, actor: personActor(userId), organizationId }, children: /* @__PURE__ */ jsx24(Decision, { approvalId, onDecided }) });
4551
+ }
4552
+ function Decision({ approvalId, onDecided }) {
4553
+ const client = useRecordsClient3();
4554
+ const [may, setMay] = useState17(null);
4555
+ const [busy, setBusy] = useState17(null);
4556
+ const [error, setError] = useState17(null);
4557
+ useEffect15(() => {
4558
+ let live = true;
4559
+ void client.workApprovalMayDecide({ approval_id: approvalId }).then((res) => {
4560
+ if (!live) return;
4561
+ if (res.ok) setMay(res.data);
4562
+ else {
4563
+ setMay(false);
4564
+ setError(res.error);
4565
+ }
4566
+ });
4567
+ return () => {
4568
+ live = false;
4569
+ };
4570
+ }, [client, approvalId]);
4571
+ const decide = async (approve) => {
4572
+ setBusy(approve ? "approve" : "refuse");
4573
+ setError(null);
4574
+ const res = await client.workApprovalDecide({ approval_id: approvalId, approve });
4575
+ setBusy(null);
4576
+ if (res.ok) onDecided(approve);
4577
+ else setError(res.error);
4578
+ };
4579
+ if (may === null) return /* @__PURE__ */ jsx24("p", { className: "text-xs text-muted-foreground", children: "Checking who can decide\u2026" });
4580
+ return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-1.5", children: [
4581
+ may ? /* @__PURE__ */ jsxs21("div", { className: "flex gap-2", children: [
4582
+ /* @__PURE__ */ jsx24(Button11, { type: "button", size: "sm", disabled: busy !== null, onClick: () => void decide(true), children: busy === "approve" ? "Approving\u2026" : "Approve" }),
4583
+ /* @__PURE__ */ jsx24(Button11, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => void decide(false), children: busy === "refuse" ? "Refusing\u2026" : "Refuse" })
4584
+ ] }) : !error && /* @__PURE__ */ jsx24("p", { className: "text-xs text-muted-foreground", children: "An owner or admin of this organization decides this." }),
4585
+ error ? /* @__PURE__ */ jsx24(RefusalLine, { error }) : null
4586
+ ] });
4587
+ }
4541
4588
  export {
4542
4589
  ColumnValuesEditor,
4543
4590
  ColumnValuesText,
4544
4591
  DATA_BINDING_MISSING,
4545
4592
  DATA_BINDING_SHAPES,
4546
4593
  DataBindingPicker,
4594
+ HeldChangeDecision,
4547
4595
  RecordNameText,
4548
4596
  RecordPicker,
4549
4597
  TableNameText,