@ai-matrx/records-ui 0.113.38 → 0.114.0

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.cjs CHANGED
@@ -659,7 +659,9 @@ var NEEDS = {
659
659
  // custom.share_grant — passing your access on is an administrator's right
660
660
  share: "admin",
661
661
  // custom.field_declare / field_update / field_retire / table settings
662
- structure: "admin"
662
+ structure: "admin",
663
+ // custom.field_declare / field_update / field_retire — the same rung; a lock takes it away, nothing else does
664
+ schema: "admin"
663
665
  };
664
666
  function levelNeededFor(what) {
665
667
  return NEEDS[what];
@@ -677,7 +679,8 @@ function sentenceFor(what, level) {
677
679
  organise: "organise this",
678
680
  remove: "delete this",
679
681
  share: "pass this on to somebody else",
680
- structure: "change the columns of this table"
682
+ structure: "change the columns of this table",
683
+ schema: "change the columns of this table"
681
684
  };
682
685
  return `You are ${have} here, and it takes ${need} to ${doing[what]}. Ask somebody who is Admin on it to move you up.`;
683
686
  }
@@ -693,6 +696,7 @@ function whatYouMayDo(level, known = true) {
693
696
  remove: may("remove"),
694
697
  share: may("share"),
695
698
  structure: may("structure"),
699
+ schema: may("schema"),
696
700
  why: (what) => known ? sentenceFor(what, level) : NOT_YET
697
701
  };
698
702
  }
@@ -704,15 +708,16 @@ function whatYouMayDoWithTable(table, level, known) {
704
708
  return {
705
709
  ...base2,
706
710
  structure: false,
707
- why: (what) => what === "structure" ? KERNEL_REASON : base2.why(what)
711
+ schema: false,
712
+ why: (what) => what === "structure" || what === "schema" ? KERNEL_REASON : base2.why(what)
708
713
  };
709
714
  }
710
715
  function tableIsLocked(table) {
711
716
  return table?.metadata?.["locked"] === true;
712
717
  }
713
- var DATABASE_LOCKED_REASON = "This database is locked, so its columns and settings are read-only. Unlock it to change them.";
718
+ var DATABASE_LOCKED_REASON = "This database is locked, so its columns cannot be added, renamed, changed or deleted. Unlock it to change them.";
714
719
  function lockedStructure(base2) {
715
- return { ...base2, structure: false, why: (what) => what === "structure" ? DATABASE_LOCKED_REASON : base2.why(what) };
720
+ return { ...base2, schema: false, why: (what) => what === "schema" ? DATABASE_LOCKED_REASON : base2.why(what) };
716
721
  }
717
722
 
718
723
  // src/host.tsx
@@ -3486,6 +3491,7 @@ function TableDetails({
3486
3491
  (0, import_react15.tableShapeChanged)(tableId);
3487
3492
  onSaved?.();
3488
3493
  };
3494
+ const locked = table.metadata?.["locked"] === true;
3489
3495
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", "data-table-details": "", children: [
3490
3496
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-medium", children: "About this table" }),
3491
3497
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-1", children: [
@@ -3539,9 +3545,9 @@ function TableDetails({
3539
3545
  size: "sm",
3540
3546
  variant: "outline",
3541
3547
  disabled: busy,
3542
- onClick: () => void write(lockPatch(table, true), { metadata: table.metadata ?? {} }),
3548
+ onClick: () => void write(lockPatch(table, !locked), { metadata: table.metadata ?? {} }),
3543
3549
  "data-table-lock-on": "",
3544
- children: "Lock"
3550
+ children: locked ? "Unlock" : "Lock"
3545
3551
  }
3546
3552
  )
3547
3553
  ] }),
@@ -7345,10 +7351,8 @@ var RELATIVE_DAY_TERMS = [
7345
7351
  { kind: "past_days", label: "is in the past \u2026 days", takesDays: true }
7346
7352
  ];
7347
7353
  function relativeDayNode(fieldId, kind, days) {
7348
- const zone2 = getPersonTimeZone();
7349
7354
  const window2 = { relative: kind };
7350
7355
  if (RELATIVE_DAY_TERMS.find((t) => t.kind === kind)?.takesDays) window2["n"] = days ?? 7;
7351
- if (zone2) window2["tz"] = zone2;
7352
7356
  return { op: "within", args: [{ field: fieldId }, { const: window2 }] };
7353
7357
  }
