@ai-matrx/records-ui 0.115.37 → 0.115.39
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 +6 -0
- package/dist/index.cjs +103 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +103 -32
- package/dist/index.js.map +1 -1
- package/dist/pickers.cjs.map +1 -1
- package/dist/pickers.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.115.39
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/records-ui/v0.115.38..npm/records-ui/v0.115.39 -- apps/shared/records-ui`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
3
9
|
## 0.115.37
|
|
4
10
|
|
|
5
11
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/index.cjs
CHANGED
|
@@ -11978,6 +11978,9 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
|
|
|
11978
11978
|
const startedFrom = (0, import_react66.useRef)(null);
|
|
11979
11979
|
const startedStored = (0, import_react66.useRef)(null);
|
|
11980
11980
|
const host = useRecordsUi();
|
|
11981
|
+
const fieldsRef = (0, import_react66.useRef)(fields);
|
|
11982
|
+
fieldsRef.current = fields;
|
|
11983
|
+
const forceNext = (0, import_react66.useRef)(/* @__PURE__ */ new Set());
|
|
11981
11984
|
const type = (0, import_react66.useCallback)((value) => {
|
|
11982
11985
|
typed2.current = value;
|
|
11983
11986
|
setDraft(value);
|
|
@@ -12134,6 +12137,47 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
|
|
|
12134
12137
|
delete next[id];
|
|
12135
12138
|
return next;
|
|
12136
12139
|
});
|
|
12140
|
+
const syncedField = fieldsRef.current.find((f) => f.key === key);
|
|
12141
|
+
if (syncedField?.source === "synced" && host.writeSyncedCell) {
|
|
12142
|
+
const force = forceNext.current.delete(id);
|
|
12143
|
+
let outcome;
|
|
12144
|
+
try {
|
|
12145
|
+
outcome = await host.writeSyncedCell({ tableId, recordId: rowId, fieldKey: key, value: shown5, force });
|
|
12146
|
+
} catch (thrown) {
|
|
12147
|
+
outcome = { ok: false, message: thrown instanceof Error ? thrown.message : String(thrown) };
|
|
12148
|
+
}
|
|
12149
|
+
setSaving((held) => {
|
|
12150
|
+
const next = { ...held };
|
|
12151
|
+
delete next[id];
|
|
12152
|
+
return next;
|
|
12153
|
+
});
|
|
12154
|
+
if (outcome.ok && outcome.status === "written") {
|
|
12155
|
+
if (typeof outcome.version === "number") {
|
|
12156
|
+
rememberVersion(versions.current, rowId, outcome.version);
|
|
12157
|
+
source.wrote(rowId, outcome.version);
|
|
12158
|
+
}
|
|
12159
|
+
settling.current.set(id, base2);
|
|
12160
|
+
writtenRef.current?.({ rowId, key, before: base2, after: shown5 });
|
|
12161
|
+
afterWrite();
|
|
12162
|
+
return;
|
|
12163
|
+
}
|
|
12164
|
+
setOptimistic((held) => {
|
|
12165
|
+
const next = { ...held };
|
|
12166
|
+
delete next[id];
|
|
12167
|
+
return next;
|
|
12168
|
+
});
|
|
12169
|
+
const sheetValue = outcome.ok ? outcome.sheetValue : null;
|
|
12170
|
+
setRefusals((held) => ({
|
|
12171
|
+
...held,
|
|
12172
|
+
[id]: outcome.ok ? {
|
|
12173
|
+
error: { code: "stale_write", message: `The sheet now says "${sheetValue ?? ""}". Retry keeps yours.` },
|
|
12174
|
+
conflict: null,
|
|
12175
|
+
attempted: value,
|
|
12176
|
+
sheet: { value: sheetValue }
|
|
12177
|
+
} : { error: { code: "refused_by_rule", message: outcome.message }, conflict: null, attempted: value }
|
|
12178
|
+
}));
|
|
12179
|
+
return;
|
|
12180
|
+
}
|
|
12137
12181
|
let written;
|
|
12138
12182
|
try {
|
|
12139
12183
|
let version = await versionOf(source, versions.current, versionReads.current, rowId);
|
|
@@ -12293,6 +12337,7 @@ function useGridEditing({ tableId, fields, rows, reload, reloadAfterWrite, canWr
|
|
|
12293
12337
|
(rowId, key) => {
|
|
12294
12338
|
const held = refusals[cellKey(rowId, key)];
|
|
12295
12339
|
if (!held) return;
|
|
12340
|
+
if (held.sheet) forceNext.current.add(cellKey(rowId, key));
|
|
12296
12341
|
void writeCell(rowId, key, held.attempted, held.conflict?.contested_fields[key]);
|
|
12297
12342
|
},
|
|
12298
12343
|
[refusals, writeCell]
|
|
@@ -20007,6 +20052,20 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
|
|
|
20007
20052
|
const name = fieldName(field2);
|
|
20008
20053
|
const format = cellFormatFor(field2, look?.format);
|
|
20009
20054
|
const workedOut = workedOutFrom(field2);
|
|
20055
|
+
const syncedMark = field2.source === "synced" ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
20056
|
+
"span",
|
|
20057
|
+
{
|
|
20058
|
+
"data-records-synced": field2.key,
|
|
20059
|
+
title: `Synced from ${look?.syncedFrom || "its source"}`,
|
|
20060
|
+
"aria-label": `Synced from ${look?.syncedFrom || "its source"}`,
|
|
20061
|
+
className: "text-[10px] text-muted-foreground",
|
|
20062
|
+
children: "\u27F3"
|
|
20063
|
+
}
|
|
20064
|
+
) : null;
|
|
20065
|
+
const withSynced = (header) => syncedMark ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
20066
|
+
syncedMark,
|
|
20067
|
+
header
|
|
20068
|
+
] }) : header;
|
|
20010
20069
|
return {
|
|
20011
20070
|
id: field2.key,
|
|
20012
20071
|
/*
|
|
@@ -20014,38 +20073,40 @@ function columnForField(field2, editing, mayWriteRow, whyNotRow, look, onAskWhoC
|
|
|
20014
20073
|
* (`custom.formula_eval`, on read or on write) and nobody types it — so its header carries
|
|
20015
20074
|
* the mark, and the formula it is worked out from is one hover away, in its own words.
|
|
20016
20075
|
*/
|
|
20017
|
-
header:
|
|
20018
|
-
|
|
20019
|
-
|
|
20076
|
+
header: withSynced(
|
|
20077
|
+
look?.rowLabel ? (
|
|
20078
|
+
// THE COLUMN THAT NAMES EACH RECORD says so (tranche 6i, the older grid's key marker).
|
|
20079
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
20080
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
20081
|
+
"span",
|
|
20082
|
+
{
|
|
20083
|
+
"data-records-row-label": field2.key,
|
|
20084
|
+
title: "This column names each record",
|
|
20085
|
+
"aria-label": "Names each record",
|
|
20086
|
+
className: "text-[10px] text-muted-foreground",
|
|
20087
|
+
children: "\u26BF"
|
|
20088
|
+
}
|
|
20089
|
+
),
|
|
20090
|
+
name
|
|
20091
|
+
] })
|
|
20092
|
+
) : workedOut && stampMarkOf(field2) ? (
|
|
20093
|
+
// A STAMP OR A RECORD NUMBER (walk 2026-10-08 D7): kept by the store, but nobody wrote a formula
|
|
20094
|
+
// for it, so its header wears its own mark — a clock, a person, a number sign — never "fx".
|
|
20095
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "inline-flex items-center", title: workedOut, "data-records-stamp": stampMarkOf(field2), children: withTypeMark(field2, name) })
|
|
20096
|
+
) : workedOut ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
20097
|
+
name,
|
|
20020
20098
|
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
20021
20099
|
"span",
|
|
20022
20100
|
{
|
|
20023
|
-
"data-records-
|
|
20024
|
-
title:
|
|
20025
|
-
"aria-label":
|
|
20026
|
-
className: "text-[10px] text-muted-foreground",
|
|
20027
|
-
children: "
|
|
20101
|
+
"data-records-worked-out": field2.key,
|
|
20102
|
+
title: workedOut,
|
|
20103
|
+
"aria-label": workedOut,
|
|
20104
|
+
className: "rounded bg-muted px-1 font-mono text-[10px] font-normal text-muted-foreground",
|
|
20105
|
+
children: "fx"
|
|
20028
20106
|
}
|
|
20029
|
-
)
|
|
20030
|
-
|
|
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,
|
|
20107
|
+
)
|
|
20108
|
+
] }) : name
|
|
20109
|
+
),
|
|
20049
20110
|
label: name,
|
|
20050
20111
|
accessorFn: (row) => row.document?.[field2.key],
|
|
20051
20112
|
// A column the store keeps no value for is not offered a sort it would refuse (`sortRefusal`).
|
|
@@ -25981,7 +26042,8 @@ function GridBody({
|
|
|
25981
26042
|
...presentation.formats?.[field2.key] ? { format: presentation.formats[field2.key] } : {},
|
|
25982
26043
|
frozen: frozenKeys.has(field2.key),
|
|
25983
26044
|
// The column that names each record wears the mark (merged grid, tranche 6i).
|
|
25984
|
-
rowLabel: merged && field2.key === (table.data?.title_field ?? null)
|
|
26045
|
+
rowLabel: merged && field2.key === (table.data?.title_field ?? null),
|
|
26046
|
+
syncedFrom: syncedFromWords(table.data)
|
|
25985
26047
|
},
|
|
25986
26048
|
onAskWhoChanged,
|
|
25987
26049
|
{
|
|
@@ -27170,6 +27232,12 @@ function withHeaderMenus(columns, menuFor, filterFor) {
|
|
|
27170
27232
|
return filter ? { ...withMenu, ...filter } : withMenu;
|
|
27171
27233
|
});
|
|
27172
27234
|
}
|
|
27235
|
+
function syncedFromWords(table) {
|
|
27236
|
+
const source = table?.sync_source;
|
|
27237
|
+
if (!source?.provider) return null;
|
|
27238
|
+
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;
|
|
27239
|
+
return source.label ? `${from} \xB7 ${source.label}` : from;
|
|
27240
|
+
}
|
|
27173
27241
|
function withoutGoneColumns(query, liveKeys, openingSort) {
|
|
27174
27242
|
const sortGone = Boolean(query.sort && !liveKeys.has(query.sort.id));
|
|
27175
27243
|
const goneFilters = Object.keys(query.columnFilters ?? {}).filter((key) => !liveKeys.has(key));
|
|
@@ -35022,6 +35090,9 @@ function packRows(bars) {
|
|
|
35022
35090
|
return { ...bar, row };
|
|
35023
35091
|
});
|
|
35024
35092
|
}
|
|
35093
|
+
function shortDay(day2) {
|
|
35094
|
+
return dayAt(day2).toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
35095
|
+
}
|
|
35025
35096
|
function windowStart(anchor, zoom, firstDay) {
|
|
35026
35097
|
const from = dayAt(addDays(anchor, -WINDOW[zoom].lead));
|
|
35027
35098
|
if (zoom === "day" || zoom === "week") from.setDate(from.getDate() - daysSinceWeekStart(from.getDay(), firstDay));
|
|
@@ -35359,7 +35430,7 @@ function TimelineView({
|
|
|
35359
35430
|
try {
|
|
35360
35431
|
const make = async (current, key, label) => {
|
|
35361
35432
|
if (current) return current.key;
|
|
35362
|
-
const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label,
|
|
35433
|
+
const made = await knobClient.fieldDeclare({ table_id: tableId, spec: { key, label, parity_type: "datetime", kind: "date" } });
|
|
35363
35434
|
if (!made.ok) {
|
|
35364
35435
|
moves.say(refusalSentence(made.error));
|
|
35365
35436
|
return null;
|
|
@@ -35880,8 +35951,8 @@ function TimelineView({
|
|
|
35880
35951
|
const slip = slipDays(baselineOf(b.p.row)?.last ?? null, at.last);
|
|
35881
35952
|
return /* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("div", { "data-timeline-list-row": b.p.row.id, className: "flex items-center gap-1 px-1.5 text-xs", style: { height: ROW_PX }, children: [
|
|
35882
35953
|
/* @__PURE__ */ (0, import_jsx_runtime120.jsx)("button", { type: "button", className: "min-w-0 flex-1 truncate text-left hover:underline", onClick: () => onOpenRecord?.(b.p.row.id), children: titleOf(b.p.row) }),
|
|
35883
|
-
/* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 tabular-nums text-muted-foreground", children:
|
|
35884
|
-
/* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 tabular-nums text-muted-foreground", children:
|
|
35954
|
+
/* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: shortDay(at.first) }),
|
|
35955
|
+
/* @__PURE__ */ (0, import_jsx_runtime120.jsx)("span", { className: "w-12 shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: shortDay(at.last) }),
|
|
35885
35956
|
/* @__PURE__ */ (0, import_jsx_runtime120.jsxs)("span", { className: "w-14 shrink-0 text-right tabular-nums", title: slip !== null ? slipWords(slip) : void 0, children: [
|
|
35886
35957
|
daysBetween(at.first, at.last) + 1,
|
|
35887
35958
|
"d",
|