@ai-matrx/records-ui 0.115.38 → 0.115.40

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
@@ -6029,9 +6029,12 @@ function withheldNoticeOf(hidden, key) {
6029
6029
  return notice && typeof notice === "object" ? notice : null;
6030
6030
  }
6031
6031
  function withheldSentence(field2, notice) {
6032
- const says = notice.says;
6033
- if (typeof says === "string" && says.trim() !== "") return says.trim();
6032
+ const extra = notice;
6033
+ if (typeof extra.says === "string" && extra.says.trim() !== "") return extra.says.trim();
6034
6034
  const name = fieldName(field2);
6035
+ if (typeof extra.part === "string" && extra.part.trim() !== "" && typeof extra.who === "string" && extra.who.trim() !== "") {
6036
+ return `${name} is in ${extra.part.trim()} \u2014 ${extra.who.trim()} see it.`;
6037
+ }
6035
6038
  const reason = notice.reason ? ` It is ${notice.reason}` : "";
6036
6039
  const needs = notice.needs ? `${reason ? "," : " It"} and reading it needs ${notice.needs}` : "";
6037
6040
  const or = notice.or ? `${needs || reason ? ", or" : " It needs"} ${notice.or}` : "";
@@ -11978,6 +11981,9 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
11978
11981
  const startedFrom = (0, import_react66.useRef)(null);
11979
11982
  const startedStored = (0, import_react66.useRef)(null);
11980
11983
  const host = useRecordsUi();
11984
+ const fieldsRef = (0, import_react66.useRef)(fields);
11985
+ fieldsRef.current = fields;
11986
+ const forceNext = (0, import_react66.useRef)(/* @__PURE__ */ new Set());
11981
11987
  const type = (0, import_react66.useCallback)((value) => {
11982
11988
  typed2.current = value;
11983
11989
  setDraft(value);
@@ -12134,6 +12140,47 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
12134
12140
  delete next[id];
12135
12141
  return next;
12136
12142
  });
12143
+ const syncedField = fieldsRef.current.find((f) => f.key === key);
12144
+ if (syncedField?.source === "synced" && host.writeSyncedCell) {
12145
+ const force = forceNext.current.delete(id);
12146
+ let outcome;
12147
+ try {
12148
+ outcome = await host.writeSyncedCell({ tableId, recordId: rowId, fieldKey: key, value: shown5, force });
12149
+ } catch (thrown) {
12150
+ outcome = { ok: false, message: thrown instanceof Error ? thrown.message : String(thrown) };
12151
+ }
12152
+ setSaving((held) => {
12153
+ const next = { ...held };
12154
+ delete next[id];
12155
+ return next;
12156
+ });
12157
+ if (outcome.ok && outcome.status === "written") {
12158
+ if (typeof outcome.version === "number") {
12159
+ rememberVersion(versions.current, rowId, outcome.version);
12160
+ source.wrote(rowId, outcome.version);
12161
+ }
12162
+ settling.current.set(id, base2);
12163
+ writtenRef.current?.({ rowId, key, before: base2, after: shown5 });
12164
+ afterWrite();
12165
+ return;
12166
+ }
12167
+ setOptimistic((held) => {
12168
+ const next = { ...held };
12169
+ delete next[id];
12170
+ return next;
12171
+ });
12172
+ const sheetValue = outcome.ok ? outcome.sheetValue : null;
12173
+ setRefusals((held) => ({
12174
+ ...held,
12175
+ [id]: outcome.ok ? {
12176
+ error: { code: "stale_write", message: `The sheet now says "${sheetValue ?? ""}". Retry keeps yours.` },
12177
+ conflict: null,
12178
+ attempted: value,
12179
+ sheet: { value: sheetValue }
12180
+ } : { error: { code: "refused_by_rule", message: outcome.message }, conflict: null, attempted: value }
12181
+ }));
12182
+ return;
12183
+ }
12137
12184
  let written;
12138
12185
  try {
12139
12186
  let version = await versionOf(source, versions.current, versionReads.current, rowId);
@@ -12293,6 +12340,7 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
12293
12340
  (rowId, key) => {
12294
12341
  const held = refusals[cellKey(rowId, key)];
12295
12342
  if (!held) return;
12343
+ if (held.sheet) forceNext.current.add(cellKey(rowId, key));
12296
12344
  void writeCell(rowId, key, held.attempted, held.conflict?.contested_fields[key]);
12297
12345
  },
12298
12346
  [refusals, writeCell]
@@ -16955,6 +17003,7 @@ function useMergedGridControls(args) {
16955
17003
  } = args;
16956
17004
  const client = (0, import_react101.useRecordsClient)();
16957
17005
  const linkRecord = useRecordsUi().linkRecord;
17006
+ const columnAccess = useRecordsUi().columnAccess;
16958
17007
  const hrefForRecord = useRecordsUi().hrefForRecord;
16959
17008
  const tableVersion = (0, recordVersions_exports.useTableVersion)(client, tableId, table);
16960
17009
  const mutation = (0, import_react101.useFieldMutation)();
@@ -17136,6 +17185,14 @@ function useMergedGridControls(args) {
17136
17185
  writeLook({ ...rest, ...next.size > 0 ? { wrapColumns: [...next] } : {} });
17137
17186
  }
17138
17187
  });
17188
+ if (columnAccess) {
17189
+ out.push({
17190
+ id: "col-access",
17191
+ label: "Who can see and edit\u2026",
17192
+ disabledReason: rights.structure ? void 0 : rights.why("structure"),
17193
+ onSelect: () => setDialog({ kind: "access", field: field2 })
17194
+ });
17195
+ }
17139
17196
  out.push({
17140
17197
  id: "col-duplicate",
17141
17198
  label: "Duplicate property",
@@ -17417,6 +17474,7 @@ function useMergedGridControls(args) {
17417
17474
  }
17418
17475
  };
17419
17476
  }, [
17477
+ columnAccess,
17420
17478
  args,
17421
17479
  colours,
17422
17480
  fieldKeys,
@@ -17467,6 +17525,13 @@ function useMergedGridControls(args) {
17467
17525
  const close = () => setDialog(null);
17468
17526
  const dialogs = !enabled ? null : /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_jsx_runtime63.Fragment, { children: [
17469
17527
  colours.dialogs,
17528
+ dialog?.kind === "access" && columnAccess ? columnAccess({
17529
+ tableId,
17530
+ fieldId: dialog.field.id,
17531
+ name: fieldName(dialog.field),
17532
+ onClose: () => setDialog(null),
17533
+ onChanged: () => (0, import_react101.tableShapeChanged)(tableId)
17534
+ }) : null,
17470
17535
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(RowActionsDialog, { tableId, open: rowActionsOpen, onOpenChange: setRowActionsOpen }),
17471
17536
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
17472
17537
  RowLabelPicker,
@@ -20007,6 +20072,40 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
20007
20072
  const name = fieldName(field2);
20008
20073
  const format = cellFormatFor(field2, look?.format);
20009
20074
  const workedOut = workedOutFrom(field2);
20075
+ const syncedMark = field2.source === "synced" ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
20076
+ "span",
20077
+ {
20078
+ "data-records-synced": field2.key,
20079
+ title: `Synced from ${look?.syncedFrom || "its source"}`,
20080
+ "aria-label": `Synced from ${look?.syncedFrom || "its source"}`,
20081
+ className: "text-[10px] text-muted-foreground",
20082
+ children: "\u27F3"
20083
+ }
20084
+ ) : null;
20085
+ const restricted = field2.sensitivity === "confidential" || field2.sensitivity === "restricted";
20086
+ const lockMark = restricted ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
20087
+ "span",
20088
+ {
20089
+ "data-records-restricted": field2.key,
20090
+ title: "Fewer people see this column",
20091
+ "aria-label": "Fewer people see this column",
20092
+ className: "inline-flex text-muted-foreground",
20093
+ children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("svg", { viewBox: "0 0 24 24", width: "11", height: "11", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
20094
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("rect", { x: "4", y: "11", width: "16", height: "10", rx: "2" }),
20095
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("path", { d: "M8 11V7a4 4 0 0 1 8 0v4" })
20096
+ ] })
20097
+ }
20098
+ ) : null;
20099
+ const withSynced = (inner2) => {
20100
+ const header = lockMark ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
20101
+ inner2,
20102
+ lockMark
20103
+ ] }) : inner2;
20104
+ return syncedMark ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
20105
+ syncedMark,
20106
+ header
20107
+ ] }) : header;
20108
+ };
20010
20109
  return {
20011
20110
  id: field2.key,
20012
20111
  /*
@@ -20014,38 +20113,40 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
20014
20113
  * (`custom.formula_eval`, on read or on write) and nobody types it — so its header carries
20015
20114
  * the mark, and the formula it is worked out from is one hover away, in its own words.
20016
20115
  */
20017
- header: look?.rowLabel ? (
20018
- // THE COLUMN THAT NAMES EACH RECORD says so (tranche 6i, the older grid's key marker).
20019
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
20116
+ header: withSynced(
20117
+ look?.rowLabel ? (
20118
+ // THE COLUMN THAT NAMES EACH RECORD says so (tranche 6i, the older grid's key marker).
20119
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
20120
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
20121
+ "span",
20122
+ {
20123
+ "data-records-row-label": field2.key,
20124
+ title: "This column names each record",
20125
+ "aria-label": "Names each record",
20126
+ className: "text-[10px] text-muted-foreground",
20127
+ children: "\u26BF"
20128
+ }
20129
+ ),
20130
+ name
20131
+ ] })
20132
+ ) : workedOut && stampMarkOf(field2) ? (
20133
+ // A STAMP OR A RECORD NUMBER (walk 2026-10-08 D7): kept by the store, but nobody wrote a formula
20134
+ // for it, so its header wears its own mark — a clock, a person, a number sign — never "fx".
20135
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "inline-flex items-center", title: workedOut, "data-records-stamp": stampMarkOf(field2), children: withTypeMark(field2, name) })
20136
+ ) : workedOut ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
20137
+ name,
20020
20138
  /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
20021
20139
  "span",
20022
20140
  {
20023
- "data-records-row-label": field2.key,
20024
- title: "This column names each record",
20025
- "aria-label": "Names each record",
20026
- className: "text-[10px] text-muted-foreground",
20027
- children: "\u26BF"
20141
+ "data-records-worked-out": field2.key,
20142
+ title: workedOut,
20143
+ "aria-label": workedOut,
20144
+ className: "rounded bg-muted px-1 font-mono text-[10px] font-normal text-muted-foreground",
20145
+ children: "fx"
20028
20146
  }
20029
- ),
20030
- name
20031
- ] })
20032
- ) : workedOut && stampMarkOf(field2) ? (
20033
- // A STAMP OR A RECORD NUMBER (walk 2026-10-08 D7): kept by the store, but nobody wrote a formula
20034
- // for it, so its header wears its own mark — a clock, a person, a number sign — never "fx".
20035
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "inline-flex items-center", title: workedOut, "data-records-stamp": stampMarkOf(field2), children: withTypeMark(field2, name) })
20036
- ) : workedOut ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
20037
- name,
20038
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
20039
- "span",
20040
- {
20041
- "data-records-worked-out": field2.key,
20042
- title: workedOut,
20043
- "aria-label": workedOut,
20044
- className: "rounded bg-muted px-1 font-mono text-[10px] font-normal text-muted-foreground",
20045
- children: "fx"
20046
- }
20047
- )
20048
- ] }) : name,
20147
+ )
20148
+ ] }) : name
20149
+ ),
20049
20150
  label: name,
20050
20151
  accessorFn: (row) => row.document?.[field2.key],
20051
20152
  // A column the store keeps no value for is not offered a sort it would refuse (`sortRefusal`).
@@ -21236,7 +21337,7 @@ function columnsSentence(mapped, total, unmapped) {
21236
21337
  if (unmapped === "ignore") return `${mapped} of ${total} columns go into this table \xB7 ${rest} left out`;
21237
21338
  return `${mapped} of ${total} go in now \xB7 ${rest} wait for approval with their values`;
21238
21339
  }
21239
- function ImportWizard({ tableId, source, onDone, onWrote, className }) {
21340
+ function ImportWizard({ tableId, source, onDone, onWrote, autoRun, className }) {
21240
21341
  const client = (0, import_react120.useRecordsClient)();
21241
21342
  const table = (0, import_react120.useTable)(tableId);
21242
21343
  const fields = (0, import_react120.useFields)(tableId);
@@ -21858,6 +21959,13 @@ function ImportWizard({ tableId, source, onDone, onWrote, className }) {
21858
21959
  const refusedByRules = ruleVerdicts.reduce((n, v) => n + v.refused, 0);
21859
21960
  const [goAheadAnyway, setGoAheadAnyway] = (0, import_react119.useState)(false);
21860
21961
  (0, import_react119.useEffect)(() => setGoAheadAnyway(false), [ruleVerdicts]);
21962
+ const [autoRan, setAutoRan] = (0, import_react119.useState)(false);
21963
+ (0, import_react119.useEffect)(() => {
21964
+ if (!autoRun || autoRan || !source || phase !== "ready" || !plan) return;
21965
+ if (busy || !rights.write || rows.length === 0 || titleMissing || ruleVerdicts.length > 0) return;
21966
+ setAutoRan(true);
21967
+ void run();
21968
+ }, [autoRun, autoRan, source, phase, plan, busy, rights.write, rows.length, titleMissing, ruleVerdicts, run]);
21861
21969
  const afterWrite = !busy && (phase === "done" || alreadyRan !== null || ledger !== null && ledger.seen > 0);
21862
21970
  return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: (0, import_design_system64.cn)("flex min-w-0 flex-col gap-2 text-xs", className), children: [
21863
21971
  /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "flex items-center gap-2", children: [
@@ -25981,7 +26089,8 @@ function GridBody({
25981
26089
  ...presentation.formats?.[field2.key] ? { format: presentation.formats[field2.key] } : {},
25982
26090
  frozen: frozenKeys.has(field2.key),
25983
26091
  // The column that names each record wears the mark (merged grid, tranche 6i).
25984
- rowLabel: merged && field2.key === (table.data?.title_field ?? null)
26092
+ rowLabel: merged && field2.key === (table.data?.title_field ?? null),
26093
+ syncedFrom: syncedFromWords(table.data)
25985
26094
  },
25986
26095
  onAskWhoChanged,
25987
26096
  {
@@ -27170,6 +27279,12 @@ function withHeaderMenus(columns, menuFor, filterFor) {
27170
27279
  return filter ? { ...withMenu, ...filter } : withMenu;
27171
27280
  });
27172
27281
  }
27282
+ function syncedFromWords(table) {
27283
+ const source = table?.sync_source;
27284
+ if (!source?.provider) return null;
27285
+ const from = source.provider === "google_sheets" ? "Google Sheets" : source.provider === "csv_url" ? "a CSV link" : source.provider === "postgres" ? "an outside database" : source.provider === "matrx_view" ? "another table" : source.provider;
27286
+ return source.label ? `${from} \xB7 ${source.label}` : from;
27287
+ }
27173
27288
  function withoutGoneColumns(query, liveKeys, openingSort) {
27174
27289
  const sortGone = Boolean(query.sort && !liveKeys.has(query.sort.id));
27175
27290
  const goneFilters = Object.keys(query.columnFilters ?? {}).filter((key) => !liveKeys.has(key));
@@ -28404,7 +28519,7 @@ function NewTableStart({
28404
28519
  /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(import_design_system74.Button, { disabled: !importReady || busy, onClick: () => void continueImport(), "data-new-table-continue": "", children: busy ? "Creating\u2026" : "Next: columns" })
28405
28520
  ] });
28406
28521
  } else {
28407
- body = /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { "data-new-table-wizard": "", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ImportWizard, { tableId: step2.tableId, source: step2.source, onDone: () => onOpenTable?.(step2.tableId) }) });
28522
+ body = /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { "data-new-table-wizard": "", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ImportWizard, { tableId: step2.tableId, source: step2.source, autoRun: step2.made, onDone: () => onOpenTable?.(step2.tableId) }) });
28408
28523
  footer = /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(import_jsx_runtime89.Fragment, { children: [
28409
28524
  !step2.made ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(import_design_system74.Button, { variant: "ghost", className: "mr-auto", onClick: () => setStep({ at: "import" }), children: "Back" }) : null,
28410
28525
  /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(import_design_system74.Button, { variant: "outline", onClick: () => onOpenTable?.(step2.tableId), "data-new-table-open": "", children: "Open the table" })
@@ -35168,6 +35283,7 @@ function TimelineView({
35168
35283
  const [dragging, setDragging] = (0, import_react207.useState)(null);
35169
35284
  const [linking, setLinking] = (0, import_react207.useState)(null);
35170
35285
  const [ganttBusy, setGanttBusy] = (0, import_react207.useState)(false);
35286
+ const [linkTarget, setLinkTarget] = (0, import_react207.useState)(null);
35171
35287
  const { placed, unscheduled } = (0, import_react207.useMemo)(() => {
35172
35288
  const out = [];
35173
35289
  const without = [];
@@ -35336,6 +35452,18 @@ function TimelineView({
35336
35452
  label: `${titleOf(target)} now waits on ${titleOf(source)}`
35337
35453
  });
35338
35454
  };
35455
+ const taskRowAt = (x, y) => {
35456
+ const canvas = scroller.current?.querySelector("[data-timeline-canvas]");
35457
+ const body2 = scroller.current;
35458
+ if (!canvas || !body2) return null;
35459
+ const box = canvas.getBoundingClientRect();
35460
+ const frame2 = body2.getBoundingClientRect();
35461
+ if (frame2.width === 0 || x < frame2.left || x > frame2.right) return null;
35462
+ const index = Math.floor((y - box.top - LANE_PAD / 2) / ROW_PX);
35463
+ if (index < 0) return null;
35464
+ const lane = laneRows[0];
35465
+ return lane?.packed.find((b) => b.row === index)?.p.row.id ?? null;
35466
+ };
35339
35467
  const beginLink = (p) => (e) => {
35340
35468
  if (e.button !== void 0 && e.button !== 0) return;
35341
35469
  e.stopPropagation();
@@ -35344,13 +35472,21 @@ function TimelineView({
35344
35472
  const x1 = box.left + box.width / 2;
35345
35473
  const y1 = box.top + box.height / 2;
35346
35474
  setLinking({ id: p.row.id, x1, y1, x2: e.clientX, y2: e.clientY });
35347
- const onMove = (ev) => setLinking((l) => l ? { ...l, x2: ev.clientX, y2: ev.clientY } : l);
35475
+ const onMove = (ev) => {
35476
+ const x = ev.clientX;
35477
+ const y = ev.clientY;
35478
+ setLinking((l) => l ? { ...l, x2: x, y2: y } : l);
35479
+ const over = taskRowAt(x, y);
35480
+ setLinkTarget(over && over !== p.row.id ? over : null);
35481
+ };
35348
35482
  const onUp = (ev) => {
35349
35483
  window.removeEventListener("pointermove", onMove);
35350
35484
  window.removeEventListener("pointerup", onUp);
35351
35485
  setLinking(null);
35486
+ setLinkTarget(null);
35487
+ const at = ev;
35352
35488
  const hit = ev.target?.closest?.("[data-timeline-bar]");
35353
- const id = hit?.getAttribute("data-timeline-bar");
35489
+ const id = taskRowAt(at.clientX, at.clientY) ?? hit?.getAttribute("data-timeline-bar");
35354
35490
  if (id && id !== p.row.id) connect(p.row.id, id);
35355
35491
  };
35356
35492
  window.addEventListener("pointermove", onMove);
@@ -35362,7 +35498,7 @@ function TimelineView({
35362
35498
  try {
35363
35499
  const make = async (current, key, label) => {
35364
35500
  if (current) return current.key;
35365
- const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label, type: "datetime", kind: "date" } });
35501
+ const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label, parity_type: "datetime", kind: "date" } });
35366
35502
  if (!made.ok) {
35367
35503
  moves.say(refusalSentence(made.error));
35368
35504
  return null;
@@ -35581,6 +35717,7 @@ function TimelineView({
35581
35717
  "data-timeline-span": `${first}..${last}`,
35582
35718
  ...p.marker ? { "data-timeline-marker": "" } : {},
35583
35719
  ...milestone ? { "data-timeline-milestone": "" } : {},
35720
+ ...linkTarget === p.row.id ? { "data-timeline-drop-target": "" } : {},
35584
35721
  ...onCritical ? { "data-timeline-critical": "" } : {},
35585
35722
  ...slip !== null ? { "data-timeline-slip": slip } : {},
35586
35723
  ...may ? {} : { "data-timeline-locked": "" },
@@ -35594,6 +35731,7 @@ function TimelineView({
35594
35731
  outside ? "overflow-visible" : "overflow-hidden",
35595
35732
  milestone ? "border-transparent bg-transparent" : color ? import_data_table22.CHOICE_CHIP_CLASS[color] : "bg-muted",
35596
35733
  onCritical ? "ring-2 ring-amber-500" : void 0,
35734
+ linkTarget === p.row.id ? "ring-2 ring-primary" : void 0,
35597
35735
  may ? "cursor-grab active:cursor-grabbing" : "cursor-pointer",
35598
35736
  dragging?.id === p.row.id ? "z-20 shadow-md" : "z-10",
35599
35737
  refused ? "ring-2 ring-destructive" : void 0
@@ -35675,7 +35813,7 @@ function TimelineView({
35675
35813
  /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [
35676
35814
  settings,
35677
35815
  /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)(import_design_system102.DropdownMenu, { children: [
35678
- /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(import_design_system102.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(import_design_system102.Button, { size: "sm", variant: ganttOn ? "secondary" : "outline", "aria-label": "Gantt options", "data-timeline-gantt-menu": "", children: "Gantt" }) }),
35816
+ /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(import_design_system102.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(import_design_system102.Button, { size: "sm", variant: "outline", className: ganttOn ? "bg-secondary" : void 0, "aria-label": "Gantt options", "data-timeline-gantt-menu": "", children: "Gantt" }) }),
35679
35817
  /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)(import_design_system102.DropdownMenuContent, { align: "end", className: "min-w-48", children: [
35680
35818
  /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(import_design_system102.DropdownMenuCheckboxItem, { checked: ganttOn, onCheckedChange: (on) => setGantt({ mode: on === true }), children: "Gantt view" }),
35681
35819
  ganttOn ? /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)(import_jsx_runtime120.Fragment, { children: [
@@ -35753,6 +35891,7 @@ function TimelineView({
35753
35891
  const ghost = baselineOf(b.p.row);
35754
35892
  const at = shown5(b.p);
35755
35893
  return /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("div", { children: [
35894
+ linkTarget === b.p.row.id ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)("div", { "aria-hidden": "true", "data-timeline-drop-band": b.p.row.id, className: "pointer-events-none absolute inset-x-0 bg-primary/10", style: { top: LANE_PAD / 2 + b.row * ROW_PX, height: ROW_PX } }) : null,
35756
35895
  ghost ? /* @__PURE__ */ (0, import_jsx_runtime120.jsx)(
35757
35896
  "div",
35758
35897
  {
@@ -39055,6 +39194,9 @@ function ArchivedPortals({
39055
39194
  var import_react230 = require("react");
39056
39195
  var import_react231 = require("@ai-matrx/records/react");
39057
39196
  var import_design_system112 = require("@ai-matrx/design-system");
39197
+ var import_core22 = require("@dnd-kit/core");
39198
+ var import_sortable = require("@dnd-kit/sortable");
39199
+ var import_utilities = require("@dnd-kit/utilities");
39058
39200
 
39059
39201
  // src/seedOnce.ts
39060
39202
  var import_react229 = require("react");
@@ -39076,7 +39218,7 @@ var NOOP3 = () => {
39076
39218
  };
39077
39219
  function viewActions(whyNot, host, locked = false, personal = false) {
39078
39220
  const one = (base2, run) => {
39079
- if (whyNot !== null) return { ...base2, disabledReason: whyNot, run: NOOP3 };
39221
+ if (whyNot !== null) return { ...base2, disabledReason: locked && base2.id !== "duplicate" && base2.id !== "lock" ? VIEW_LOCKED_REASON : whyNot, run: NOOP3 };
39080
39222
  if (!run) return { ...base2, disabledReason: ACTION_NOT_HERE_REASON, run: NOOP3 };
39081
39223
  return { ...base2, run };
39082
39224
  };
@@ -39119,6 +39261,25 @@ function seedIsSatisfied(seed, views) {
39119
39261
  if (views.some((v) => v.name === seed.name)) return true;
39120
39262
  return seed.isDefault === true && views.some((v) => v.isDefault);
39121
39263
  }
39264
+ function SectionBox({ id, children, ...rest }) {
39265
+ const { setNodeRef, isOver } = (0, import_core22.useDroppable)({ id });
39266
+ return /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("div", { ref: setNodeRef, className: (0, import_design_system112.cn)("rounded-sm", isOver && "bg-accent/40"), ...rest, children });
39267
+ }
39268
+ function SortableRow({ id, disabled, children }) {
39269
+ const { attributes, listeners: listeners2, setNodeRef, transform, transition, isDragging } = (0, import_sortable.useSortable)({ id, disabled });
39270
+ return /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
39271
+ "div",
39272
+ {
39273
+ ref: setNodeRef,
39274
+ style: { transform: import_utilities.CSS.Transform.toString(transform), transition },
39275
+ className: (0, import_design_system112.cn)(isDragging && "relative z-10 opacity-80"),
39276
+ "data-view-row": id,
39277
+ ...disabled ? {} : attributes,
39278
+ ...disabled ? {} : listeners2,
39279
+ children
39280
+ }
39281
+ );
39282
+ }
39122
39283
  function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews, initialViews, className }) {
39123
39284
  const client = (0, import_react231.useRecordsClient)();
39124
39285
  const claimSeed = useSeedGuard();
@@ -39150,6 +39311,26 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39150
39311
  }
39151
39312
  });
39152
39313
  const [renamingSection, setRenamingSection] = (0, import_react230.useState)(null);
39314
+ const [dragging, setDragging] = (0, import_react230.useState)(false);
39315
+ const justDragged = (0, import_react230.useRef)(false);
39316
+ const sensors = (0, import_core22.useSensors)((0, import_core22.useSensor)(import_core22.PointerSensor, { activationConstraint: { distance: 6 } }));
39317
+ async function dropped(event) {
39318
+ setDragging(false);
39319
+ justDragged.current = true;
39320
+ setTimeout(() => {
39321
+ justDragged.current = false;
39322
+ }, 250);
39323
+ if (!event.over || !views) return;
39324
+ const writes = (0, import_views2.planViewDrop)(views, String(event.active.id), String(event.over.id));
39325
+ for (const w of writes) {
39326
+ const written = await saveViewPatch(client, tableId, w.id, { position: w.position, ..."section" in w ? { section: w.section ?? null } : {} });
39327
+ if (!written.ok) {
39328
+ setError(written.error);
39329
+ break;
39330
+ }
39331
+ }
39332
+ if (writes.length > 0) await load();
39333
+ }
39153
39334
  const toggleShut = (name) => {
39154
39335
  setShut((all) => {
39155
39336
  const next = all.includes(name) ? all.filter((n) => n !== name) : [...all, name];
@@ -39362,83 +39543,89 @@ function ViewBar({ tableId, activeViewId, onActiveView, seed, settings, onViews,
39362
39543
  ) }),
39363
39544
  /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(import_design_system112.PopoverContent, { sizing: "content", align: "start", className: "w-64 p-1", "data-view-picker-content": "", children: [
39364
39545
  /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { role: "group", "aria-label": "Saved views", className: "flex max-h-[50dvh] flex-col overflow-y-auto", children: [
39365
- (0, import_views2.groupViewsBySection)(views).map((group) => /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { role: "group", "aria-label": group.name ?? "Views", "data-view-section": group.name ?? "", children: [
39366
- group.name !== null ? renamingSection?.from === group.name ? /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
39367
- "form",
39368
- {
39369
- className: "flex items-center gap-1 px-1 py-1",
39370
- onSubmit: (e) => {
39371
- e.preventDefault();
39372
- void renameSection(group.name, renamingSection.draft);
39373
- },
39374
- children: [
39375
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
39376
- import_design_system112.Input,
39377
- {
39378
- autoFocus: true,
39379
- "aria-label": "New name for this section",
39380
- value: renamingSection.draft,
39381
- onChange: (e) => setRenamingSection({ from: group.name, draft: e.target.value }),
39382
- onKeyDown: (e) => {
39383
- if (e.key === "Escape") {
39384
- e.preventDefault();
39385
- e.stopPropagation();
39386
- setRenamingSection(null);
39387
- }
39388
- },
39389
- className: "h-7 min-w-0 flex-1 text-xs"
39390
- }
39391
- ),
39392
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Button, { size: "sm", type: "submit", className: "h-7", children: "Save" })
39393
- ]
39394
- }
39395
- ) : /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { className: "group flex min-h-7 items-center gap-1 px-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: [
39396
- /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
39546
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_core22.DndContext, { sensors, collisionDetection: import_core22.closestCenter, onDragStart: () => setDragging(true), onDragCancel: () => setDragging(false), onDragEnd: (e) => void dropped(e), children: (() => {
39547
+ const groups = (0, import_views2.groupViewsBySection)(views);
39548
+ return groups.some((g) => g.name === null) || !dragging ? groups : [{ name: null, views: [] }, ...groups];
39549
+ })().map((group) => /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(SectionBox, { id: (0, import_views2.sectionDropId)(group.name), role: "group", "aria-label": group.name ?? "Views", "data-view-section": group.name ?? "", children: [
39550
+ group.name === null && group.views.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "block px-2 py-1.5 text-[11px] text-muted-foreground", children: "No section" }) : null,
39551
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(import_sortable.SortableContext, { items: group.views.map((v) => v.id), strategy: import_sortable.verticalListSortingStrategy, children: [
39552
+ group.name !== null ? renamingSection?.from === group.name ? /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
39553
+ "form",
39554
+ {
39555
+ className: "flex items-center gap-1 px-1 py-1",
39556
+ onSubmit: (e) => {
39557
+ e.preventDefault();
39558
+ void renameSection(group.name, renamingSection.draft);
39559
+ },
39560
+ children: [
39561
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(
39562
+ import_design_system112.Input,
39563
+ {
39564
+ autoFocus: true,
39565
+ "aria-label": "New name for this section",
39566
+ value: renamingSection.draft,
39567
+ onChange: (e) => setRenamingSection({ from: group.name, draft: e.target.value }),
39568
+ onKeyDown: (e) => {
39569
+ if (e.key === "Escape") {
39570
+ e.preventDefault();
39571
+ e.stopPropagation();
39572
+ setRenamingSection(null);
39573
+ }
39574
+ },
39575
+ className: "h-7 min-w-0 flex-1 text-xs"
39576
+ }
39577
+ ),
39578
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Button, { size: "sm", type: "submit", className: "h-7", children: "Save" })
39579
+ ]
39580
+ }
39581
+ ) : /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)("div", { className: "group flex min-h-7 items-center gap-1 px-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: [
39582
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
39583
+ "button",
39584
+ {
39585
+ type: "button",
39586
+ className: "flex min-w-0 flex-1 items-center gap-1 text-left",
39587
+ "aria-expanded": !shut.includes(group.name),
39588
+ "data-view-section-toggle": "",
39589
+ onClick: () => toggleShut(group.name),
39590
+ children: [
39591
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("svg", { viewBox: "0 0 24 24", className: (0, import_design_system112.cn)("h-3 w-3 shrink-0", shut.includes(group.name) && "-rotate-90"), fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("path", { d: "m6 9 6 6 6-6" }) }),
39592
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "truncate", children: group.name }),
39593
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "shrink-0 font-normal normal-case", children: group.views.length })
39594
+ ]
39595
+ }
39596
+ ),
39597
+ rights.admin ? /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(import_jsx_runtime131.Fragment, { children: [
39598
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("button", { type: "button", className: "shrink-0 normal-case hover:text-foreground", "data-view-section-rename": "", onClick: () => setRenamingSection({ from: group.name, draft: group.name }), children: "Rename" }),
39599
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("button", { type: "button", className: "shrink-0 normal-case hover:text-destructive", "data-view-section-delete": "", title: "The views stay; they leave the section", onClick: () => void renameSection(group.name, null), children: "Delete" })
39600
+ ] }) : null
39601
+ ] }) : null,
39602
+ group.name !== null && shut.includes(group.name) && !group.views.some((v) => v.id === active) ? null : group.views.map((view) => /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(SortableRow, { id: view.id, disabled: !(rights.admin || view.personal) || view.presentation?.locked === true, children: /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
39397
39603
  "button",
39398
39604
  {
39399
39605
  type: "button",
39400
- className: "flex min-w-0 flex-1 items-center gap-1 text-left",
39401
- "aria-expanded": !shut.includes(group.name),
39402
- "data-view-section-toggle": "",
39403
- onClick: () => toggleShut(group.name),
39606
+ "aria-pressed": view.id === active,
39607
+ className: (0, import_design_system112.cn)(
39608
+ "flex min-h-8 w-full items-center gap-2 rounded-sm px-2 text-left text-xs text-popover-foreground hover:bg-accent hover:text-accent-foreground",
39609
+ group.name !== null && "pl-4",
39610
+ view.id === active && "font-medium"
39611
+ ),
39612
+ onClick: () => {
39613
+ if (justDragged.current) return;
39614
+ setActive(view.id);
39615
+ onActiveView?.(view);
39616
+ setOpen(false);
39617
+ },
39618
+ title: view.ruleId ? "Membership is this view's Rule" : "The whole table",
39404
39619
  children: [
39405
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("svg", { viewBox: "0 0 24 24", className: (0, import_design_system112.cn)("h-3 w-3 shrink-0", shut.includes(group.name) && "-rotate-90"), fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("path", { d: "m6 9 6 6 6-6" }) }),
39406
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "truncate", children: group.name }),
39407
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "shrink-0 font-normal normal-case", children: group.views.length })
39620
+ /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "min-w-0 flex-1 truncate", children: view.name }),
39621
+ view.presentation?.locked === true ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Badge, { variant: "neutral", className: "shrink-0 px-1.5 py-0 text-[10px]", "data-view-locked": "", title: VIEW_LOCKED_REASON, children: "Locked" }) : null,
39622
+ view.personal ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Badge, { variant: "neutral", className: "shrink-0 px-1.5 py-0 text-[10px]", "data-view-personal": "", title: "Only you see this view", children: "Personal" }) : null,
39623
+ view.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Badge, { variant: "neutral", className: "shrink-0 px-1.5 py-0 text-[10px]", "data-view-default": "", children: "Default" }) : null
39408
39624
  ]
39409
39625
  }
39410
- ),
39411
- rights.admin ? /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(import_jsx_runtime131.Fragment, { children: [
39412
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("button", { type: "button", className: "shrink-0 normal-case hover:text-foreground", "data-view-section-rename": "", onClick: () => setRenamingSection({ from: group.name, draft: group.name }), children: "Rename" }),
39413
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("button", { type: "button", className: "shrink-0 normal-case hover:text-destructive", "data-view-section-delete": "", title: "The views stay; they leave the section", onClick: () => void renameSection(group.name, null), children: "Delete" })
39414
- ] }) : null
39415
- ] }) : null,
39416
- group.name !== null && shut.includes(group.name) && !group.views.some((v) => v.id === active) ? null : group.views.map((view) => /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
39417
- "button",
39418
- {
39419
- type: "button",
39420
- "aria-pressed": view.id === active,
39421
- className: (0, import_design_system112.cn)(
39422
- "flex min-h-8 w-full items-center gap-2 rounded-sm px-2 text-left text-xs text-popover-foreground hover:bg-accent hover:text-accent-foreground",
39423
- group.name !== null && "pl-4",
39424
- view.id === active && "font-medium"
39425
- ),
39426
- onClick: () => {
39427
- setActive(view.id);
39428
- onActiveView?.(view);
39429
- setOpen(false);
39430
- },
39431
- title: view.ruleId ? "Membership is this view's Rule" : "The whole table",
39432
- children: [
39433
- /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "min-w-0 flex-1 truncate", children: view.name }),
39434
- view.presentation?.locked === true ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Badge, { variant: "neutral", className: "shrink-0 px-1.5 py-0 text-[10px]", "data-view-locked": "", title: VIEW_LOCKED_REASON, children: "Locked" }) : null,
39435
- view.personal ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Badge, { variant: "neutral", className: "shrink-0 px-1.5 py-0 text-[10px]", "data-view-personal": "", title: "Only you see this view", children: "Personal" }) : null,
39436
- view.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)(import_design_system112.Badge, { variant: "neutral", className: "shrink-0 px-1.5 py-0 text-[10px]", "data-view-default": "", children: "Default" }) : null
39437
- ]
39438
- },
39439
- view.id
39440
- ))
39441
- ] }, group.name ?? "__loose")),
39626
+ ) }, view.id))
39627
+ ] })
39628
+ ] }, group.name ?? "__loose")) }),
39442
39629
  views.length === 0 && !rights.admin ? /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("span", { className: "px-2 py-1 text-xs text-muted-foreground", children: rights.why("structure") }) : null