7354
7358
  function relativeDayOf(expr) {
@@ -8996,8 +9000,8 @@ function FieldEditor(props) {
8996
9000
  const entityMutation = (0, import_react51.useEntityFieldMutation)();
8997
9001
  const mutation = onEntity ? { saving: entityMutation.saving, error: entityMutation.error } : { saving: tableMutation.saving, error: tableMutation.error };
8998
9002
  const client = (0, import_react51.useRecordsClient)();
8999
- const mayShape = onEntity ? entityRights.data?.may_declare === true : tableRights2.structure;
9000
- const whyNot = onEntity ? entityRights.data?.reason ?? null : tableRights2.why("structure");
9003
+ const mayShape = onEntity ? entityRights.data?.may_declare === true : tableRights2.schema;
9004
+ const whyNot = onEntity ? entityRights.data?.reason ?? null : tableRights2.why("schema");
9001
9005
  const storeLabel = onEntity ? entityRights.data?.label ?? null : table.data?.name ?? null;
9002
9006
  const tableLabel = props.tableLabel ?? storeLabel;
9003
9007
  const offered = onEntity ? STANDARD_TABLE_FIELD_CHOICES : FIELD_TYPE_CHOICES;
@@ -15920,7 +15924,7 @@ function useMergedGridControls(args) {
15920
15924
  },
15921
15925
  [enabled, fieldOf2, choiceOptions, rows, choiceCounts]
15922
15926
  );
15923
- const copyText14 = (0, import_react90.useCallback)(
15927
+ const copyText16 = (0, import_react90.useCallback)(
15924
15928
  (text, what) => {
15925
15929
  void (0, import_clipboard.copyText)(text).then(
15926
15930
  (landed) => landed ? notify?.success(`${what} ${what.endsWith("cells") ? "are" : "is"} copied.`) : notify?.error("The clipboard refused the copy. Select the cells and press Cmd-C.")
@@ -15929,7 +15933,7 @@ function useMergedGridControls(args) {
15929
15933
  [notify]
15930
15934
  );
15931
15935
  const ctx = (0, import_react90.useMemo)(() => {
15932
- const mayStructure = rights.structure && editable;
15936
+ const mayStructure = rights.schema && editable;
15933
15937
  const summaries = args.summaries;
15934
15938
  const firstKey = fieldKeys[0];
15935
15939
  return {
@@ -15958,7 +15962,7 @@ function useMergedGridControls(args) {
15958
15962
  id: "col-duplicate",
15959
15963
  label: "Duplicate property",
15960
15964
  icon: "copy-plus",
15961
- disabledReason: mayStructure ? void 0 : editable ? rights.why("structure") : "Editing is off here.",
15965
+ disabledReason: mayStructure ? void 0 : editable ? rights.why("schema") : "Editing is off here.",
15962
15966
  // DUPLICATE PROPERTY (Notion N5): one door declares the copy right after this column and copies
15963
15967
  // every record's value into it (`custom.field_duplicate`); nothing to fill in, as in Notion.
15964
15968
  onSelect: () => {
@@ -15995,14 +15999,14 @@ function useMergedGridControls(args) {
15995
15999
  id: "table-row-label",
15996
16000
  label: "What names each record\u2026",
15997
16001
  icon: "tag",
15998
- disabledReason: mayStructure ? void 0 : editable ? rights.why("structure") : "Editing is off here.",
16002
+ disabledReason: mayStructure ? void 0 : editable ? rights.why("schema") : "Editing is off here.",
15999
16003
  onSelect: () => setLabelling(true)
16000
16004
  },
16001
16005
  {
16002
16006
  id: "table-row-actions",
16003
16007
  label: ROW_ACTIONS_MENU_LABEL,
16004
16008
  icon: "zap",
16005
- disabledReason: mayStructure ? void 0 : editable ? rights.why("structure") : "Editing is off here.",
16009
+ disabledReason: mayStructure ? void 0 : editable ? rights.why("schema") : "Editing is off here.",
16006
16010
  onSelect: () => setRowActionsOpen(true)
16007
16011
  },
16008
16012
  // CLEAN THE WHOLE TABLE AT ONCE (the Sheet's CellCleanupButton): every text column, one review.
@@ -16032,7 +16036,7 @@ function useMergedGridControls(args) {
16032
16036
  mayAddRecord: editable && rights.write,
16033
16037
  whyNotAdd: editable ? rights.why("write") : "Editing is off here.",
16034
16038
  mayStructure,
16035
- whyNotStructure: editable ? rights.why("structure") : "Editing is off here.",
16039
+ whyNotStructure: editable ? rights.why("schema") : "Editing is off here.",
16036
16040
  cleanable: (field2) => isTextColumn(field2),
16037
16041
  typeable: (columnId2) => {
16038
16042
  const field2 = fields.find((f) => f.key === columnId2);
@@ -16040,7 +16044,7 @@ function useMergedGridControls(args) {
16040
16044
  },
16041
16045
  sortedBy: query.sort ? { id: query.sort.id, direction: query.sort.direction } : null,
16042
16046
  actions: {
16043
- copyText: copyText14,
16047
+ copyText: copyText16,
16044
16048
  pasteInto: (rowId, columnId2) => {
16045
16049
  const field2 = fields.find((f) => f.key === columnId2);
16046
16050
  if (!field2) return;
@@ -16109,10 +16113,10 @@ function useMergedGridControls(args) {
16109
16113
  ...hrefForRecord && table ? {
16110
16114
  copyRecordLink: (rowId) => {
16111
16115
  const href = hrefForRecord({ table, recordId: rowId });
16112
- if (href) copyText14(new URL(href, window.location.origin).toString(), "The link");
16116
+ if (href) copyText16(new URL(href, window.location.origin).toString(), "The link");
16113
16117
  }
16114
16118
  } : {},
16115
- ...editable && rights.structure ? {
16119
+ ...editable && rights.schema ? {
16116
16120
  saveAsTemplate: (rowId) => {
16117
16121
  const row = rows.find((r) => r.id === rowId);
16118
16122
  if (row) setDialog({ kind: "template", row });
@@ -16209,7 +16213,7 @@ function useMergedGridControls(args) {
16209
16213
  fieldKeys,
16210
16214
  canWrite,
16211
16215
  client,
16212
- copyText14,
16216
+ copyText16,
16213
16217
  editable,
16214
16218
  editing,
16215
16219
  fields,
@@ -24693,7 +24697,7 @@ function GridBody({
24693
24697
  const offersRowActions = !embedded && (canWrite || Boolean(host.talkToRecord) || Boolean(!readOnly && host.runAgentAction && tableActions2.agent.length > 0));
24694
24698
  const hasTalk = Boolean(host.talkToRecord);
24695
24699
  const hasAgent = Boolean(host.runAgentAction);
24696
- const mayManageActions = !readOnly && rights.structure;
24700
+ const mayManageActions = !readOnly && rights.schema;
24697
24701
  const actionsHeader = (0, import_react127.useMemo)(
24698
24702
  () => /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(ActionsHeaderControls, { ...mayManageActions ? { onAddColumn: () => addColumnNow.current() } : {} }),
24699
24703
  [mayManageActions]
@@ -24776,9 +24780,9 @@ function GridBody({
24776
24780
  (key) => holdByContent(headerHeld.current, `filter:${key}`, filterFor(key))
24777
24781
  );
24778
24782
  const pinnedPlus = offersRowActions && mayManageActions;
24779
- return merged && rights.structure && !readOnly && !pinnedPlus ? [...drawn, addColumnDef] : drawn;
24783
+ return merged && rights.schema && !readOnly && !pinnedPlus ? [...drawn, addColumnDef] : drawn;
24780
24784
  },
24781
- [bodyColumns, controls.headerMenuFor, controls.filterFor, merged, rights.structure, readOnly, addColumnDef, offersRowActions, mayManageActions]
24785
+ [bodyColumns, controls.headerMenuFor, controls.filterFor, merged, rights.schema, readOnly, addColumnDef, offersRowActions, mayManageActions]
24782
24786
  );
24783
24787
  const columnsHeld = (0, import_react127.useRef)(null);
24784
24788
  const columns = columnsHeld.current !== null && sameColumns(columnsHeld.current, drawnColumns) ? columnsHeld.current : drawnColumns;
@@ -25076,7 +25080,7 @@ function GridBody({
25076
25080
  }
25077
25081
  ) : null,
25078
25082
  viewId && viewOrder?.onPlaced && hasSeveralRows ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(import_design_system65.Button, { size: "sm", variant: "ghost", onClick: () => setReordering(true), "data-records-reorder-open": "", children: "Reorder" }) : null,
25079
- !readOnly && rights.structure && onAddField ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(AddFieldButton, { onClick: onAddField }) : null,
25083
+ !readOnly && rights.schema && onAddField ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(AddFieldButton, { onClick: onAddField }) : null,
25080
25084
  embedded ? null : /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
25081
25085
  GridLayoutMenu,
25082
25086
  {
@@ -25393,7 +25397,7 @@ function GridBody({
25393
25397
  className: "flex flex-col items-start gap-2 rounded-md border border-dashed p-6",
25394
25398
  children: [
25395
25399
  /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("p", { className: "text-sm font-medium", children: NO_COLUMNS_YET }),
25396
- rights.structure && onAddField ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(import_design_system65.Button, { size: "sm", onClick: onAddField, children: "Add your first column" }) : /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("p", { className: "max-w-prose text-xs text-muted-foreground", children: rights.why("structure") })
25400
+ rights.schema && onAddField ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(import_design_system65.Button, { size: "sm", onClick: onAddField, children: "Add your first column" }) : /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("p", { className: "max-w-prose text-xs text-muted-foreground", children: rights.why("schema") })
25397
25401
  ]
25398
25402
  }
25399
25403
  ) : /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(import_jsx_runtime77.Fragment, { children: [
@@ -25975,6 +25979,7 @@ function ConnectedRecordsTableCard({
25975
25979
  }
25976
25980
 
25977
25981
  // src/ExportMenu.tsx
25982
+ var import_clipboard3 = require("@ai-matrx/kit/clipboard");
25978
25983
  var import_download2 = require("@ai-matrx/kit/download");
25979
25984
  var import_react133 = require("react");
25980
25985
  var import_react134 = require("@ai-matrx/records/react");
@@ -26156,6 +26161,31 @@ function ExportMenu({ tableId, rows, label, className, view }) {
26156
26161
  children: "XLSX"
26157
26162
  }
26158
26163
  ),
26164
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
26165
+ import_design_system67.Button,
26166
+ {
26167
+ size: "sm",
26168
+ variant: "outline",
26169
+ onClick: () => void exported().then((rows2) => download(`${name}.md`, "text/markdown;charset=utf-8", (0, import_core18.exportMarkdown)(columns, rows2))).catch(
26170
+ (thrown) => setFailure((0, refusals_exports.refusalFromThrown)(thrown, "The Markdown could not be written.", "The CSV beside this button carries the same rows."))
26171
+ ),
26172
+ children: "Markdown"
26173
+ }
26174
+ ),
26175
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
26176
+ import_design_system67.Button,
26177
+ {
26178
+ size: "sm",
26179
+ variant: "outline",
26180
+ onClick: () => void exported().then(async (rows2) => {
26181
+ if (await (0, import_clipboard3.copyText)((0, import_core18.exportMarkdown)(columns, rows2))) host.notify?.success("Markdown copied");
26182
+ else host.notify?.error("Couldn\u2019t copy the Markdown");
26183
+ }).catch(
26184
+ (thrown) => setFailure((0, refusals_exports.refusalFromThrown)(thrown, "The Markdown could not be written.", "The CSV beside this button carries the same rows."))
26185
+ ),
26186
+ children: "Copy Markdown"
26187
+ }
26188
+ ),
26159
26189
  /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
26160
26190
  import_react135.AlchemyMenu,
26161
26191
  {
@@ -26465,14 +26495,14 @@ function fieldsForNewColumns(columns) {
26465
26495
  }
26466
26496
 
26467
26497
  // src/BookingSlots.tsx
26468
- var import_clipboard4 = require("@ai-matrx/kit/clipboard");
26498
+ var import_clipboard5 = require("@ai-matrx/kit/clipboard");
26469
26499
  var import_react143 = require("react");
26470
26500
  var import_react144 = require("@ai-matrx/records/react");
26471
26501
  var import_records48 = require("@ai-matrx/records");
26472
26502
  var import_design_system75 = require("@ai-matrx/design-system");
26473
26503
 
26474
26504
  // src/BookingBuilder.tsx
26475
- var import_clipboard3 = require("@ai-matrx/kit/clipboard");
26505
+ var import_clipboard4 = require("@ai-matrx/kit/clipboard");
26476
26506
  var import_design_system70 = require("@ai-matrx/design-system");
26477
26507
  var import_react139 = require("react");
26478
26508
  var import_react140 = require("@ai-matrx/records/react");
@@ -26949,7 +26979,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, startNew, classN
26949
26979
  size: "sm",
26950
26980
  variant: "outline",
26951
26981
  onClick: () => {
26952
- void (0, import_clipboard3.copyText)(url).then((landed) => {
26982
+ void (0, import_clipboard4.copyText)(url).then((landed) => {
26953
26983
  setCopied(landed);
26954
26984
  if (landed) window.setTimeout(() => setCopied(false), 1600);
26955
26985
  });
@@ -27064,7 +27094,7 @@ var ACTION_NO_ACCESS_REASON = "You don't have access";
27064
27094
  var ACTION_PLATFORM_TABLE_REASON = "Platform tables can't be changed here";
27065
27095
  function rightsReason(rights, what, table) {
27066
27096
  if (!rights.known) return ACTION_CHECKING_ACCESS_REASON;
27067
- if (what === "structure" && table?.is_kernel) return ACTION_PLATFORM_TABLE_REASON;
27097
+ if ((what === "structure" || what === "schema") && table?.is_kernel) return ACTION_PLATFORM_TABLE_REASON;
27068
27098
  if (rights[what]) return null;
27069
27099
  if (rights.level === null) return ACTION_NO_ACCESS_REASON;
27070
27100
  return `Needs ${LEVEL_WORD[levelNeededFor(what)]} access`;
@@ -27126,7 +27156,7 @@ function tableActions(input) {
27126
27156
  const url = tableLink(table.id, host.origin);
27127
27157
  const favorite = host.isFavorite === true;
27128
27158
  const openInNewTab = host.openInNewTab;
27129
- const copyText14 = host.copyText;
27159
+ const copyText16 = host.copyText;
27130
27160
  const openBuiltOn = host.openBuiltOn;
27131
27161
  const built = [
27132
27162
  action({ id: "open", label: "Open", icon: "folder-open", group: "open", verb: "open" }, "read", input, bind(host.open, table)),
@@ -27140,7 +27170,7 @@ function tableActions(input) {
27140
27170
  { id: "copy-link", label: "Copy link", icon: "link", group: "open", verb: "copy-link" },
27141
27171
  "read",
27142
27172
  input,
27143
- copyText14 ? () => copyText14(url, table) : void 0
27173
+ copyText16 ? () => copyText16(url, table) : void 0
27144
27174
  ),
27145
27175
  action({ id: "rename", label: "Rename\u2026", icon: "pencil", group: "organize", verb: "rename" }, "structure", input, bind(host.rename, table)),
27146
27176
  action({ id: "duplicate", label: "Duplicate", icon: "copy", group: "organize", verb: "duplicate" }, "read", input, bind(host.duplicate, table)),
@@ -27160,7 +27190,7 @@ function tableActions(input) {
27160
27190
  action({ id: "share", label: "Share\u2026", icon: "share-2", group: "share", verb: "share" }, "share", input, bind(host.share, table)),
27161
27191
  action({ id: "export", label: "Export\u2026", icon: "download", group: "share", verb: "export" }, "read", input, bind(host.export, table)),
27162
27192
  action({ id: "import", label: "Import\u2026", icon: "upload", group: "share", verb: "import" }, "structure", input, bind(host.import, table)),
27163
- action({ id: "add-column", label: ADD_FIELD_OPEN_LABEL, icon: "columns-3", group: "manage", rank: 1 }, "structure", input, bind(host.addColumn, table)),
27193
+ action({ id: "add-column", label: ADD_FIELD_OPEN_LABEL, icon: "columns-3", group: "manage", rank: 1 }, "schema", input, bind(host.addColumn, table)),
27164
27194
  action({ id: "settings", label: "Settings", icon: "settings", group: "manage", verb: "settings" }, "structure", input, bind(host.settings, table)),
27165
27195
  action({ id: "history", label: "History", icon: "history", group: "manage", verb: "history" }, "read", input, bind(host.history, table)),
27166
27196
  // custom.view_designate asks editor on the table — `canDesignate` in TablePage.
@@ -27550,7 +27580,7 @@ function BookingSlots({ tableId, activeBookingId, className }) {
27550
27580
  [client, load]
27551
27581
  );
27552
27582
  const copy = (0, import_react143.useCallback)(async (url, formId) => {
27553
- if (await (0, import_clipboard4.copyText)(url)) {
27583
+ if (await (0, import_clipboard5.copyText)(url)) {
27554
27584
  setCopied(formId);
27555
27585
  setShown(null);
27556
27586
  window.setTimeout(() => setCopied(null), 1600);
@@ -29835,26 +29865,6 @@ function TableSettingsPanel({
29835
29865
  if (table.error) return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(RefusalNotice, { error: table.error, className });
29836
29866
  if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(RefusalNotice, { error: fields.error, className });
29837
29867
  if (!rights.structure) {
29838
- if (tableIsLocked(table.data)) {
29839
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: (0, import_design_system86.cn)("flex flex-col items-start gap-2 text-xs text-muted-foreground", className), "data-table-locked": "", children: [
29840
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("p", { children: DATABASE_LOCKED_REASON }),
29841
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
29842
- import_design_system86.Button,
29843
- {
29844
- size: "sm",
29845
- variant: "outline",
29846
- onClick: () => {
29847
- void saveTableLock(client, tableId, false).then((done) => {
29848
- if (done.ok) table.reload();
29849
- else ui.notify?.error(done.says);
29850
- });
29851
- },
29852
- "data-table-unlock": "",
29853
- children: "Unlock database"
29854
- }
29855
- )
29856
- ] });
29857
- }
29858
29868
  return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("p", { className: (0, import_design_system86.cn)("text-xs text-muted-foreground", className), children: rights.why("structure") });
29859
29869
  }
29860
29870
  const rows = [...fields.data ?? []].sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0));
@@ -29954,8 +29964,26 @@ function TableSettingsPanel({
29954
29964
  /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "flex items-center gap-2", children: [
29955
29965
  /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "font-medium", children: "Fields" }),
29956
29966
  /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "text-muted-foreground", children: rows.length }),
29957
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(import_design_system86.Button, { size: "sm", variant: "outline", className: "ml-auto", onClick: () => setEditing("new"), children: "Add a field" })
29967
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(import_design_system86.Button, { size: "sm", variant: "outline", className: "ml-auto", disabled: !rights.schema, onClick: () => setEditing("new"), children: "Add a field" })
29958
29968
  ] }),
29969
+ tableIsLocked(table.data) ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "flex flex-wrap items-center gap-2 text-muted-foreground", "data-table-locked": "", children: [
29970
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { children: DATABASE_LOCKED_REASON }),
29971
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
29972
+ import_design_system86.Button,
29973
+ {
29974
+ size: "sm",
29975
+ variant: "outline",
29976
+ onClick: () => {
29977
+ void saveTableLock(client, tableId, false).then((done) => {
29978
+ if (done.ok) table.reload();
29979
+ else ui.notify?.error(done.says);
29980
+ });
29981
+ },
29982
+ "data-table-unlock": "",
29983
+ children: "Unlock database"
29984
+ }
29985
+ )
29986
+ ] }) : null,
29959
29987
  shape.error ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(RefusalNotice, { error: shape.error }) : null,
29960
29988
  askingToRemove ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "flex flex-wrap items-center gap-2 rounded border border-destructive/40 px-2 py-1.5", children: [
29961
29989
  /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "text-destructive", children: [
@@ -29974,7 +30002,7 @@ function TableSettingsPanel({
29974
30002
  ),
29975
30003
  /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(import_design_system86.Button, { size: "sm", variant: "ghost", onClick: () => setAskingToRemove(null), children: "Keep it" })
29976
30004
  ] }) : null,
29977
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
30005
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("fieldset", { disabled: !rights.schema, className: "min-w-0 border-0 p-0", "data-columns-locked": rights.schema ? void 0 : "", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
29978
30006
  ColumnsAtOnce,
29979
30007
  {
29980
30008
  rows,
@@ -29987,7 +30015,7 @@ function TableSettingsPanel({
29987
30015
  table.reload();
29988
30016
  }
29989
30017
  }
29990
- ),
30018
+ ) }),
29991
30019
  /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(import_design_system86.Separator, {}),
29992
30020
  /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(StageRulesSection, { tableId }),
29993
30021
  /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(RowActionsSection, { tableId }),
@@ -30259,7 +30287,7 @@ function RecordFieldsInPlace({
30259
30287
  }
30260
30288
 
30261
30289
  // src/ShareControl.tsx
30262
- var import_clipboard5 = require("@ai-matrx/kit/clipboard");
30290
+ var import_clipboard6 = require("@ai-matrx/kit/clipboard");
30263
30291
  var import_react171 = require("react");
30264
30292
  var import_design_system88 = require("@ai-matrx/design-system");
30265
30293
  var import_jsx_runtime102 = require("react/jsx-runtime");
@@ -30322,7 +30350,7 @@ function ShareForSomebodyElse({
30322
30350
  }) {
30323
30351
  const [copied, setCopied] = (0, import_react171.useState)(null);
30324
30352
  const copy = async () => {
30325
- if (await (0, import_clipboard5.copyText)(window.location.href)) {
30353
+ if (await (0, import_clipboard6.copyText)(window.location.href)) {
30326
30354
  setCopied("yes");
30327
30355
  } else {
30328
30356
  setCopied("no");
@@ -31021,7 +31049,7 @@ function CardDates({ record, fields }) {
31021
31049
  }
31022
31050
 
31023
31051
  // src/RecordActionMenu.tsx
31024
- var import_clipboard6 = require("@ai-matrx/kit/clipboard");
31052
+ var import_clipboard7 = require("@ai-matrx/kit/clipboard");
31025
31053
  var import_react181 = require("react");
31026
31054
  var import_react182 = require("@ai-matrx/records/react");
31027
31055
  var import_design_system92 = require("@ai-matrx/design-system");
@@ -31048,7 +31076,7 @@ function recordActions(input) {
31048
31076
  const origin = (host.origin ?? DEFAULT_ACTION_ORIGIN).replace(/\/+$/, "");
31049
31077
  const url = host.href ? /^https?:/.test(host.href) ? host.href : `${origin}${host.href}` : recordLink(record.tableId, record.id, host.origin);
31050
31078
  const openInNewTab = host.openInNewTab;
31051
- const copyText14 = host.copyText;
31079
+ const copyText16 = host.copyText;
31052
31080
  const built = [
31053
31081
  action2({ id: "open", label: "Open", icon: "folder-open", group: "open", verb: "open" }, "read", input, bind2(host.open, record)),
31054
31082
  action2(
@@ -31061,7 +31089,7 @@ function recordActions(input) {
31061
31089
  { id: "copy-link", label: "Copy link", icon: "link", group: "open", verb: "copy-link" },
31062
31090
  "read",
31063
31091
  input,
31064
- copyText14 ? () => copyText14(url, record) : void 0
31092
+ copyText16 ? () => copyText16(url, record) : void 0
31065
31093
  ),
31066
31094
  action2({ id: "duplicate", label: "Duplicate", icon: "copy", group: "organize", verb: "duplicate" }, "organise", input, bind2(host.duplicate, record)),
31067
31095
  action2(
@@ -31114,7 +31142,7 @@ function useRecordActionHost({ tableId, row, onOpenRecord, onChanged, onMerge })
31114
31142
  window.open(url, "_blank", "noopener,noreferrer");
31115
31143
  },
31116
31144
  copyText: async (url) => {
31117
- if (await (0, import_clipboard6.copyText)(url)) {
31145
+ if (await (0, import_clipboard7.copyText)(url)) {
31118
31146
  said2("Link copied");
31119
31147
  } else {
31120
31148
  notify?.error("Couldn\u2019t copy the link");
@@ -40221,7 +40249,7 @@ function clientNoun(table) {
40221
40249
  }
40222
40250
 
40223
40251
  // src/PortalsPanel.tsx
40224
- var import_clipboard7 = require("@ai-matrx/kit/clipboard");
40252
+ var import_clipboard8 = require("@ai-matrx/kit/clipboard");
40225
40253
  var import_react232 = require("react");
40226
40254
  var import_react233 = require("@ai-matrx/records/react");
40227
40255
  var import_records61 = require("@ai-matrx/records");
@@ -40822,7 +40850,7 @@ function CopyLink({ url, what }) {
40822
40850
  variant: "outline",
40823
40851
  onClick: () => {
40824
40852
  void (async () => {
40825
- if (await (0, import_clipboard7.copyText)(url)) {
40853
+ if (await (0, import_clipboard8.copyText)(url)) {
40826
40854
  setCopied(true);
40827
40855
  setShown(false);
40828
40856
  window.setTimeout(() => setCopied(false), 1600);
@@ -42125,7 +42153,7 @@ function SubscriptionsPanel({ tableId, activeRuleId, className }) {
42125
42153
  }
42126
42154
 
42127
42155
  // src/FormBuilder.tsx
42128
- var import_clipboard9 = require("@ai-matrx/kit/clipboard");
42156
+ var import_clipboard10 = require("@ai-matrx/kit/clipboard");
42129
42157
  var import_design_system123 = require("@ai-matrx/design-system");
42130
42158
  var import_react243 = require("react");
42131
42159
  var import_core21 = require("@dnd-kit/core");
@@ -42138,7 +42166,7 @@ var import_design_system124 = require("@ai-matrx/design-system");
42138
42166
  // src/FormFlowEditor.tsx
42139
42167
  var import_react240 = require("react");
42140
42168
  var import_design_system121 = require("@ai-matrx/design-system");
42141
- var import_clipboard8 = require("@ai-matrx/kit/clipboard");
42169
+ var import_clipboard9 = require("@ai-matrx/kit/clipboard");
42142
42170
  var import_forms = require("@ai-matrx/records/forms");
42143
42171
  var import_jsx_runtime138 = require("react/jsx-runtime");
42144
42172
  function freshEndingId(taken) {
@@ -42353,7 +42381,7 @@ function ThemeEditor({
42353
42381
  }
42354
42382
  var EMBED_LABELS = { inline: "Inline", popup: "Popup", slider: "Slider" };
42355
42383
  function EmbedSnippets({ url, label }) {
42356
- const { copyText: copyText14 } = (0, import_clipboard8.useClipboard)();
42384
+ const { copyText: copyText16 } = (0, import_clipboard9.useClipboard)();
42357
42385
  const [kind, setKind] = (0, import_react240.useState)("inline");
42358
42386
  const [copied, setCopied] = (0, import_react240.useState)(false);
42359
42387
  const snippet = (0, import_forms.formEmbedSnippet)(kind, url, { label });
@@ -42367,7 +42395,7 @@ function EmbedSnippets({ url, label }) {
42367
42395
  size: "sm",
42368
42396
  variant: "outline",
42369
42397
  className: "ml-auto",
42370
- onClick: () => void copyText14(snippet).then((ok) => {
42398
+ onClick: () => void copyText16(snippet).then((ok) => {
42371
42399
  setCopied(Boolean(ok));
42372
42400
  window.setTimeout(() => setCopied(false), 1500);
42373
42401
  }),
@@ -43287,7 +43315,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, startWithOne,
43287
43315
  await load();
43288
43316
  }
43289
43317
  async function copyLink(url) {
43290
- if (await (0, import_clipboard9.copyText)(url)) {
43318
+ if (await (0, import_clipboard10.copyText)(url)) {
43291
43319
  setCopied(true);
43292
43320
  setShownUrl(null);
43293
43321
  window.setTimeout(() => setCopied(false), 1600);
@@ -46065,7 +46093,7 @@ function TargetControl({
46065
46093
  }
46066
46094
 
46067
46095
  // src/QuestionPanel.tsx
46068
- var import_clipboard10 = require("@ai-matrx/kit/clipboard");
46096
+ var import_clipboard11 = require("@ai-matrx/kit/clipboard");
46069
46097
  var import_react262 = require("react");
46070
46098
  var import_design_system133 = require("@ai-matrx/design-system");
46071
46099
  var import_react263 = require("@ai-matrx/records/react");
@@ -46236,7 +46264,7 @@ function QuestionPanel({ tableId, activeQuestionId, draft, className }) {
46236
46264
  const url = new URL(window.location.href);
46237
46265
  url.searchParams.set("view", "questions");
46238
46266
  url.searchParams.set("item", current.id);
46239
- void (0, import_clipboard10.copyText)(url.toString());
46267
+ void (0, import_clipboard11.copyText)(url.toString());
46240
46268
  };
46241
46269
  if (fields.loading || hidden === null) {
46242
46270
  return /* @__PURE__ */ (0, import_jsx_runtime150.jsxs)("div", { className: (0, import_design_system133.cn)("flex flex-col gap-2 p-3", className), "data-testid": "question-panel", children: [
@@ -47709,7 +47737,7 @@ function onePerKey3(all) {
47709
47737
  }
47710
47738
 
47711
47739
  // src/FormsPanel.tsx
47712
- var import_clipboard11 = require("@ai-matrx/kit/clipboard");
47740
+ var import_clipboard12 = require("@ai-matrx/kit/clipboard");
47713
47741
  var import_react268 = require("react");
47714
47742
  var import_react269 = require("@ai-matrx/records/react");
47715
47743
  var import_records68 = require("@ai-matrx/records");
@@ -47768,7 +47796,7 @@ function FormsPanel({ tableId, activeFormId, className }) {
47768
47796
  );
47769
47797
  const [shown4, setShown] = (0, import_react268.useState)(null);
47770
47798
  const copy = (0, import_react268.useCallback)(async (url, formId) => {
47771
- if (await (0, import_clipboard11.copyText)(url)) {
47799
+ if (await (0, import_clipboard12.copyText)(url)) {
47772
47800
  setCopied(formId);
47773
47801
  setShown(null);
47774
47802
  window.setTimeout(() => setCopied(null), 1600);
@@ -48727,7 +48755,7 @@ function PublicRow({ row, fields }) {
48727
48755
  }
48728
48756
 
48729
48757
  // src/EmbedFrame.tsx
48730
- var import_clipboard12 = require("@ai-matrx/kit/clipboard");
48758
+ var import_clipboard13 = require("@ai-matrx/kit/clipboard");
48731
48759
  var import_react278 = require("react");
48732
48760
  var import_react279 = require("@ai-matrx/records/react");
48733
48761
  var import_design_system141 = require("@ai-matrx/design-system");
@@ -48825,7 +48853,7 @@ function EmbedFrame({
48825
48853
  {
48826
48854
  size: "sm",
48827
48855
  variant: "outline",
48828
- onClick: () => void (0, import_clipboard12.copyText)(snippet ?? ""),
48856
+ onClick: () => void (0, import_clipboard13.copyText)(snippet ?? ""),
48829
48857
  children: "Copy"
48830
48858
  }
48831
48859
  ),
@@ -48863,7 +48891,7 @@ function useEmbedHandshake(args) {
48863
48891
  }
48864
48892
 
48865
48893
  // src/TablePage.tsx
48866
- var import_clipboard15 = require("@ai-matrx/kit/clipboard");
48894
+ var import_clipboard17 = require("@ai-matrx/kit/clipboard");
48867
48895
  var import_react291 = require("react");
48868
48896
  var import_records70 = require("@ai-matrx/records");
48869
48897
  var import_react292 = require("@ai-matrx/records/react");
@@ -48890,15 +48918,23 @@ function subscribeCalendarAction(args) {
48890
48918
  }
48891
48919
 
48892
48920
  // src/CalendarSubscribe.tsx
48893
- var import_clipboard13 = require("@ai-matrx/kit/clipboard");
48921
+ var import_clipboard14 = require("@ai-matrx/kit/clipboard");
48894
48922
  var import_react281 = require("react");
48923
+
48924
+ // src/asRefusal.ts
48925
+ function asRefusal3(e, fallback) {
48926
+ if (e instanceof Error && e.message.trim() !== "") return e;
48927
+ return { message: fallback };
48928
+ }
48929
+
48930
+ // src/CalendarSubscribe.tsx
48895
48931
  var import_design_system142 = require("@ai-matrx/design-system");
48896
48932
  var import_jsx_runtime159 = require("react/jsx-runtime");
48897
48933
  function CalendarLinkOnce({ url }) {
48898
48934
  const notify = useRecordsUi().notify;
48899
48935
  const [copied, setCopied] = (0, import_react281.useState)(false);
48900
48936
  const copy = async () => {
48901
- if (await (0, import_clipboard13.copyText)(url)) {
48937
+ if (await (0, import_clipboard14.copyText)(url)) {
48902
48938
  setCopied(true);
48903
48939
  notify?.success("Link copied");
48904
48940
  } else notify?.error("Couldn\u2019t copy the link");
@@ -48950,7 +48986,7 @@ function CalendarSubscribeDialog({
48950
48986
  });
48951
48987
  setUrl(port.urlFor(made.token));
48952
48988
  } catch (e) {
48953
- setError(e instanceof Error ? e.message : "The link could not be made");
48989
+ setError(asRefusal3(e, "The link could not be made"));
48954
48990
  } finally {
48955
48991
  setBusy(false);
48956
48992
  }
@@ -48960,12 +48996,13 @@ function CalendarSubscribeDialog({
48960
48996
  /* @__PURE__ */ (0, import_jsx_runtime159.jsx)("p", { className: "text-sm text-muted-foreground", children: "Shows the rows this view shows, read as you." }),
48961
48997
  url ? /* @__PURE__ */ (0, import_jsx_runtime159.jsx)(CalendarLinkOnce, { url }) : /* @__PURE__ */ (0, import_jsx_runtime159.jsxs)("div", { className: "flex flex-col gap-2", children: [
48962
48998
  /* @__PURE__ */ (0, import_jsx_runtime159.jsx)(import_design_system142.Button, { size: "sm", onClick: () => void make(), disabled: busy, "data-calendar-make": "", children: busy ? "Making\u2026" : "Make link" }),
48963
- error ? /* @__PURE__ */ (0, import_jsx_runtime159.jsx)("p", { role: "alert", className: "text-sm text-destructive", "data-calendar-error": "", children: error }) : null
48999
+ error ? /* @__PURE__ */ (0, import_jsx_runtime159.jsx)(RefusalNotice, { error }) : null
48964
49000
  ] })
48965
49001
  ] }) });
48966
49002
  }
48967
49003
 
48968
49004
  // src/viewShare.ts
49005
+ var import_clipboard15 = require("@ai-matrx/kit/clipboard");
48969
49006
  var import_core24 = require("@ai-matrx/records/core");
48970
49007
  var NO_VIEW_REASON = "No saved view yet";
48971
49008
  function viewLink(tableId, viewId, origin) {
@@ -49005,6 +49042,56 @@ async function downloadViewCsv(args) {
49005
49042
  download(`${name}.csv`, "text/csv;charset=utf-8", (0, import_core24.exportCsv)(columns, rows));
49006
49043
  host.notify?.success(read.cut ? cutWords(read.rows.length) : "CSV downloaded");
49007
49044
  }
49045
+ function downloadMarkdownAction(args) {
49046
+ return {
49047
+ id: "download-markdown",
49048
+ label: "Download Markdown",
49049
+ icon: "file-text",
49050
+ group: "share",
49051
+ ...args.disabledReason ? { disabledReason: args.disabledReason } : {},
49052
+ run: args.run
49053
+ };
49054
+ }
49055
+ function copyMarkdownAction(args) {
49056
+ return {
49057
+ id: "copy-markdown",
49058
+ label: "Copy as Markdown",
49059
+ icon: "copy",
49060
+ group: "share",
49061
+ ...args.disabledReason ? { disabledReason: args.disabledReason } : {},
49062
+ run: args.run
49063
+ };
49064
+ }
49065
+ async function readViewMarkdown(args) {
49066
+ const { client, host, tableId, fields, view, labels } = args;
49067
+ const read = await readViewRows(client, tableId, fields, view, args.ceiling);
49068
+ if ("error" in read) return null;
49069
+ const columns = viewColumns(fields, view.presentation);
49070
+ const rows = await rowsForFile({ client, host, fields: columns, records: read.rows, labels });
49071
+ return { markdown: (0, import_core24.exportMarkdown)(columns, rows), cut: read.cut, count: read.rows.length };
49072
+ }
49073
+ async function downloadViewMarkdown(args) {
49074
+ const table = await readViewMarkdown(args);
49075
+ if (!table) {
49076
+ args.host.notify?.error("The Markdown could not be written");
49077
+ return;
49078
+ }
49079
+ const name = fileNameOf(args.tableName) || "records";
49080
+ download(`${name}.md`, "text/markdown;charset=utf-8", table.markdown);
49081
+ args.host.notify?.success(table.cut ? cutWords(table.count) : "Markdown downloaded");
49082
+ }
49083
+ async function copyViewMarkdown(args) {
49084
+ const table = await readViewMarkdown(args);
49085
+ if (!table) {
49086
+ args.host.notify?.error("The Markdown could not be written");
49087
+ return;
49088
+ }
49089
+ if (await (0, import_clipboard15.copyText)(table.markdown)) {
49090
+ args.host.notify?.success(table.cut ? cutWords(table.count) : "Markdown copied");
49091
+ } else {
49092
+ args.host.notify?.error("Couldn\u2019t copy the Markdown");
49093
+ }
49094
+ }
49008
49095
 
49009
49096
  // src/RecordPanel.tsx
49010
49097
  var import_react282 = require("react");
@@ -49155,7 +49242,7 @@ function BreakDownDialog({
49155
49242
  }
49156
49243
 
49157
49244
  // src/TableReference.tsx
49158
- var import_clipboard14 = require("@ai-matrx/kit/clipboard");
49245
+ var import_clipboard16 = require("@ai-matrx/kit/clipboard");
49159
49246
  var import_react285 = require("react");
49160
49247
  var import_workspace2 = require("@ai-matrx/alchemy/react/workspace");
49161
49248
  var import_design_system145 = require("@ai-matrx/design-system");
@@ -49193,7 +49280,7 @@ function TableReferenceDialog({
49193
49280
  async (choice) => {
49194
49281
  if (!port) return;
49195
49282
  try {
49196
- if (!await (0, import_clipboard14.copyText)(await port.build(choice.reference))) throw new Error("clipboard refused");
49283
+ if (!await (0, import_clipboard16.copyText)(await port.build(choice.reference))) throw new Error("clipboard refused");
49197
49284
  setCopied(choice.id);
49198
49285
  notify?.success("Reference copied");
49199
49286
  } catch {
@@ -50432,7 +50519,7 @@ function TablePage({
50432
50519
  viewId: view?.id ?? null,
50433
50520
  origin: actionOrigin,
50434
50521
  copy: async (text) => {
50435
- if (await (0, import_clipboard15.copyText)(text)) {
50522
+ if (await (0, import_clipboard17.copyText)(text)) {
50436
50523
  recordsUi.notify?.success("Link copied");
50437
50524
  } else {
50438
50525
  recordsUi.notify?.error("Couldn\u2019t copy the link");
@@ -50452,6 +50539,30 @@ function TablePage({
50452
50539
  labels: viewLabels
50453
50540
  })
50454
50541
  }),
50542
+ downloadMarkdownAction({
50543
+ ...mayDo.known && !mayDo.read ? { disabledReason: "Needs Viewer access" } : !allFields.data ? { disabledReason: "Reading this table\u2026" } : {},
50544
+ run: () => downloadViewMarkdown({
50545
+ client,
50546
+ host: recordsUi,
50547
+ tableId,
50548
+ tableName: table.data?.name ?? "",
50549
+ fields: allFields.data ?? [],
50550
+ view: viewReading,
50551
+ labels: viewLabels
50552
+ })
50553
+ }),
50554
+ copyMarkdownAction({
50555
+ ...mayDo.known && !mayDo.read ? { disabledReason: "Needs Viewer access" } : !allFields.data ? { disabledReason: "Reading this table\u2026" } : {},
50556
+ run: () => copyViewMarkdown({
50557
+ client,
50558
+ host: recordsUi,
50559
+ tableId,
50560
+ tableName: table.data?.name ?? "",
50561
+ fields: allFields.data ?? [],
50562
+ view: viewReading,
50563
+ labels: viewLabels
50564
+ })
50565
+ }),
50455
50566
  // THE PRIVATE CALENDAR LINK (CAL-FEED-UI): only where the host bound the doors.
50456
50567
  ...recordsUi.calendarFeed && organizationId ? [
50457
50568
  subscribeCalendarAction({
@@ -50465,7 +50576,7 @@ function TablePage({
50465
50576
  window.open(url, "_blank", "noopener,noreferrer");
50466
50577
  },
50467
50578
  copyText: async (url) => {
50468
- if (await (0, import_clipboard15.copyText)(url)) {
50579
+ if (await (0, import_clipboard17.copyText)(url)) {
50469
50580
  recordsUi.notify?.success("Link copied");
50470
50581
  } else {
50471
50582
  recordsUi.notify?.error("Couldn\u2019t copy the link");
@@ -51730,7 +51841,7 @@ function CalendarLinks({ port }) {
51730
51841
  setRows(await port.list());
51731
51842
  setError(null);
51732
51843
  } catch (e) {
51733
- setError(e instanceof Error ? e.message : "The links could not be read");
51844
+ setError(asRefusal3(e, "The links could not be read"));
51734
51845
  }
51735
51846
  }, [port]);
51736
51847
  (0, import_react300.useEffect)(() => {
@@ -51741,12 +51852,12 @@ function CalendarLinks({ port }) {
51741
51852
  await run();
51742
51853
  setError(null);
51743
51854
  } catch (e) {
51744
- setError(e instanceof Error ? e.message : "That didn\u2019t work");
51855
+ setError(asRefusal3(e, "That didn\u2019t work"));
51745
51856
  }
51746
51857
  };
51747
51858
  if (rows === null && !error) return /* @__PURE__ */ (0, import_jsx_runtime172.jsx)("p", { className: "text-sm text-muted-foreground", "data-calendar-links-loading": "", children: "Reading your links\u2026" });
51748
51859
  return /* @__PURE__ */ (0, import_jsx_runtime172.jsxs)("div", { className: "flex flex-col gap-2", "data-calendar-links": "", children: [
51749
- error ? /* @__PURE__ */ (0, import_jsx_runtime172.jsx)("p", { role: "alert", className: "text-sm text-destructive", "data-calendar-error": "", children: error }) : null,
51860
+ error ? /* @__PURE__ */ (0, import_jsx_runtime172.jsx)(RefusalNotice, { error }) : null,
51750
51861
  rows && rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime172.jsx)("p", { className: "text-sm text-muted-foreground", children: "No calendar links yet." }) : null,
51751
51862
  rows?.map((row) => /* @__PURE__ */ (0, import_jsx_runtime172.jsxs)("div", { className: "flex flex-col gap-2 rounded-md border px-3 py-2", "data-calendar-link-row": row.id, children: [
51752
51863
  /* @__PURE__ */ (0, import_jsx_runtime172.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [