@ai-matrx/records-ui 0.93.33 → 0.93.37
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/CHANGELOG.md +24 -0
- package/dist/index.cjs +55 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +55 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5458,16 +5458,26 @@ import { tableShapeChanged, useRecordsClient as useRecordsClient6 } from "@ai-ma
|
|
|
5458
5458
|
import { Button as Button12, Select as Select3, SelectContent as SelectContent3, SelectItem as SelectItem3, SelectTrigger as SelectTrigger3, SelectValue as SelectValue3 } from "@ai-matrx/design-system";
|
|
5459
5459
|
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
5460
5460
|
var RETYPE_TARGETS = [
|
|
5461
|
-
{ behaviour: "text", label: "Text", holds: "words" },
|
|
5462
|
-
{ behaviour: "range", label: "Number", holds: "a number" },
|
|
5463
|
-
|
|
5461
|
+
{ id: "text", behaviour: "text", kind: null, label: "Text", holds: "words" },
|
|
5462
|
+
{ id: "number", behaviour: "range", kind: "number", label: "Number", holds: "a number" },
|
|
5463
|
+
// A DATE is a `range` of kind date: `migrate_retype` alone cannot say "date" (it keeps the old
|
|
5464
|
+
// kind, so every date would be kept aside), so this one goes through `custom.field_update`'s own
|
|
5465
|
+
// retype arm (`parity_type: datetime`), which converts on the SAME trigger and keeps what does not
|
|
5466
|
+
// fit in `_retired` with the reason — measured on the live store 2026-09-28.
|
|
5467
|
+
{ id: "date", behaviour: "range", kind: "date", label: "Date", holds: "a date" },
|
|
5468
|
+
{ id: "checkbox", behaviour: "boolean", kind: null, label: "Yes / no", holds: "a yes or a no" }
|
|
5464
5469
|
];
|
|
5465
5470
|
var PREVIEW_GROUPS = 1e3;
|
|
5466
5471
|
function retypeableFrom(field2) {
|
|
5467
5472
|
const behaviour = String(field2.type);
|
|
5468
|
-
|
|
5473
|
+
return behaviour === "text" || behaviour === "range" || behaviour === "boolean";
|
|
5474
|
+
}
|
|
5475
|
+
function currentTarget(field2) {
|
|
5469
5476
|
const kind = String(editorKindFor(field2));
|
|
5470
|
-
|
|
5477
|
+
if (String(field2.type) === "boolean") return "checkbox";
|
|
5478
|
+
if (kind === "datetime" || kind === "date") return "date";
|
|
5479
|
+
if (String(field2.type) === "range") return "number";
|
|
5480
|
+
return "text";
|
|
5471
5481
|
}
|
|
5472
5482
|
function FieldRetype({ field: field2, tableId, onRetyped }) {
|
|
5473
5483
|
const client = useRecordsClient6();
|
|
@@ -5478,7 +5488,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
|
|
|
5478
5488
|
const [busy, setBusy] = useState17(false);
|
|
5479
5489
|
const [said, setSaid] = useState17(null);
|
|
5480
5490
|
const name = fieldName(field2);
|
|
5481
|
-
const targets = RETYPE_TARGETS.filter((t) => t.
|
|
5491
|
+
const targets = RETYPE_TARGETS.filter((t) => t.id !== currentTarget(field2));
|
|
5482
5492
|
useEffect14(() => {
|
|
5483
5493
|
if (!to) return;
|
|
5484
5494
|
let cancelled = false;
|
|
@@ -5493,7 +5503,7 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
|
|
|
5493
5503
|
return;
|
|
5494
5504
|
}
|
|
5495
5505
|
const groups = answer.data.map((row) => ({ value: row.groups[field2.key] ?? null, count: row.row_count }));
|
|
5496
|
-
setPreview(previewRetype({ type: to.behaviour }, groups, answer.data.length >= PREVIEW_GROUPS));
|
|
5506
|
+
setPreview(previewRetype({ type: to.behaviour, kind: to.kind }, groups, answer.data.length >= PREVIEW_GROUPS));
|
|
5497
5507
|
});
|
|
5498
5508
|
return () => {
|
|
5499
5509
|
cancelled = true;
|
|
@@ -5503,22 +5513,35 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
|
|
|
5503
5513
|
return /* @__PURE__ */ jsxs18("p", { className: "text-[11px] text-muted-foreground", "data-records-retype": "not-here", children: [
|
|
5504
5514
|
name,
|
|
5505
5515
|
" holds ",
|
|
5506
|
-
String(
|
|
5507
|
-
",
|
|
5516
|
+
String(field2.type) === "formula" ? "a value the table works out" : "records picked from a list or another table",
|
|
5517
|
+
", and the store keeps those as record ids \u2014 turned into words or numbers they would read as ids, so it is not changed here."
|
|
5508
5518
|
] });
|
|
5509
5519
|
}
|
|
5510
5520
|
const change = async () => {
|
|
5511
5521
|
if (!to) return;
|
|
5512
5522
|
setBusy(true);
|
|
5513
5523
|
setRefusal(null);
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
if (
|
|
5517
|
-
|
|
5518
|
-
|
|
5524
|
+
let holding;
|
|
5525
|
+
let aside;
|
|
5526
|
+
if (to.id === "date") {
|
|
5527
|
+
const done = await client.fieldUpdate({ field_id: field2.id, patch: { parity_type: "datetime" } });
|
|
5528
|
+
setBusy(false);
|
|
5529
|
+
if (!done.ok) {
|
|
5530
|
+
setRefusal(done.error);
|
|
5531
|
+
return;
|
|
5532
|
+
}
|
|
5533
|
+
holding = preview?.converts ?? 0;
|
|
5534
|
+
aside = preview?.keptAside ?? 0;
|
|
5535
|
+
} else {
|
|
5536
|
+
const done = await client.migrateRetype({ field_id: field2.id, to: to.behaviour });
|
|
5537
|
+
setBusy(false);
|
|
5538
|
+
if (!done.ok) {
|
|
5539
|
+
setRefusal(done.error);
|
|
5540
|
+
return;
|
|
5541
|
+
}
|
|
5542
|
+
holding = done.data.records_still_holding_a_value ?? 0;
|
|
5543
|
+
aside = done.data.values_in_retired_for_this_field ?? 0;
|
|
5519
5544
|
}
|
|
5520
|
-
const holding = done.data.records_still_holding_a_value ?? 0;
|
|
5521
|
-
const aside = done.data.values_in_retired_for_this_field ?? 0;
|
|
5522
5545
|
setSaid(
|
|
5523
5546
|
`${name} now holds ${to.holds}. ${holding} ${holding === 1 ? "record holds" : "records hold"} a value` + (aside > 0 ? `; ${aside} ${aside === 1 ? "value that did not fit was" : "values that did not fit were"} kept with ${aside === 1 ? "its record" : "their records"}, with the reason.` : ".")
|
|
5524
5547
|
);
|
|
@@ -5529,9 +5552,9 @@ function FieldRetype({ field: field2, tableId, onRetyped }) {
|
|
|
5529
5552
|
};
|
|
5530
5553
|
return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-1.5", "data-records-retype": "", children: [
|
|
5531
5554
|
/* @__PURE__ */ jsxs18("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
5532
|
-
/* @__PURE__ */ jsxs18(Select3, { value: to?.
|
|
5555
|
+
/* @__PURE__ */ jsxs18(Select3, { value: to?.id ?? "", onValueChange: (next) => setTo(targets.find((t) => t.id === next) ?? null), children: [
|
|
5533
5556
|
/* @__PURE__ */ jsx22(SelectTrigger3, { size: "sm", "aria-label": "Change what this column holds", className: "w-auto min-w-[12rem]", children: /* @__PURE__ */ jsx22(SelectValue3, { placeholder: "Change what this column holds" }) }),
|
|
5534
|
-
/* @__PURE__ */ jsx22(SelectContent3, { children: targets.map((t) => /* @__PURE__ */ jsx22(SelectItem3, { value: t.
|
|
5557
|
+
/* @__PURE__ */ jsx22(SelectContent3, { children: targets.map((t) => /* @__PURE__ */ jsx22(SelectItem3, { value: t.id, children: t.label }, t.id)) })
|
|
5535
5558
|
] }),
|
|
5536
5559
|
to ? /* @__PURE__ */ jsx22(Button12, { size: "sm", disabled: busy || asking || preview === null, onClick: () => void change(), "data-records-retype-go": "", children: busy ? "Changing\u2026" : `Change to ${to.label}` }) : null,
|
|
5537
5560
|
to ? /* @__PURE__ */ jsx22(Button12, { size: "sm", variant: "ghost", onClick: () => setTo(null), disabled: busy, children: "Cancel" }) : null
|
|
@@ -9525,7 +9548,10 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
|
|
|
9525
9548
|
// The type is in the header's tooltip rather than a second header row: one
|
|
9526
9549
|
// row of headers, always — and it is the parity type's own WORD, not a
|
|
9527
9550
|
// token (`Long text`, never `long_text`).
|
|
9528
|
-
|
|
9551
|
+
// Top-aligned where a value may wrap to several lines; on a phone a cell never wraps (one line,
|
|
9552
|
+
// scrolled sideways) and the row is as tall as its 44 px tick box, so the value sits in the
|
|
9553
|
+
// middle beside the box — top-aligned it sat ~10 px above it (merged-grid review 2, 390 px).
|
|
9554
|
+
className: "sm:align-top max-sm:align-middle",
|
|
9529
9555
|
...{ title: fieldTypeLabel(field2) }
|
|
9530
9556
|
};
|
|
9531
9557
|
}
|
|
@@ -9555,6 +9581,12 @@ function PastePreview({
|
|
|
9555
9581
|
"aria-label": "What this paste will write",
|
|
9556
9582
|
"data-matrx-paste-preview": true,
|
|
9557
9583
|
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
|
|
9584
|
+
onKeyDown: (event) => {
|
|
9585
|
+
if (event.key !== "Escape") return;
|
|
9586
|
+
event.preventDefault();
|
|
9587
|
+
event.stopPropagation();
|
|
9588
|
+
if (!busy) onCancel();
|
|
9589
|
+
},
|
|
9558
9590
|
children: /* @__PURE__ */ jsxs30("div", { className: "flex max-h-[80vh] w-full max-w-2xl flex-col gap-3 overflow-auto rounded-lg border bg-background p-4 shadow-lg", children: [
|
|
9559
9591
|
/* @__PURE__ */ jsxs30("div", { className: "flex items-baseline justify-between gap-3", children: [
|
|
9560
9592
|
/* @__PURE__ */ jsx34("h2", { className: "text-sm font-medium", children: outcome ? "What was written" : "Before this is written" }),
|
|
@@ -9630,11 +9662,13 @@ function PastePreview({
|
|
|
9630
9662
|
". Add the columns first and paste again."
|
|
9631
9663
|
] }) : null,
|
|
9632
9664
|
/* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-end gap-2 pt-1", children: [
|
|
9633
|
-
/* @__PURE__ */ jsx34(Button22, { size: "sm", variant: "ghost", onClick: onCancel, disabled: busy, children: "Cancel" }),
|
|
9665
|
+
/* @__PURE__ */ jsx34(Button22, { size: "sm", variant: "ghost", onClick: onCancel, disabled: busy, autoFocus: nothingToDo, children: "Cancel" }),
|
|
9634
9666
|
/* @__PURE__ */ jsx34(
|
|
9635
9667
|
Button22,
|
|
9636
9668
|
{
|
|
9637
9669
|
size: "sm",
|
|
9670
|
+
autoFocus: !nothingToDo,
|
|
9671
|
+
"data-matrx-paste-confirm": "",
|
|
9638
9672
|
disabled: busy || nothingToDo,
|
|
9639
9673
|
onClick: () => {
|
|
9640
9674
|
setBusy(true);
|
|
@@ -9654,7 +9688,7 @@ function Outcome({ outcome, onClose }) {
|
|
|
9654
9688
|
return /* @__PURE__ */ jsxs30(Fragment11, { children: [
|
|
9655
9689
|
/* @__PURE__ */ jsx34("p", { className: "text-sm", "data-matrx-paste-outcome": whole ? "whole" : "partial", children: whole ? `All ${outcome.readBack} ${outcome.readBack === 1 ? "value is" : "values are"} in the table \u2014 read back out of it, not just accepted.` : `${outcome.readBack} of ${outcome.readBack + outcome.missing} values are in the table. The rest are not, and nothing was lost from what you copied \u2014 it is still on your clipboard.` }),
|
|
9656
9690
|
outcome.refusals.length > 0 ? /* @__PURE__ */ jsx34("ul", { className: "flex flex-col gap-1", children: outcome.refusals.slice(0, 8).map((why, index) => /* @__PURE__ */ jsx34("li", { className: "text-xs text-muted-foreground", children: why }, index)) }) : null,
|
|
9657
|
-
/* @__PURE__ */ jsx34("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsx34(Button22, { size: "sm", onClick: onClose, children: "Close" }) })
|
|
9691
|
+
/* @__PURE__ */ jsx34("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsx34(Button22, { size: "sm", onClick: onClose, autoFocus: true, children: "Close" }) })
|
|
9658
9692
|
] });
|
|
9659
9693
|
}
|
|
9660
9694
|
function PlanTable({ plan }) {
|