@ai-matrx/records-ui 0.95.3 → 0.95.10
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 +127 -0
- package/dist/index.cjs +7265 -6066
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +149 -26
- package/dist/index.d.ts +149 -26
- package/dist/index.js +6894 -5685
- package/dist/index.js.map +1 -1
- package/dist/object-actions.cjs +17 -12
- package/dist/object-actions.cjs.map +1 -1
- package/dist/object-actions.d.cts +1 -1
- package/dist/object-actions.d.ts +1 -1
- package/dist/object-actions.js +19 -12
- package/dist/object-actions.js.map +1 -1
- package/dist/{objectActions-DozKWxks.d.cts → objectActions-CUR8KdPr.d.cts} +11 -2
- package/dist/{objectActions-DozKWxks.d.ts → objectActions-CUR8KdPr.d.ts} +11 -2
- package/dist/pickers.cjs +98 -34
- package/dist/pickers.cjs.map +1 -1
- package/dist/pickers.d.cts +4 -0
- package/dist/pickers.d.ts +4 -0
- package/dist/pickers.js +98 -34
- package/dist/pickers.js.map +1 -1
- package/package.json +3 -3
package/dist/pickers.cjs
CHANGED
|
@@ -46,6 +46,40 @@ var import_react30 = require("react");
|
|
|
46
46
|
var import_react31 = require("@ai-matrx/records/react");
|
|
47
47
|
var import_design_system16 = require("@ai-matrx/design-system");
|
|
48
48
|
|
|
49
|
+
// src/askOnce.ts
|
|
50
|
+
var asked = /* @__PURE__ */ new WeakMap();
|
|
51
|
+
function askOnce(client, key, ask, freshMs) {
|
|
52
|
+
let held = asked.get(client);
|
|
53
|
+
if (!held) {
|
|
54
|
+
held = /* @__PURE__ */ new Map();
|
|
55
|
+
asked.set(client, held);
|
|
56
|
+
}
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
const kept = held.get(key);
|
|
59
|
+
if (kept && now - kept.at <= freshMs) return kept.answer;
|
|
60
|
+
const answer = ask().then(
|
|
61
|
+
(result) => {
|
|
62
|
+
if (!result.ok) held.delete(key);
|
|
63
|
+
return result;
|
|
64
|
+
},
|
|
65
|
+
(thrown) => {
|
|
66
|
+
held.delete(key);
|
|
67
|
+
throw thrown;
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
held.set(key, { at: now, answer });
|
|
71
|
+
return answer;
|
|
72
|
+
}
|
|
73
|
+
function forgetAsked(client, prefix) {
|
|
74
|
+
const held = asked.get(client);
|
|
75
|
+
if (!held) return;
|
|
76
|
+
for (const key of [...held.keys()]) if (key.startsWith(prefix)) held.delete(key);
|
|
77
|
+
}
|
|
78
|
+
var FIELD_OPTIONS_FRESH_MS = 2e3;
|
|
79
|
+
function fieldOptionsOnce(client, fieldId) {
|
|
80
|
+
return askOnce(client, `field_options:${fieldId}`, () => client.fieldOptions({ field_id: fieldId }), FIELD_OPTIONS_FRESH_MS);
|
|
81
|
+
}
|
|
82
|
+
|
|
49
83
|
// src/editors.tsx
|
|
50
84
|
var import_react24 = require("react");
|
|
51
85
|
var import_records10 = require("@ai-matrx/records");
|
|
@@ -717,7 +751,12 @@ var REMEDY = {
|
|
|
717
751
|
unreachable: "Nothing was changed. Check your connection and open this again.",
|
|
718
752
|
needs_approval: "Nothing was changed yet. The people who can approve it have been asked.",
|
|
719
753
|
stale_read: "Open this again in a moment and it will be up to date.",
|
|
720
|
-
|
|
754
|
+
// 🚨 ONE REMEDY THAT IS TRUE OF EVERY DOOR (lane CHAIR-STORE-PERF, 2026-10-03). The store cancels the
|
|
755
|
+
// WHOLE statement at its clock, so a timed-out door wrote nothing — a create, a column add and a page
|
|
756
|
+
// read alike. "Try a smaller page" was written for the page read and was printed to a person adding
|
|
757
|
+
// one row to a three-row table (clone walk, 2026-10-03; the clock was a lock another lane's
|
|
758
|
+
// rehearsal held, not the row). A door whose page can shrink says so in its own hint, which wins here.
|
|
759
|
+
timed_out: "Nothing was changed. Try again in a moment.",
|
|
721
760
|
internal: "Nothing you did caused this. Try again, and tell us if it keeps happening."
|
|
722
761
|
};
|
|
723
762
|
var ENGINEER_TEXT = [
|
|
@@ -961,7 +1000,7 @@ var import_jsx_runtime4 = (
|
|
|
961
1000
|
require("react/jsx-runtime")
|
|
962
1001
|
);
|
|
963
1002
|
var NO_STORE_ON_THIS_SCREEN_REASON = "This question points at a record in somebody's own data, and a page answered without an account is never allowed to search that. Leave it blank \u2014 whoever receives your answer will fill it in.";
|
|
964
|
-
function RelationPicker({ field, value, onChange, disabled, id, className, allowCreate = true }) {
|
|
1003
|
+
function RelationPicker({ field, value, onChange, disabled, id, className, allowCreate = true, onPicked }) {
|
|
965
1004
|
const client = (0, import_react4.useOptionalRecordsClient)();
|
|
966
1005
|
const [rows, setRows] = (0, import_react3.useState)(null);
|
|
967
1006
|
const [words, setWords] = (0, import_react3.useState)({});
|
|
@@ -1049,8 +1088,10 @@ function RelationPicker({ field, value, onChange, disabled, id, className, allow
|
|
|
1049
1088
|
const full = field.multi && field.relation_max !== null && picked.length >= field.relation_max;
|
|
1050
1089
|
const toggle = (recordId) => {
|
|
1051
1090
|
if (!field.multi) {
|
|
1052
|
-
|
|
1091
|
+
const choosing = picked[0] !== recordId;
|
|
1092
|
+
onChange(choosing ? recordId : null);
|
|
1053
1093
|
setOpen(false);
|
|
1094
|
+
if (choosing && onPicked) setTimeout(onPicked, 0);
|
|
1054
1095
|
return;
|
|
1055
1096
|
}
|
|
1056
1097
|
const next = new Set(picked);
|
|
@@ -1326,31 +1367,31 @@ var FILES = /* @__PURE__ */ new WeakMap();
|
|
|
1326
1367
|
function signatureFilesOf(client, recordId) {
|
|
1327
1368
|
let held = SOURCES.get(client);
|
|
1328
1369
|
if (!held) SOURCES.set(client, held = /* @__PURE__ */ new Map());
|
|
1329
|
-
let
|
|
1330
|
-
if (!
|
|
1331
|
-
|
|
1370
|
+
let asked3 = held.get(recordId);
|
|
1371
|
+
if (!asked3) {
|
|
1372
|
+
asked3 = client.recordValuesVersioned({ record_id: recordId }).then((answered) => {
|
|
1332
1373
|
if (!answered.ok) return {};
|
|
1333
1374
|
return Object.fromEntries(answered.data.map((v) => [v.field_key, signatureFileOf(v.source)]));
|
|
1334
1375
|
});
|
|
1335
|
-
held.set(recordId,
|
|
1376
|
+
held.set(recordId, asked3);
|
|
1336
1377
|
}
|
|
1337
|
-
return
|
|
1378
|
+
return asked3;
|
|
1338
1379
|
}
|
|
1339
1380
|
function drawingOf(client, fileId) {
|
|
1340
1381
|
let held = FILES.get(client);
|
|
1341
1382
|
if (!held) FILES.set(client, held = /* @__PURE__ */ new Map());
|
|
1342
|
-
let
|
|
1343
|
-
if (!
|
|
1344
|
-
|
|
1383
|
+
let asked3 = held.get(fileId);
|
|
1384
|
+
if (!asked3) {
|
|
1385
|
+
asked3 = client.recordRead({ record_id: fileId }).then((answered) => {
|
|
1345
1386
|
if (!answered.ok) return { src: null, hostFileId: null };
|
|
1346
1387
|
const doc = answered.data.document ?? {};
|
|
1347
1388
|
const content = drawnSignatureOf(doc["content"]);
|
|
1348
1389
|
const hostFileId = typeof doc["file_id"] === "string" && doc["file_id"] !== "" ? doc["file_id"] : null;
|
|
1349
1390
|
return { src: content, hostFileId };
|
|
1350
1391
|
});
|
|
1351
|
-
held.set(fileId,
|
|
1392
|
+
held.set(fileId, asked3);
|
|
1352
1393
|
}
|
|
1353
|
-
return
|
|
1394
|
+
return asked3;
|
|
1354
1395
|
}
|
|
1355
1396
|
function DrawnImage({ src, inCell }) {
|
|
1356
1397
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
@@ -1597,7 +1638,7 @@ function RecordLabelProvider({ children }) {
|
|
|
1597
1638
|
const [archivedRefs, setArchivedRefs] = (0, import_react9.useState)({});
|
|
1598
1639
|
const [settled, setSettled] = (0, import_react9.useState)({});
|
|
1599
1640
|
const [waitingLines, setWaitingLines] = (0, import_react9.useState)({});
|
|
1600
|
-
const
|
|
1641
|
+
const asked3 = (0, import_react9.useRef)(/* @__PURE__ */ new Set());
|
|
1601
1642
|
const chased = (0, import_react9.useRef)(/* @__PURE__ */ new Set());
|
|
1602
1643
|
const timers = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
1603
1644
|
const startWaitClock = (0, import_react9.useCallback)((field, target) => {
|
|
@@ -1635,12 +1676,12 @@ function RecordLabelProvider({ children }) {
|
|
|
1635
1676
|
const want = (0, import_react9.useCallback)(
|
|
1636
1677
|
(field) => {
|
|
1637
1678
|
if (!pointsAtRecords(field)) return;
|
|
1638
|
-
if (
|
|
1639
|
-
|
|
1679
|
+
if (asked3.current.has(field.id)) return;
|
|
1680
|
+
asked3.current.add(field.id);
|
|
1640
1681
|
startWaitClock(field, null);
|
|
1641
1682
|
void (async () => {
|
|
1642
1683
|
if (field.type === "list") {
|
|
1643
|
-
const result = await client
|
|
1684
|
+
const result = await fieldOptionsOnce(client, field.id);
|
|
1644
1685
|
if (result.ok) {
|
|
1645
1686
|
setNames((current) => {
|
|
1646
1687
|
const next = { ...current };
|
|
@@ -1724,7 +1765,7 @@ function RecordLabelProvider({ children }) {
|
|
|
1724
1765
|
const once = choiceKeyName(field.id, id);
|
|
1725
1766
|
if (settled[field.id] && !rereadFor.current.has(once)) {
|
|
1726
1767
|
rereadFor.current.add(once);
|
|
1727
|
-
|
|
1768
|
+
asked3.current.delete(field.id);
|
|
1728
1769
|
want(field);
|
|
1729
1770
|
}
|
|
1730
1771
|
return null;
|
|
@@ -2954,15 +2995,15 @@ function TypedDateHelper({ kind, text, onText, label }) {
|
|
|
2954
2995
|
// src/choiceNudge.ts
|
|
2955
2996
|
var import_react22 = require("react");
|
|
2956
2997
|
var import_react23 = require("@ai-matrx/records/react");
|
|
2957
|
-
var
|
|
2998
|
+
var asked2 = /* @__PURE__ */ new WeakMap();
|
|
2958
2999
|
function choiceNudgeOf(client) {
|
|
2959
|
-
let answer =
|
|
3000
|
+
let answer = asked2.get(client);
|
|
2960
3001
|
if (!answer) {
|
|
2961
3002
|
answer = Promise.resolve().then(() => client.choiceNudge()).then(
|
|
2962
3003
|
(result) => result.ok ? result.data : "ask",
|
|
2963
3004
|
() => "ask"
|
|
2964
3005
|
);
|
|
2965
|
-
|
|
3006
|
+
asked2.set(client, answer);
|
|
2966
3007
|
}
|
|
2967
3008
|
return answer;
|
|
2968
3009
|
}
|
|
@@ -3110,7 +3151,7 @@ function TypedTextControl({ field, value, onChange, disabled, id, onCommit, onCa
|
|
|
3110
3151
|
(0, import_react24.useEffect)(() => {
|
|
3111
3152
|
if (!needsChoices || !client) return;
|
|
3112
3153
|
let cancelled = false;
|
|
3113
|
-
void client
|
|
3154
|
+
void fieldOptionsOnce(client, field.id).then((result) => {
|
|
3114
3155
|
if (!cancelled) setChoices(result.ok ? inTheStoresOrder(result.data ?? []) : []);
|
|
3115
3156
|
});
|
|
3116
3157
|
return () => {
|
|
@@ -3274,7 +3315,7 @@ function FieldControl({ field, value, onChange, disabled, id, autoOpen, onClose,
|
|
|
3274
3315
|
}
|
|
3275
3316
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RelationPicker, { field, value, onChange, disabled, id: inputId });
|
|
3276
3317
|
case "relation":
|
|
3277
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RelationPicker, { field, value, onChange, disabled, id: inputId });
|
|
3318
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RelationPicker, { field, value, onChange, disabled, id: inputId, onPicked: onCommit });
|
|
3278
3319
|
default:
|
|
3279
3320
|
if (typeof value === "boolean" || field.config?.["kind"] === "boolean") {
|
|
3280
3321
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
@@ -3444,7 +3485,7 @@ function OptionControl({ field, value, onChange, disabled, id, autoOpen, onClose
|
|
|
3444
3485
|
(0, import_react24.useEffect)(() => {
|
|
3445
3486
|
if (!client) return;
|
|
3446
3487
|
let cancelled = false;
|
|
3447
|
-
void client
|
|
3488
|
+
void fieldOptionsOnce(client, field.id).then((result) => {
|
|
3448
3489
|
if (cancelled) return;
|
|
3449
3490
|
if (result.ok) setOptions(inTheStoresOrder(result.data ?? []));
|
|
3450
3491
|
else setRefusal(result.error);
|
|
@@ -3507,7 +3548,10 @@ function OptionControl({ field, value, onChange, disabled, id, autoOpen, onClose
|
|
|
3507
3548
|
initialSearch,
|
|
3508
3549
|
addsChoices,
|
|
3509
3550
|
allowOther: (0, import_records10.allowsOtherValues)(field),
|
|
3510
|
-
onChoicesChanged: () =>
|
|
3551
|
+
onChoicesChanged: () => {
|
|
3552
|
+
if (client) forgetAsked(client, `field_options:${field.id}`);
|
|
3553
|
+
setReread((n) => n + 1);
|
|
3554
|
+
}
|
|
3511
3555
|
}
|
|
3512
3556
|
);
|
|
3513
3557
|
}
|
|
@@ -3933,20 +3977,40 @@ function TablePicker({ dataSource, value, onChange, disabled, tables }) {
|
|
|
3933
3977
|
const options = tablePickerEntries(
|
|
3934
3978
|
list.rows.map((t) => ({ ...t, id: t.table_id, name: t.table_name })),
|
|
3935
3979
|
{ keep: value }
|
|
3936
|
-
).entries.map(({ table: t }) =>
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3980
|
+
).entries.map(({ table: t }) => t);
|
|
3981
|
+
const sameName = /* @__PURE__ */ new Map();
|
|
3982
|
+
for (const t of options) {
|
|
3983
|
+
const key = `${t.organization_id}|${t.table_name.trim().toLowerCase()}`;
|
|
3984
|
+
sameName.set(key, (sameName.get(key) ?? 0) + 1);
|
|
3985
|
+
}
|
|
3986
|
+
const pickerOptions = options.map((t) => {
|
|
3987
|
+
const twin = (sameName.get(`${t.organization_id}|${t.table_name.trim().toLowerCase()}`) ?? 0) > 1;
|
|
3988
|
+
const row = t;
|
|
3989
|
+
const second = [
|
|
3990
|
+
row.created_by_name ? `by ${row.created_by_name}` : null,
|
|
3991
|
+
row.updated_at ? `changed ${new Date(row.updated_at).toLocaleDateString()}` : null
|
|
3992
|
+
].filter(Boolean).join(" \xB7 ");
|
|
3993
|
+
return {
|
|
3994
|
+
value: t.table_id,
|
|
3995
|
+
// The organization hint already tells two same-named tables apart across organizations.
|
|
3996
|
+
label: t.table_name,
|
|
3997
|
+
hint: t.organization_name,
|
|
3998
|
+
keywords: t.organization_name,
|
|
3999
|
+
...twin && second ? {
|
|
4000
|
+
render: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex min-w-0 flex-col", children: [
|
|
4001
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate", children: t.table_name }),
|
|
4002
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: second })
|
|
4003
|
+
] })
|
|
4004
|
+
} : {}
|
|
4005
|
+
};
|
|
4006
|
+
});
|
|
3943
4007
|
const missing = Boolean(value) && !list.loading && !list.error && !list.rows.some((t) => t.table_id === value);
|
|
3944
4008
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
3945
4009
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3946
4010
|
import_design_system16.CreatablePicker,
|
|
3947
4011
|
{
|
|
3948
4012
|
value: value || null,
|
|
3949
|
-
options,
|
|
4013
|
+
options: pickerOptions,
|
|
3950
4014
|
onSelect: onChange,
|
|
3951
4015
|
placeholder: missing ? "Table not available" : "Choose a table",
|
|
3952
4016
|
searchPlaceholder: "Search tables",
|
|
@@ -4468,7 +4532,7 @@ function referencesOf(field, value, kind, labels) {
|
|
|
4468
4532
|
}));
|
|
4469
4533
|
}
|
|
4470
4534
|
var ARCHIVED_REFERENCE_WORD = "Archived";
|
|
4471
|
-
var ARCHIVED_REFERENCE_TIP = "In
|
|
4535
|
+
var ARCHIVED_REFERENCE_TIP = "In the Archived view; restore it to use it again";
|
|
4472
4536
|
function ReferenceChip({ reference, waiting }) {
|
|
4473
4537
|
const host = useRecordsUi();
|
|
4474
4538
|
const words = reference.label ?? (reference.token === "record" ? waiting ?? "Loading\u2026" : WITHHELD_ENTITY_LABEL);
|