39443
39630
  ] }),
39444
39631
  /* @__PURE__ */ (0, import_jsx_runtime131.jsx)("div", { className: "mt-1 border-t border-border pt-1", children: naming ? /* @__PURE__ */ (0, import_jsx_runtime131.jsxs)(
@@ -44719,9 +44906,9 @@ function SubscriptionsPanel({ tableId, activeRuleId, className }) {
44719
44906
  var import_clipboard10 = require("@ai-matrx/kit/clipboard");
44720
44907
  var import_design_system132 = require("@ai-matrx/design-system");
44721
44908
  var import_react266 = require("react");
44722
- var import_core22 = require("@dnd-kit/core");
44723
- var import_sortable = require("@dnd-kit/sortable");
44724
- var import_utilities = require("@dnd-kit/utilities");
44909
+ var import_core23 = require("@dnd-kit/core");
44910
+ var import_sortable2 = require("@dnd-kit/sortable");
44911
+ var import_utilities2 = require("@dnd-kit/utilities");
44725
44912
  var import_react267 = require("@ai-matrx/records/react");
44726
44913
  var import_records67 = require("@ai-matrx/records");
44727
44914
  var import_design_system133 = require("@ai-matrx/design-system");
@@ -46352,9 +46539,9 @@ function QuestionList({
46352
46539
  onQuestions,
46353
46540
  onQuestion
46354
46541
  }) {
46355
- const sensors = (0, import_core22.useSensors)(
46356
- (0, import_core22.useSensor)(import_core22.PointerSensor, { activationConstraint: { distance: 4 } }),
46357
- (0, import_core22.useSensor)(import_core22.KeyboardSensor, { coordinateGetter: import_sortable.sortableKeyboardCoordinates })
46542
+ const sensors = (0, import_core23.useSensors)(
46543
+ (0, import_core23.useSensor)(import_core23.PointerSensor, { activationConstraint: { distance: 4 } }),
46544
+ (0, import_core23.useSensor)(import_core23.KeyboardSensor, { coordinateGetter: import_sortable2.sortableKeyboardCoordinates })
46358
46545
  );
46359
46546
  const askable = askableFields([...fields]);
46360
46547
  const unasked = askable.filter((f) => !draft.questions.some((q) => q.field === f.key));
@@ -46367,7 +46554,7 @@ function QuestionList({
46367
46554
  const from = draft.questions.findIndex((q) => q.field === event.active.id);
46368
46555
  const to = event.over ? draft.questions.findIndex((q) => q.field === event.over.id) : -1;
46369
46556
  if (from < 0 || to < 0 || from === to) return;
46370
- onQuestions((0, import_sortable.arrayMove)(draft.questions, from, to));
46557
+ onQuestions((0, import_sortable2.arrayMove)(draft.questions, from, to));
46371
46558
  }
46372
46559
  const notAskable = whyNotAskable([...fields]);
46373
46560
  const leftUnasked = requiredLeftUnasked([...fields], draft.questions.map((q) => q.field));
@@ -46376,7 +46563,7 @@ function QuestionList({
46376
46563
  /* @__PURE__ */ (0, import_jsx_runtime151.jsx)("span", { className: "font-medium text-foreground", children: "Questions" }),
46377
46564
  /* @__PURE__ */ (0, import_jsx_runtime151.jsx)("span", { className: "tabular-nums", children: draft.questions.length })
46378
46565
  ] }),
46379
- /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(import_core22.DndContext, { sensors, collisionDetection: import_core22.closestCenter, onDragEnd: dragEnd, children: /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(import_sortable.SortableContext, { items: draft.questions.map((q) => q.field), strategy: import_sortable.verticalListSortingStrategy, children: draft.questions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(
46566
+ /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(import_core23.DndContext, { sensors, collisionDetection: import_core23.closestCenter, onDragEnd: dragEnd, children: /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(import_sortable2.SortableContext, { items: draft.questions.map((q) => q.field), strategy: import_sortable2.verticalListSortingStrategy, children: draft.questions.map((question, index) => /* @__PURE__ */ (0, import_jsx_runtime151.jsx)(
46380
46567
  QuestionRow,
46381
46568
  {
46382
46569
  index,
@@ -46429,14 +46616,14 @@ function QuestionRow({
46429
46616
  onChange,
46430
46617
  onRemove
46431
46618
  }) {
46432
- const sortable = (0, import_sortable.useSortable)({ id: question.field });
46619
+ const sortable = (0, import_sortable2.useSortable)({ id: question.field });
46433
46620
  const [open, setOpen] = (0, import_react266.useState)(true);
46434
46621
  const name = field2 ? fieldName(field2) : question.field;
46435
46622
  return /* @__PURE__ */ (0, import_jsx_runtime151.jsxs)(
46436
46623
  "div",
46437
46624
  {
46438
46625
  ref: sortable.setNodeRef,
46439
- style: { transform: import_utilities.CSS.Transform.toString(sortable.transform), transition: sortable.transition },
46626
+ style: { transform: import_utilities2.CSS.Transform.toString(sortable.transform), transition: sortable.transition },
46440
46627
  className: (0, import_design_system133.cn)("rounded border bg-background px-2 py-1.5", sortable.isDragging && "z-10 shadow-md"),
46441
46628
  "data-records-form-question-row": question.field,
46442
46629
  children: [
@@ -47372,9 +47559,9 @@ var import_react280 = require("@ai-matrx/records/react");
47372
47559
  var import_design_system140 = require("@ai-matrx/design-system");
47373
47560
 
47374
47561
  // src/DashboardGrid.tsx
47375
- var import_core23 = require("@dnd-kit/core");
47376
- var import_sortable2 = require("@dnd-kit/sortable");
47377
- var import_utilities2 = require("@dnd-kit/utilities");
47562
+ var import_core24 = require("@dnd-kit/core");
47563
+ var import_sortable3 = require("@dnd-kit/sortable");
47564
+ var import_utilities3 = require("@dnd-kit/utilities");
47378
47565
  var import_design_system138 = require("@ai-matrx/design-system");
47379
47566
 
47380
47567
  // src/dashboardLayout.ts
@@ -47428,7 +47615,7 @@ function withBlockIds(blocks) {
47428
47615
  // src/DashboardGrid.tsx
47429
47616
  var import_jsx_runtime156 = require("react/jsx-runtime");
47430
47617
  var dashboardCollision = (args) => {
47431
- const under = (0, import_core23.pointerWithin)(args);
47618
+ const under = (0, import_core24.pointerWithin)(args);
47432
47619
  if (under.length > 0) return under;
47433
47620
  const at = args.collisionRect;
47434
47621
  return args.droppableContainers.flatMap((container) => {
@@ -47438,9 +47625,9 @@ var dashboardCollision = (args) => {
47438
47625
  }).sort((a, b) => a.data.value - b.data.value);
47439
47626
  };
47440
47627
  function DashboardGrid({ items, arranging, onMove, onSpan }) {
47441
- const sensors = (0, import_core23.useSensors)(
47442
- (0, import_core23.useSensor)(import_core23.PointerSensor, { activationConstraint: { distance: 4 } }),
47443
- (0, import_core23.useSensor)(import_core23.KeyboardSensor, { coordinateGetter: import_sortable2.sortableKeyboardCoordinates })
47628
+ const sensors = (0, import_core24.useSensors)(
47629
+ (0, import_core24.useSensor)(import_core24.PointerSensor, { activationConstraint: { distance: 4 } }),
47630
+ (0, import_core24.useSensor)(import_core24.KeyboardSensor, { coordinateGetter: import_sortable3.sortableKeyboardCoordinates })
47444
47631
  );
47445
47632
  const ids = items.map((item) => item.id);
47446
47633
  function dragEnd(event) {
@@ -47450,7 +47637,7 @@ function DashboardGrid({ items, arranging, onMove, onSpan }) {
47450
47637
  }
47451
47638
  const grid = /* @__PURE__ */ (0, import_jsx_runtime156.jsx)("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-12", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(GridCell2, { item, index, arranging, onSpan }, item.id)) });
47452
47639
  if (!arranging) return grid;
47453
- return /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(import_core23.DndContext, { sensors, collisionDetection: dashboardCollision, onDragEnd: dragEnd, children: /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(import_sortable2.SortableContext, { items: ids, strategy: import_sortable2.rectSortingStrategy, children: grid }) });
47640
+ return /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(import_core24.DndContext, { sensors, collisionDetection: dashboardCollision, onDragEnd: dragEnd, children: /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(import_sortable3.SortableContext, { items: ids, strategy: import_sortable3.rectSortingStrategy, children: grid }) });
47454
47641
  }
47455
47642
  function GridCell2({
47456
47643
  item,
@@ -47458,8 +47645,8 @@ function GridCell2({
47458
47645
  arranging,
47459
47646
  onSpan
47460
47647
  }) {
47461
- const sortable = (0, import_sortable2.useSortable)({ id: item.id, disabled: !arranging });
47462
- const style = arranging ? { transform: import_utilities2.CSS.Transform.toString(sortable.transform), transition: sortable.transition } : void 0;
47648
+ const sortable = (0, import_sortable3.useSortable)({ id: item.id, disabled: !arranging });
47649
+ const style = arranging ? { transform: import_utilities3.CSS.Transform.toString(sortable.transform), transition: sortable.transition } : void 0;
47463
47650
  return /* @__PURE__ */ (0, import_jsx_runtime156.jsxs)(
47464
47651
  "div",
47465
47652
  {
@@ -49316,7 +49503,7 @@ function AgentAnswer({
49316
49503
  // src/PageScreen.tsx
49317
49504
  var import_react285 = require("react");
49318
49505
  var import_react286 = require("@ai-matrx/records/react");
49319
- var import_core24 = require("@ai-matrx/records/core");
49506
+ var import_core25 = require("@ai-matrx/records/core");
49320
49507
  var import_design_system143 = require("@ai-matrx/design-system");
49321
49508
  var import_forms4 = require("@ai-matrx/records/forms");
49322
49509
  var import_jsx_runtime161 = require("react/jsx-runtime");
@@ -49733,7 +49920,7 @@ function ListBlockView({
49733
49920
  ...sort.length > 0 ? { sort } : {}
49734
49921
  });
49735
49922
  const reload = page.reload;
49736
- (0, import_react285.useEffect)(() => (0, import_core24.onRecordChanged)(() => reload()), [reload]);
49923
+ (0, import_react285.useEffect)(() => (0, import_core25.onRecordChanged)(() => reload()), [reload]);
49737
49924
  const rows = nobodyIsMe ? [] : page.data?.rows ?? [];
49738
49925
  const columns = block.columns && block.columns.length > 0 ? block.columns.map((k) => all.find((f) => f.key === k)).filter((f) => !!f) : [...all].sort((a, b) => (a.sort ?? 100) - (b.sort ?? 100)).slice(0, DEFAULT_COLUMNS);
49739
49926
  const firstId = rows[0]?.id ?? null;
@@ -51362,9 +51549,9 @@ function CalendarSubscribeDialog({
51362
51549
 
51363
51550
  // src/viewShare.ts
51364
51551
  var import_clipboard15 = require("@ai-matrx/kit/clipboard");
51365
- var import_core25 = require("@ai-matrx/print/core");
51552
+ var import_core26 = require("@ai-matrx/print/core");
51366
51553
  var import_markdown = require("@ai-matrx/print/markdown");
51367
- var import_core26 = require("@ai-matrx/records/core");
51554
+ var import_core27 = require("@ai-matrx/records/core");
51368
51555
  var NO_VIEW_REASON = "No saved view yet";
51369
51556
  function viewLink(tableId, viewId, origin) {
51370
51557
  return `${tableLink(tableId, origin)}?view=${encodeURIComponent(viewId)}`;
@@ -51400,7 +51587,7 @@ async function downloadViewCsv(args) {
51400
51587
  const columns = viewColumns(fields, view.presentation);
51401
51588
  const rows = await rowsForFile({ client, host, fields: columns, records: read.rows, labels });
51402
51589
  const name = fileNameOf(args.tableName) || "records";
51403
- download(`${name}.csv`, "text/csv;charset=utf-8", (0, import_core26.exportCsv)(columns, rows));
51590
+ download(`${name}.csv`, "text/csv;charset=utf-8", (0, import_core27.exportCsv)(columns, rows));
51404
51591
  host.notify?.success(read.cut ? cutWords(read.rows.length) : "CSV downloaded");
51405
51592
  }
51406
51593
  function downloadMarkdownAction(args) {
@@ -51429,7 +51616,7 @@ async function readViewMarkdown(args) {
51429
51616
  if ("error" in read) return null;
51430
51617
  const columns = viewColumns(fields, view.presentation);
51431
51618
  const rows = await rowsForFile({ client, host, fields: columns, records: read.rows, labels });
51432
- return { markdown: (0, import_core26.exportMarkdown)(columns, rows), cut: read.cut, count: read.rows.length };
51619
+ return { markdown: (0, import_core27.exportMarkdown)(columns, rows), cut: read.cut, count: read.rows.length };
51433
51620
  }
51434
51621
  async function downloadViewMarkdown(args) {
51435
51622
  const table = await readViewMarkdown(args);
@@ -51487,7 +51674,7 @@ async function runTablePageAction(kind, args) {
51487
51674
  }
51488
51675
  const page = (0, import_markdown.renderMarkdownDocument)(markdown, { title, withPrintActions: kind === "html-preview" });
51489
51676
  if (kind === "html-preview") {
51490
- (0, import_core25.openPrintWindow)(page, title);
51677
+ (0, import_core26.openPrintWindow)(page, title);
51491
51678
  if (note) args.host.notify?.success(note);
51492
51679
  } else if (kind === "copy-html-page") {
51493
51680
  if (await (0, import_clipboard15.copyText)(page)) args.host.notify?.success(note ?? "HTML page copied");