@ai-matrx/records-ui 0.93.2 → 0.93.4
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 +17 -0
- package/dist/index.cjs +665 -424
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +579 -338
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -4349,7 +4349,20 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow,
|
|
|
4349
4349
|
}
|
|
4350
4350
|
return null;
|
|
4351
4351
|
}, [client, tableId, reload, order]);
|
|
4352
|
+
const rowSignature = (0, import_react22.useCallback)(
|
|
4353
|
+
(rowId) => {
|
|
4354
|
+
const out = [];
|
|
4355
|
+
if (editing?.rowId === rowId) out.push("open", editing.key, draft);
|
|
4356
|
+
const prefix = `${rowId}::`;
|
|
4357
|
+
for (const id in optimistic) if (id.startsWith(prefix)) out.push("held", id, optimistic[id]);
|
|
4358
|
+
for (const id in saving) if (id.startsWith(prefix)) out.push("saving", id);
|
|
4359
|
+
for (const id in refusals) if (id.startsWith(prefix)) out.push("refused", id, refusals[id]);
|
|
4360
|
+
return out;
|
|
4361
|
+
},
|
|
4362
|
+
[editing, draft, optimistic, saving, refusals]
|
|
4363
|
+
);
|
|
4352
4364
|
return {
|
|
4365
|
+
rowSignature,
|
|
4353
4366
|
valueFor,
|
|
4354
4367
|
editing,
|
|
4355
4368
|
draft,
|
|
@@ -7965,6 +7978,10 @@ function useMergedGridControls(args) {
|
|
|
7965
7978
|
(columnKey) => enabled && fieldOf2(columnKey) ? headerMenuItems(columnKey, ctx) : void 0,
|
|
7966
7979
|
[enabled, ctx, fieldOf2]
|
|
7967
7980
|
);
|
|
7981
|
+
const columnsControl = (0, import_react40.useMemo)(
|
|
7982
|
+
() => enabled ? { order, hidden, onChange: keepColumns } : void 0,
|
|
7983
|
+
[enabled, order, hidden, keepColumns]
|
|
7984
|
+
);
|
|
7968
7985
|
const close = () => setDialog(null);
|
|
7969
7986
|
const dialogs = !enabled ? null : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
7970
7987
|
colours.dialogs,
|
|
@@ -8096,7 +8113,7 @@ function useMergedGridControls(args) {
|
|
|
8096
8113
|
headerMenuFor,
|
|
8097
8114
|
filterFor,
|
|
8098
8115
|
contextMenu,
|
|
8099
|
-
columns:
|
|
8116
|
+
columns: columnsControl,
|
|
8100
8117
|
dialogs,
|
|
8101
8118
|
addColumn: () => setDialog({ kind: "insert", anchor: null, side: "right" }),
|
|
8102
8119
|
sheetTools: enabled ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
@@ -8202,11 +8219,12 @@ function placePinnedRows(pageRows, pinned, anchors) {
|
|
|
8202
8219
|
}
|
|
8203
8220
|
function withAddRowCells(columns, line) {
|
|
8204
8221
|
if (line === null) return columns;
|
|
8222
|
+
const draw = () => typeof line === "function" ? line() : line;
|
|
8205
8223
|
return columns.map((column, index) => {
|
|
8206
8224
|
const own2 = column.cell;
|
|
8207
8225
|
return {
|
|
8208
8226
|
...column,
|
|
8209
|
-
cell: (row, rowIndex) => row.id === ADD_ROW_ID ? index === 0 ?
|
|
8227
|
+
cell: (row, rowIndex) => row.id === ADD_ROW_ID ? index === 0 ? draw() : null : own2 ? own2(row, rowIndex) : null
|
|
8210
8228
|
};
|
|
8211
8229
|
});
|
|
8212
8230
|
}
|
|
@@ -8229,6 +8247,7 @@ function AddRowLine({ onAdd, busy }) {
|
|
|
8229
8247
|
}
|
|
8230
8248
|
);
|
|
8231
8249
|
}
|
|
8250
|
+
var drawNothing = () => null;
|
|
8232
8251
|
function addColumnColumn(onAdd) {
|
|
8233
8252
|
return {
|
|
8234
8253
|
id: ADD_COLUMN_ID,
|
|
@@ -8248,7 +8267,8 @@ function addColumnColumn(onAdd) {
|
|
|
8248
8267
|
children: "+"
|
|
8249
8268
|
}
|
|
8250
8269
|
),
|
|
8251
|
-
|
|
8270
|
+
// ONE function for the life of the module: a body cell that draws nothing never changes.
|
|
8271
|
+
cell: drawNothing,
|
|
8252
8272
|
sortable: false,
|
|
8253
8273
|
filter: false,
|
|
8254
8274
|
hideable: false,
|
|
@@ -9623,7 +9643,43 @@ function useGridUndo(args) {
|
|
|
9623
9643
|
[push, undo, redo, held, busy, notice, dismiss]
|
|
9624
9644
|
);
|
|
9625
9645
|
}
|
|
9626
|
-
function
|
|
9646
|
+
function useUndoSource(undo) {
|
|
9647
|
+
const box = (0, import_react52.useRef)({
|
|
9648
|
+
undo,
|
|
9649
|
+
face: { back: undo.depth.back, forward: undo.depth.forward, busy: undo.busy },
|
|
9650
|
+
listeners: /* @__PURE__ */ new Set()
|
|
9651
|
+
});
|
|
9652
|
+
box.current.undo = undo;
|
|
9653
|
+
const source = (0, import_react52.useMemo)(
|
|
9654
|
+
() => ({
|
|
9655
|
+
face: () => box.current.face,
|
|
9656
|
+
subscribe: (listener) => {
|
|
9657
|
+
box.current.listeners.add(listener);
|
|
9658
|
+
return () => {
|
|
9659
|
+
box.current.listeners.delete(listener);
|
|
9660
|
+
};
|
|
9661
|
+
},
|
|
9662
|
+
undo: () => void box.current.undo.undo(),
|
|
9663
|
+
redo: () => void box.current.undo.redo()
|
|
9664
|
+
}),
|
|
9665
|
+
[]
|
|
9666
|
+
);
|
|
9667
|
+
const { back, forward } = undo.depth;
|
|
9668
|
+
const busy = undo.busy;
|
|
9669
|
+
(0, import_react52.useLayoutEffect)(() => {
|
|
9670
|
+
const held = box.current.face;
|
|
9671
|
+
if (held.back === back && held.forward === forward && held.busy === busy) return;
|
|
9672
|
+
box.current.face = { back, forward, busy };
|
|
9673
|
+
for (const listener of box.current.listeners) listener();
|
|
9674
|
+
}, [back, forward, busy]);
|
|
9675
|
+
return source;
|
|
9676
|
+
}
|
|
9677
|
+
function UndoRedoLive({ source }) {
|
|
9678
|
+
const face = (0, import_react52.useSyncExternalStore)(source.subscribe, source.face, source.face);
|
|
9679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(UndoRedoPair, { face, onUndo: source.undo, onRedo: source.redo });
|
|
9680
|
+
}
|
|
9681
|
+
function UndoRedoPair({ face, onUndo, onRedo }) {
|
|
9682
|
+
const undo = { depth: { back: face.back, forward: face.forward }, busy: face.busy };
|
|
9627
9683
|
if (undo.depth.back === 0 && undo.depth.forward === 0) return null;
|
|
9628
9684
|
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
9629
9685
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
@@ -9635,7 +9691,7 @@ function UndoRedoButtons({ undo }) {
|
|
|
9635
9691
|
title: undo.depth.back > 0 ? `Undo (Cmd-Z) \xB7 ${undo.depth.back} ${undo.depth.back === 1 ? "step" : "steps"} back` : "Nothing to undo",
|
|
9636
9692
|
"aria-label": `Undo, ${undo.depth.back} ${undo.depth.back === 1 ? "step" : "steps"}`,
|
|
9637
9693
|
disabled: undo.busy || undo.depth.back === 0,
|
|
9638
|
-
onClick:
|
|
9694
|
+
onClick: onUndo,
|
|
9639
9695
|
children: [
|
|
9640
9696
|
"Undo ",
|
|
9641
9697
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ml-1 tabular-nums text-muted-foreground", "data-records-undo-count": "", children: undo.depth.back })
|
|
@@ -9651,7 +9707,7 @@ function UndoRedoButtons({ undo }) {
|
|
|
9651
9707
|
title: undo.depth.forward > 0 ? `Redo (Shift-Cmd-Z) \xB7 ${undo.depth.forward} ${undo.depth.forward === 1 ? "step" : "steps"} forward` : "Nothing to redo",
|
|
9652
9708
|
"aria-label": `Redo, ${undo.depth.forward} ${undo.depth.forward === 1 ? "step" : "steps"}`,
|
|
9653
9709
|
disabled: undo.busy || undo.depth.forward === 0,
|
|
9654
|
-
onClick:
|
|
9710
|
+
onClick: onRedo,
|
|
9655
9711
|
children: [
|
|
9656
9712
|
"Redo ",
|
|
9657
9713
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ml-1 tabular-nums text-muted-foreground", "data-records-redo-count": "", children: undo.depth.forward })
|
|
@@ -10836,6 +10892,8 @@ function HandOrderDialog({
|
|
|
10836
10892
|
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
10837
10893
|
var NO_COLUMNS_YET = "This table has no columns yet";
|
|
10838
10894
|
var NO_COLUMNS_WHY = "A column is what a record holds \u2014 a name, a date, an amount, a person. Add the first one and the grid appears with it; everything else on this page works the moment it exists.";
|
|
10895
|
+
var NO_SUMMARIES = Object.freeze({});
|
|
10896
|
+
var rowIdOf = (row) => row.id;
|
|
10839
10897
|
function Grid({
|
|
10840
10898
|
tableId,
|
|
10841
10899
|
pageSize = 50,
|
|
@@ -10985,7 +11043,17 @@ function Grid({
|
|
|
10985
11043
|
onEnded: (exit, from, how) => sheetController.current?.endEdit(exit, { rowId: from.rowId, columnId: from.key }, how)
|
|
10986
11044
|
} : {}
|
|
10987
11045
|
});
|
|
11046
|
+
const editingNow = (0, import_react60.useRef)(editing);
|
|
11047
|
+
editingNow.current = editing;
|
|
11048
|
+
const editingHandle = (0, import_react60.useMemo)(
|
|
11049
|
+
() => new Proxy({}, {
|
|
11050
|
+
get: (_target, key) => editingNow.current[key]
|
|
11051
|
+
}),
|
|
11052
|
+
[]
|
|
11053
|
+
);
|
|
11054
|
+
const rowVersion = (0, import_react60.useCallback)((row) => editingNow.current.rowSignature(row.id), []);
|
|
10988
11055
|
const undo = useGridUndo({ tableId, reload: records.reload, forget: editing.forget });
|
|
11056
|
+
const undoSource = useUndoSource(undo);
|
|
10989
11057
|
pushWritten.current = (write) => {
|
|
10990
11058
|
const field2 = (fields.data ?? []).find((f) => f.key === write.key);
|
|
10991
11059
|
const name = changedRecordName(table.data, rows.find((r) => r.id === write.rowId)?.document ?? {}, write.key, write.after);
|
|
@@ -11055,7 +11123,7 @@ function Grid({
|
|
|
11055
11123
|
const [selectedIds, setSelectedIds] = (0, import_react60.useState)([]);
|
|
11056
11124
|
const offerSelection = canWrite && (merged || tableActions.runnable.length > 0);
|
|
11057
11125
|
const [reordering, setReordering] = (0, import_react60.useState)(false);
|
|
11058
|
-
const chosenSummaries = localSummaries ?? presentation.summaries ??
|
|
11126
|
+
const chosenSummaries = localSummaries ?? presentation.summaries ?? NO_SUMMARIES;
|
|
11059
11127
|
const summaries = useColumnSummaries({ tableId, chosen: chosenSummaries, filter: question.filter, version: records.data });
|
|
11060
11128
|
const [duplicated, setDuplicated] = (0, import_react60.useState)(null);
|
|
11061
11129
|
const duplicate = (0, import_react60.useCallback)(
|
|
@@ -11504,7 +11572,7 @@ function Grid({
|
|
|
11504
11572
|
() => ordered.map(
|
|
11505
11573
|
(field2) => columnForField(
|
|
11506
11574
|
field2,
|
|
11507
|
-
canWrite ?
|
|
11575
|
+
canWrite ? editingHandle : null,
|
|
11508
11576
|
mayWriteRow,
|
|
11509
11577
|
whyNotRow,
|
|
11510
11578
|
{
|
|
@@ -11523,7 +11591,7 @@ function Grid({
|
|
|
11523
11591
|
[
|
|
11524
11592
|
ordered,
|
|
11525
11593
|
canWrite,
|
|
11526
|
-
|
|
11594
|
+
editingHandle,
|
|
11527
11595
|
mayWriteRow,
|
|
11528
11596
|
whyNotRow,
|
|
11529
11597
|
presentation.formats,
|
|
@@ -11535,9 +11603,39 @@ function Grid({
|
|
|
11535
11603
|
pinCell
|
|
11536
11604
|
]
|
|
11537
11605
|
);
|
|
11538
|
-
const
|
|
11539
|
-
() =>
|
|
11540
|
-
|
|
11606
|
+
const footerNow = (0, import_react60.useRef)({
|
|
11607
|
+
summaryCell: () => null,
|
|
11608
|
+
addLine: () => null,
|
|
11609
|
+
choose: () => void 0,
|
|
11610
|
+
add: () => void 0
|
|
11611
|
+
});
|
|
11612
|
+
footerNow.current = {
|
|
11613
|
+
// The footer is memoised on what it shows (`footerRows` below), so its buttons act through here.
|
|
11614
|
+
choose: chooseSummary,
|
|
11615
|
+
add: () => void addRowHere(),
|
|
11616
|
+
summaryCell: (columnId) => {
|
|
11617
|
+
const field2 = ordered.find((f) => f.key === columnId);
|
|
11618
|
+
if (!field2) return null;
|
|
11619
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11620
|
+
SummaryCell,
|
|
11621
|
+
{
|
|
11622
|
+
field: field2,
|
|
11623
|
+
firstColumn: ordered[0]?.key === columnId,
|
|
11624
|
+
chosen: chosenSummaries[columnId],
|
|
11625
|
+
value: summaries.values[columnId],
|
|
11626
|
+
rowCount: summaries.rowCount,
|
|
11627
|
+
summaries,
|
|
11628
|
+
onChoose: (op2) => footerNow.current.choose(columnId, op2)
|
|
11629
|
+
}
|
|
11630
|
+
);
|
|
11631
|
+
},
|
|
11632
|
+
addLine: () => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AddRowLine, { onAdd: () => footerNow.current.add(), busy: added.busy })
|
|
11633
|
+
};
|
|
11634
|
+
const addColumnNow = (0, import_react60.useRef)(controls.addColumn);
|
|
11635
|
+
addColumnNow.current = controls.addColumn;
|
|
11636
|
+
const bodyColumns = (0, import_react60.useMemo)(
|
|
11637
|
+
() => withAddRowCells(
|
|
11638
|
+
withSummaryCells(
|
|
11541
11639
|
// THE ONE WAY A ROW OPENS ITS RECORD (VERIFIER-17): an Open control on the first cell,
|
|
11542
11640
|
// and Space on any cell. Absent when the host cannot open a record.
|
|
11543
11641
|
withOpenRecord(
|
|
@@ -11547,27 +11645,123 @@ function Grid({
|
|
|
11547
11645
|
// The merged grid's handle sits at the START of the row, where Airtable's expand sits.
|
|
11548
11646
|
merged ? "start" : "end"
|
|
11549
11647
|
),
|
|
11550
|
-
(columnId) =>
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11648
|
+
(columnId) => footerNow.current.summaryCell(columnId)
|
|
11649
|
+
),
|
|
11650
|
+
mayAddRow ? () => footerNow.current.addLine() : null
|
|
11651
|
+
),
|
|
11652
|
+
[fieldColumns, onOpenRecord, table.data, merged, mayAddRow]
|
|
11653
|
+
);
|
|
11654
|
+
const isRowSelectable = (0, import_react60.useCallback)((row) => row.id !== SUMMARY_ROW.id && mayWriteRow(row.id), [mayWriteRow]);
|
|
11655
|
+
const copyConfig = (0, import_react60.useMemo)(
|
|
11656
|
+
() => table.data ? gridCopyConfig({
|
|
11657
|
+
tableId,
|
|
11658
|
+
tableName: tableName(table.data),
|
|
11659
|
+
fields: ordered,
|
|
11660
|
+
rowLabel: (row) => recordNameIn(table.data, row.document ?? {})
|
|
11661
|
+
}) : null,
|
|
11662
|
+
[tableId, table.data, ordered]
|
|
11663
|
+
);
|
|
11664
|
+
const tableStyleProp = (0, import_react60.useMemo)(
|
|
11665
|
+
() => (0, import_data_table9.tableStyleIsEmpty)(paint.style) ? null : {
|
|
11666
|
+
style: paint.style,
|
|
11667
|
+
// A choice is read as its OPTION (`paintByOption`): the rule, the value and the
|
|
11668
|
+
// colour a column keeps for it all name the same option, however it is stored.
|
|
11669
|
+
documentOf: (row) => paint.documentOf(row.document ?? {}),
|
|
11670
|
+
// A value its column keeps a colour for wears THAT colour (`choiceLooks.ts`);
|
|
11671
|
+
// any other value still paints from its word.
|
|
11672
|
+
choiceColorFor: paint.choiceColorFor
|
|
11673
|
+
},
|
|
11674
|
+
[paint]
|
|
11675
|
+
);
|
|
11676
|
+
const rowActionsNow = (0, import_react60.useRef)({ runner, handToAgent, host, table: table.data, duplicate });
|
|
11677
|
+
rowActionsNow.current = { runner, handToAgent, host, table: table.data, duplicate };
|
|
11678
|
+
const offersRowActions = canWrite || Boolean(host.talkToRecord) || Boolean(host.runAgentAction && tableActions.agent.length > 0);
|
|
11679
|
+
const hasTalk = Boolean(host.talkToRecord);
|
|
11680
|
+
const hasAgent = Boolean(host.runAgentAction);
|
|
11681
|
+
const rowActions = (0, import_react60.useCallback)(
|
|
11682
|
+
(row) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
11683
|
+
canWrite && mayWriteRow(row.id) ? tableActions.runnable.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11684
|
+
ActionButton,
|
|
11685
|
+
{
|
|
11686
|
+
action,
|
|
11687
|
+
busy: runner.busy === action.id,
|
|
11688
|
+
onPress: () => rowActionsNow.current.runner.press(action, [row.id])
|
|
11689
|
+
},
|
|
11690
|
+
action.id
|
|
11691
|
+
)) : null,
|
|
11692
|
+
host.runAgentAction ? tableActions.agent.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11693
|
+
ActionButton,
|
|
11694
|
+
{
|
|
11695
|
+
action,
|
|
11696
|
+
busy: false,
|
|
11697
|
+
onPress: () => rowActionsNow.current.handToAgent(action, row)
|
|
11698
|
+
},
|
|
11699
|
+
action.id
|
|
11700
|
+
)) : null,
|
|
11701
|
+
host.talkToRecord ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11702
|
+
import_design_system35.Button,
|
|
11703
|
+
{
|
|
11704
|
+
size: "sm",
|
|
11705
|
+
variant: "ghost",
|
|
11706
|
+
onClick: () => rowActionsNow.current.host.talkToRecord?.({
|
|
11707
|
+
tableId,
|
|
11708
|
+
recordId: row.id,
|
|
11709
|
+
// ONE NAMING CALL (`names.ts`), not this file's own join
|
|
11710
|
+
// of a Table's title column to a document.
|
|
11711
|
+
title: recordNameIn(
|
|
11712
|
+
rowActionsNow.current.table,
|
|
11713
|
+
row.document ?? {}
|
|
11714
|
+
)
|
|
11715
|
+
}),
|
|
11716
|
+
children: "Talk"
|
|
11565
11717
|
}
|
|
11566
|
-
)
|
|
11567
|
-
|
|
11718
|
+
) : null,
|
|
11719
|
+
Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11720
|
+
import_design_system35.Button,
|
|
11721
|
+
{
|
|
11722
|
+
size: "sm",
|
|
11723
|
+
variant: "ghost",
|
|
11724
|
+
"data-records-duplicate": row.id,
|
|
11725
|
+
title: "Duplicate this record",
|
|
11726
|
+
onClick: (event) => {
|
|
11727
|
+
event.stopPropagation();
|
|
11728
|
+
void rowActionsNow.current.duplicate(row);
|
|
11729
|
+
},
|
|
11730
|
+
children: "Duplicate"
|
|
11731
|
+
}
|
|
11732
|
+
) : null,
|
|
11733
|
+
canWrite && mayWriteRow(row.id) ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11734
|
+
import_design_system35.Button,
|
|
11735
|
+
{
|
|
11736
|
+
size: "sm",
|
|
11737
|
+
variant: "ghost",
|
|
11738
|
+
title: "Delete this record",
|
|
11739
|
+
onClick: () => setDeleting(row),
|
|
11740
|
+
children: "Delete"
|
|
11741
|
+
}
|
|
11742
|
+
) : null
|
|
11743
|
+
] }),
|
|
11744
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- `hasTalk`/`hasAgent` stand for the host ports the JSX reads; handlers run through `rowActionsNow`.
|
|
11745
|
+
[canWrite, mayWriteRow, tableActions.runnable, tableActions.agent, runner.busy, hasTalk, hasAgent, editable, rights.write]
|
|
11746
|
+
);
|
|
11747
|
+
const headerHeld = (0, import_react60.useRef)(/* @__PURE__ */ new Map());
|
|
11748
|
+
const menuLatest = (0, import_react60.useRef)(/* @__PURE__ */ new Map());
|
|
11749
|
+
const addColumnDef = (0, import_react60.useMemo)(() => addColumnColumn(() => addColumnNow.current()), []);
|
|
11750
|
+
const drawnColumns = (0, import_react60.useMemo)(
|
|
11751
|
+
() => {
|
|
11752
|
+
const filterFor = controls.filterFor;
|
|
11753
|
+
const drawn = withHeaderMenus(
|
|
11754
|
+
bodyColumns,
|
|
11755
|
+
(key) => holdHeaderMenu(headerHeld.current, menuLatest.current, key, controls.headerMenuFor(key)),
|
|
11756
|
+
(key) => holdByContent(headerHeld.current, `filter:${key}`, filterFor(key))
|
|
11757
|
+
);
|
|
11758
|
+
return merged && rights.structure && editable ? [...drawn, addColumnDef] : drawn;
|
|
11568
11759
|
},
|
|
11569
|
-
[
|
|
11760
|
+
[bodyColumns, controls.headerMenuFor, controls.filterFor, merged, rights.structure, editable, addColumnDef]
|
|
11570
11761
|
);
|
|
11762
|
+
const columnsHeld = (0, import_react60.useRef)(null);
|
|
11763
|
+
const columns = columnsHeld.current !== null && sameColumns(columnsHeld.current, drawnColumns) ? columnsHeld.current : drawnColumns;
|
|
11764
|
+
columnsHeld.current = columns;
|
|
11571
11765
|
const [localColumns, setLocalColumns] = (0, import_react60.useState)(
|
|
11572
11766
|
null
|
|
11573
11767
|
);
|
|
@@ -11640,6 +11834,274 @@ function Grid({
|
|
|
11640
11834
|
} : {}
|
|
11641
11835
|
};
|
|
11642
11836
|
}, [presentation, onPresentationChange, writeLook, merged, phone]);
|
|
11837
|
+
const queryTotal = records.data?.total ?? rows.length;
|
|
11838
|
+
const tableQuery = (0, import_react60.useMemo)(
|
|
11839
|
+
() => merged ? {
|
|
11840
|
+
// THE STORE ANSWERS THE QUERY (tranche 6k): `data` is already the page.
|
|
11841
|
+
mode: "controlled",
|
|
11842
|
+
state: query,
|
|
11843
|
+
totalItems: queryTotal,
|
|
11844
|
+
onStateChange: setQuery,
|
|
11845
|
+
sourceProcessing: { search: "source", columnFilters: "source", sort: "source" }
|
|
11846
|
+
} : { mode: "controlled-local", state: query, onStateChange: setQuery },
|
|
11847
|
+
[merged, query, queryTotal]
|
|
11848
|
+
);
|
|
11849
|
+
const showAddLine = mayAddRow && rows.length > 0;
|
|
11850
|
+
const showSummaryLine = rows.length > 0 && (!merged || Object.keys(chosenSummaries).length > 0);
|
|
11851
|
+
const footerFace = JSON.stringify([
|
|
11852
|
+
showAddLine ? added.busy : null,
|
|
11853
|
+
showSummaryLine ? [chosenSummaries, summaries.values, summaries.rowCount, summaries.loading] : null
|
|
11854
|
+
]);
|
|
11855
|
+
const footerRows = (0, import_react60.useMemo)(
|
|
11856
|
+
() => [...showAddLine ? [ADD_ROW] : [], ...showSummaryLine ? [SUMMARY_ROW] : []],
|
|
11857
|
+
// `footerFace`, `ordered` and the summaries' operations are what the footer's cells draw.
|
|
11858
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
11859
|
+
[showAddLine, showSummaryLine, footerFace, ordered, summaries.operations, summaries.askOperations]
|
|
11860
|
+
);
|
|
11861
|
+
const coverageTotal = typeof records.data?.total === "number" ? records.data.total : null;
|
|
11862
|
+
const tableCoverage = (0, import_react60.useMemo)(
|
|
11863
|
+
() => ({
|
|
11864
|
+
answeredBy: merged ? "source" : "client",
|
|
11865
|
+
...merged && coverageTotal !== null ? { matched: coverageTotal } : {},
|
|
11866
|
+
noun: "record",
|
|
11867
|
+
...coverageTotal !== null ? { total: coverageTotal } : {}
|
|
11868
|
+
}),
|
|
11869
|
+
[merged, coverageTotal]
|
|
11870
|
+
);
|
|
11871
|
+
const sheetNow = (0, import_react60.useRef)({ merged, writeRange, editing, fields: fields.data ?? [], mayWriteRow, notify: host.notify });
|
|
11872
|
+
sheetNow.current = { merged, writeRange, editing, fields: fields.data ?? [], mayWriteRow, notify: host.notify };
|
|
11873
|
+
const hasNotify = Boolean(host.notify);
|
|
11874
|
+
const readOnlyReason = !editable || !rights.known || rights.write ? "Editing is off here, so this table can be copied but not changed." : rights.why("write");
|
|
11875
|
+
const spreadsheetConfig = (0, import_react60.useMemo)(
|
|
11876
|
+
() => canWrite && editable ? {
|
|
11877
|
+
enabled: true,
|
|
11878
|
+
writableColumnIds: pasteableKeys,
|
|
11879
|
+
onPatch: (patches, intent) => {
|
|
11880
|
+
const now = sheetNow.current;
|
|
11881
|
+
if (now.merged) {
|
|
11882
|
+
void now.writeRange(patches, intent);
|
|
11883
|
+
return;
|
|
11884
|
+
}
|
|
11885
|
+
for (const patch of patches) {
|
|
11886
|
+
now.editing.setCell(patch.rowId, patch.columnId, patch.value);
|
|
11887
|
+
}
|
|
11888
|
+
},
|
|
11889
|
+
...merged ? { undoDepth: 0, onSelectionChange: followSelection, controllerRef: sheetController } : {},
|
|
11890
|
+
columnRefusal: (columnId) => {
|
|
11891
|
+
const field2 = sheetNow.current.fields.find((f) => f.key === columnId);
|
|
11892
|
+
if (!field2) return `This table has no column called ${columnId}.`;
|
|
11893
|
+
return `${fieldName(field2)} cannot take a pasted value \u2014 ${fieldTypeLabel(field2)} is worked out or chosen, not typed.`;
|
|
11894
|
+
},
|
|
11895
|
+
validateCell: ({ columnId, value }) => {
|
|
11896
|
+
const field2 = sheetNow.current.fields.find((f) => f.key === columnId);
|
|
11897
|
+
if (!field2) return `This table has no column called ${columnId}.`;
|
|
11898
|
+
const judged = valueFromPastedText(field2, value === null ? "" : String(value));
|
|
11899
|
+
return "refusal" in judged ? judged.refusal : void 0;
|
|
11900
|
+
},
|
|
11901
|
+
onPastePlan: receivePastePlan,
|
|
11902
|
+
/*
|
|
11903
|
+
* TYPE-TO-EDIT (design-system 0.43 `onEditRequest`): the cell a person is on
|
|
11904
|
+
* opens ITS OWN editor — the Field's — holding what they typed (a letter, an
|
|
11905
|
+
* IME composition, an Option/AltGr character, dictation). A worked-out column
|
|
11906
|
+
* or a row this person may not write answers false, so nothing is swallowed.
|
|
11907
|
+
*/
|
|
11908
|
+
onEditRequest: (address, seed) => {
|
|
11909
|
+
const now = sheetNow.current;
|
|
11910
|
+
const field2 = now.fields.find((f) => f.key === address.columnId);
|
|
11911
|
+
if (!field2 || !fieldIsEditable(field2) || !now.mayWriteRow(address.rowId)) return false;
|
|
11912
|
+
if (seed !== null && seed !== "" && typingOpens(field2) === "none") return false;
|
|
11913
|
+
now.editing.begin({ rowId: address.rowId, key: field2.key }, seed);
|
|
11914
|
+
return true;
|
|
11915
|
+
},
|
|
11916
|
+
...hasNotify ? { notify: (message) => sheetNow.current.notify?.success(message) } : {}
|
|
11917
|
+
} : {
|
|
11918
|
+
/*
|
|
11919
|
+
* RANGE SELECTION AND COPY FOR A READER (merge step 3, 0.42 `readOnly`). A person
|
|
11920
|
+
* who may not change this table may still drag out a range, select all and press
|
|
11921
|
+
* Cmd-C for a real Excel/Sheets block — the UX walk graded range selection BROKEN
|
|
11922
|
+
* on a table whose writes were refused. Every write gesture (cut, paste, clear,
|
|
11923
|
+
* fill, undo) says why it cannot, in the store's own words.
|
|
11924
|
+
*/
|
|
11925
|
+
enabled: true,
|
|
11926
|
+
readOnly: true,
|
|
11927
|
+
...merged ? { onSelectionChange: followSelection, controllerRef: sheetController } : {},
|
|
11928
|
+
readOnlyReason
|
|
11929
|
+
},
|
|
11930
|
+
[canWrite, editable, pasteableKeys, merged, followSelection, receivePastePlan, hasNotify, readOnlyReason]
|
|
11931
|
+
);
|
|
11932
|
+
const toolbarFields = fields.data;
|
|
11933
|
+
const hasSeveralRows = rows.length > 1;
|
|
11934
|
+
const editingBusy = editing.busy;
|
|
11935
|
+
const addRecord = editing.addRecord;
|
|
11936
|
+
const phoneSheetTools = merged && phone ? controls.sheetTools : null;
|
|
11937
|
+
const tableToolbar = (0, import_react60.useMemo)(
|
|
11938
|
+
() => ({
|
|
11939
|
+
search: true,
|
|
11940
|
+
searchPlaceholder: "Search records",
|
|
11941
|
+
/*
|
|
11942
|
+
* A PHONE (tranche 6o): search and the one Tools button sit side by side at the START of
|
|
11943
|
+
* the row, so Tools is never scrolled out of reach; the search is the same query.
|
|
11944
|
+
*/
|
|
11945
|
+
...merged && phone ? {
|
|
11946
|
+
customSearch: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "flex min-w-0 flex-1 items-center gap-1.5", "data-records-grid-phone-search": "", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11947
|
+
"input",
|
|
11948
|
+
{
|
|
11949
|
+
type: "search",
|
|
11950
|
+
value: query.search,
|
|
11951
|
+
placeholder: "Search",
|
|
11952
|
+
"aria-label": "Search records",
|
|
11953
|
+
onChange: (event) => {
|
|
11954
|
+
const search = event.target.value;
|
|
11955
|
+
setQuery((held) => ({ ...held, search, page: 1 }));
|
|
11956
|
+
},
|
|
11957
|
+
className: "h-8 w-full min-w-0 rounded-md border border-input bg-background px-2 text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
11958
|
+
style: { fontSize: "16px" }
|
|
11959
|
+
}
|
|
11960
|
+
) })
|
|
11961
|
+
} : {},
|
|
11962
|
+
/* ONE ROW (lane TABLE-PAGE-CHROME): on a table page the grid's search, columns and
|
|
11963
|
+
sort are drawn INTO the page's toolbar row, never a second bar under it. */
|
|
11964
|
+
...toolbarSlot !== void 0 ? { portalInto: toolbarSlot, singleRow: true } : {},
|
|
11965
|
+
// SCR-2 / SCR-4: PRESENT for an admin, ABSENT for everyone else.
|
|
11966
|
+
// There is no third state: this package ships no disabled variant of
|
|
11967
|
+
// these controls, so a member cannot be shown a dead one by mistake.
|
|
11968
|
+
/*
|
|
11969
|
+
* WHERE THE GRID'S CONTROLS GO (lane C, review 2026-09-26 D6). Inline when the row has
|
|
11970
|
+
* room; behind the row's "…" once the page row is folded that far (Undo / Redo and New
|
|
11971
|
+
* record stay beside it — the primary action is never folded); on a phone EVERY control
|
|
11972
|
+
* — the table's own (clear, copy/export, group, columns), these, the search, the sort and
|
|
11973
|
+
* the page's filter, layout and share — in ONE "Tools" sheet. Never dropped.
|
|
11974
|
+
*/
|
|
11975
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
11976
|
+
manual ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11977
|
+
SortStateControl,
|
|
11978
|
+
{
|
|
11979
|
+
...handOrderSortState({
|
|
11980
|
+
sortName: columnSort ? columnLabel(toolbarFields ?? [], columnSort.id) : null,
|
|
11981
|
+
direction: columnSort?.direction ?? null,
|
|
11982
|
+
onBack: () => setQuery((held) => ({ ...held, sort: null, page: 1 })),
|
|
11983
|
+
...viewOrder?.onUseSort && columnSort ? {
|
|
11984
|
+
onUseSort: () => {
|
|
11985
|
+
const sort = columnSort;
|
|
11986
|
+
const chosen = { field: sort.id, direction: sort.direction };
|
|
11987
|
+
setHeldOrder({ order: "sorted", sorts: [chosen] });
|
|
11988
|
+
viewOrder.onUseSort?.(chosen);
|
|
11989
|
+
host.notify?.success(
|
|
11990
|
+
`Sorted by ${columnLabel(toolbarFields ?? [], sort.id)} ${sortArrow(sort.direction)}. ${MANUAL_SORT.replacedToast}`
|
|
11991
|
+
);
|
|
11992
|
+
}
|
|
11993
|
+
} : {}
|
|
11994
|
+
})
|
|
11995
|
+
}
|
|
11996
|
+
) : null,
|
|
11997
|
+
viewId && viewOrder?.onPlaced && hasSeveralRows ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system35.Button, { size: "sm", variant: "ghost", onClick: () => setReordering(true), "data-records-reorder-open": "", children: "Reorder" }) : null,
|
|
11998
|
+
!merged && Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system35.Button, { size: "sm", disabled: editingBusy, onClick: () => void addRecord(), children: editingBusy ? "Adding\u2026" : "New record" }) : null,
|
|
11999
|
+
rights.structure && onAddField ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AddFieldButton, { onClick: onAddField }) : null,
|
|
12000
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
12001
|
+
GridLayoutMenu,
|
|
12002
|
+
{
|
|
12003
|
+
look,
|
|
12004
|
+
firstColumn: sortedKeys[0] ? {
|
|
12005
|
+
key: sortedKeys[0],
|
|
12006
|
+
name: (() => {
|
|
12007
|
+
const first = (toolbarFields ?? []).find((f) => f.key === sortedKeys[0]);
|
|
12008
|
+
return first ? fieldName(first) : humanize(sortedKeys[0]);
|
|
12009
|
+
})()
|
|
12010
|
+
} : null,
|
|
12011
|
+
onChange: changeLayout,
|
|
12012
|
+
kept: Boolean(onPresentationChange)
|
|
12013
|
+
}
|
|
12014
|
+
)
|
|
12015
|
+
] }),
|
|
12016
|
+
...merged ? {
|
|
12017
|
+
overflow: {
|
|
12018
|
+
mode: phone ? "sheet" : toolbarFold2 >= 3 ? "menu" : "inline",
|
|
12019
|
+
pinned: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
12020
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(UndoRedoLive, { source: undoSource }),
|
|
12021
|
+
Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system35.Button, { size: "sm", className: "shrink-0", disabled: added.busy, onClick: () => addRowRef.current(), children: added.busy ? "Adding\u2026" : "New record" }) : null
|
|
12022
|
+
] }),
|
|
12023
|
+
...phone ? {
|
|
12024
|
+
sheetTop: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-col gap-1.5 pb-1", "data-records-grid-sheet-top": "", "data-matrx-table-tools-keep-open": "", children: [
|
|
12025
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
12026
|
+
"input",
|
|
12027
|
+
{
|
|
12028
|
+
type: "search",
|
|
12029
|
+
value: query.search,
|
|
12030
|
+
placeholder: "Search",
|
|
12031
|
+
"aria-label": "Search records",
|
|
12032
|
+
onChange: (event) => {
|
|
12033
|
+
const search = event.target.value;
|
|
12034
|
+
setQuery((held) => ({ ...held, search, page: 1 }));
|
|
12035
|
+
},
|
|
12036
|
+
className: "h-10 w-full min-w-0 rounded-md border border-input bg-background px-2 text-foreground placeholder:text-muted-foreground",
|
|
12037
|
+
style: { fontSize: "16px" }
|
|
12038
|
+
}
|
|
12039
|
+
),
|
|
12040
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("label", { className: "flex items-center gap-2 text-xs text-muted-foreground", "data-records-grid-sheet-sort": "", children: [
|
|
12041
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "shrink-0", children: "Sort by" }),
|
|
12042
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
12043
|
+
"select",
|
|
12044
|
+
{
|
|
12045
|
+
"aria-label": "Sort by",
|
|
12046
|
+
value: query.sort ? `${query.sort.id}:${query.sort.direction}` : "",
|
|
12047
|
+
onChange: (event) => {
|
|
12048
|
+
const [id, direction] = event.target.value.split(":");
|
|
12049
|
+
setQuery((held) => ({
|
|
12050
|
+
...held,
|
|
12051
|
+
page: 1,
|
|
12052
|
+
sort: id ? { id, direction: direction === "desc" ? "desc" : "asc" } : null
|
|
12053
|
+
}));
|
|
12054
|
+
},
|
|
12055
|
+
className: "h-10 min-w-0 flex-1 rounded-md border border-input bg-background px-2 text-foreground",
|
|
12056
|
+
style: { fontSize: "16px" },
|
|
12057
|
+
children: [
|
|
12058
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "No sort" }),
|
|
12059
|
+
ordered.flatMap((field2) => [
|
|
12060
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: `${field2.key}:asc`, children: `${fieldName(field2)} \u2191` }, `${field2.key}:asc`),
|
|
12061
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: `${field2.key}:desc`, children: `${fieldName(field2)} \u2193` }, `${field2.key}:desc`)
|
|
12062
|
+
])
|
|
12063
|
+
]
|
|
12064
|
+
}
|
|
12065
|
+
)
|
|
12066
|
+
] }),
|
|
12067
|
+
phoneSheetTools
|
|
12068
|
+
] }),
|
|
12069
|
+
...sheetExtras ? { sheetExtras } : {}
|
|
12070
|
+
} : {}
|
|
12071
|
+
}
|
|
12072
|
+
} : {}
|
|
12073
|
+
}),
|
|
12074
|
+
[
|
|
12075
|
+
merged,
|
|
12076
|
+
phone,
|
|
12077
|
+
query.search,
|
|
12078
|
+
query.sort,
|
|
12079
|
+
toolbarSlot,
|
|
12080
|
+
manual,
|
|
12081
|
+
columnSort,
|
|
12082
|
+
toolbarFields,
|
|
12083
|
+
viewOrder,
|
|
12084
|
+
host,
|
|
12085
|
+
viewId,
|
|
12086
|
+
hasSeveralRows,
|
|
12087
|
+
editable,
|
|
12088
|
+
rights.write,
|
|
12089
|
+
rights.structure,
|
|
12090
|
+
editingBusy,
|
|
12091
|
+
addRecord,
|
|
12092
|
+
onAddField,
|
|
12093
|
+
look,
|
|
12094
|
+
sortedKeys,
|
|
12095
|
+
changeLayout,
|
|
12096
|
+
onPresentationChange,
|
|
12097
|
+
toolbarFold2,
|
|
12098
|
+
undoSource,
|
|
12099
|
+
added.busy,
|
|
12100
|
+
ordered,
|
|
12101
|
+
phoneSheetTools,
|
|
12102
|
+
sheetExtras
|
|
12103
|
+
]
|
|
12104
|
+
);
|
|
11643
12105
|
const labelOfField = (0, import_react60.useCallback)(
|
|
11644
12106
|
(key) => {
|
|
11645
12107
|
const held = (fields.data ?? []).find((f) => f.key === key);
|
|
@@ -11800,46 +12262,27 @@ function Grid({
|
|
|
11800
12262
|
...fills ? { className: "min-h-0 flex-1" } : {},
|
|
11801
12263
|
data: rows,
|
|
11802
12264
|
columns,
|
|
11803
|
-
getRowId:
|
|
12265
|
+
getRowId: rowIdOf,
|
|
12266
|
+
rowVersion,
|
|
11804
12267
|
isLoading: nothingToShowYet,
|
|
11805
12268
|
isFetching: refreshing,
|
|
11806
12269
|
density: host.density ?? "condensed",
|
|
11807
12270
|
viewTabs: false,
|
|
11808
12271
|
stickyHeader: true,
|
|
11809
12272
|
pageSize,
|
|
11810
|
-
query:
|
|
11811
|
-
// THE STORE ANSWERS THE QUERY (tranche 6k): `data` is already the page.
|
|
11812
|
-
mode: "controlled",
|
|
11813
|
-
state: query,
|
|
11814
|
-
totalItems: records.data?.total ?? rows.length,
|
|
11815
|
-
onStateChange: setQuery,
|
|
11816
|
-
sourceProcessing: { search: "source", columnFilters: "source", sort: "source" }
|
|
11817
|
-
} : { mode: "controlled-local", state: query, onStateChange: setQuery },
|
|
12273
|
+
query: tableQuery,
|
|
11818
12274
|
tableClassName: (0, import_design_system35.cn)(
|
|
11819
12275
|
!look.wrap && "[&_tbody_td]:max-w-[28rem] [&_tbody_td]:overflow-hidden [&_tbody_td]:text-ellipsis [&_tbody_td]:whitespace-nowrap! [&_tbody_td_*]:whitespace-nowrap!",
|
|
11820
12276
|
look.fit === "scroll" && "sm:[&>table]:w-max! sm:[&>table]:max-w-none! sm:[&>table]:min-w-full!"
|
|
11821
12277
|
),
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
...mayAddRow && rows.length > 0 ? [ADD_ROW] : [],
|
|
11825
|
-
...rows.length > 0 && (!merged || Object.keys(chosenSummaries).length > 0) ? [SUMMARY_ROW] : []
|
|
11826
|
-
];
|
|
11827
|
-
return footerRows.length > 0 ? { footerRows } : {};
|
|
11828
|
-
})(),
|
|
11829
|
-
...table.data ? {
|
|
11830
|
-
copy: gridCopyConfig({
|
|
11831
|
-
tableId,
|
|
11832
|
-
tableName: tableName(table.data),
|
|
11833
|
-
fields: ordered,
|
|
11834
|
-
rowLabel: (row) => recordNameIn(table.data, row.document ?? {})
|
|
11835
|
-
})
|
|
11836
|
-
} : {},
|
|
12278
|
+
footerRows,
|
|
12279
|
+
...copyConfig ? { copy: copyConfig } : {},
|
|
11837
12280
|
...offerSelection ? {
|
|
11838
12281
|
selection: {
|
|
11839
12282
|
selectedIds,
|
|
11840
12283
|
onSelectedIdsChange: setSelectedIds,
|
|
11841
12284
|
noun,
|
|
11842
|
-
isRowSelectable
|
|
12285
|
+
isRowSelectable,
|
|
11843
12286
|
actions: (_selected, ids) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
11844
12287
|
merged ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11845
12288
|
BulkActions,
|
|
@@ -11866,154 +12309,18 @@ function Grid({
|
|
|
11866
12309
|
] })
|
|
11867
12310
|
}
|
|
11868
12311
|
} : {},
|
|
11869
|
-
detail:
|
|
11870
|
-
window:
|
|
12312
|
+
detail: DETAIL_OFF,
|
|
12313
|
+
window: WINDOW_OFF,
|
|
11871
12314
|
...controls.contextMenu ? { contextMenu: controls.contextMenu } : {},
|
|
11872
|
-
|
|
11873
|
-
spreadsheet: {
|
|
11874
|
-
enabled: true,
|
|
11875
|
-
writableColumnIds: pasteableKeys,
|
|
11876
|
-
onPatch: (patches, intent) => {
|
|
11877
|
-
if (merged) {
|
|
11878
|
-
void writeRange(patches, intent);
|
|
11879
|
-
return;
|
|
11880
|
-
}
|
|
11881
|
-
for (const patch of patches) {
|
|
11882
|
-
editing.setCell(patch.rowId, patch.columnId, patch.value);
|
|
11883
|
-
}
|
|
11884
|
-
},
|
|
11885
|
-
...merged ? { undoDepth: 0, onSelectionChange: followSelection, controllerRef: sheetController } : {},
|
|
11886
|
-
columnRefusal: (columnId) => {
|
|
11887
|
-
const field2 = (fields.data ?? []).find((f) => f.key === columnId);
|
|
11888
|
-
if (!field2) return `This table has no column called ${columnId}.`;
|
|
11889
|
-
return `${fieldName(field2)} cannot take a pasted value \u2014 ${fieldTypeLabel(field2)} is worked out or chosen, not typed.`;
|
|
11890
|
-
},
|
|
11891
|
-
validateCell: ({ columnId, value }) => {
|
|
11892
|
-
const field2 = (fields.data ?? []).find((f) => f.key === columnId);
|
|
11893
|
-
if (!field2) return `This table has no column called ${columnId}.`;
|
|
11894
|
-
const judged = valueFromPastedText(field2, value === null ? "" : String(value));
|
|
11895
|
-
return "refusal" in judged ? judged.refusal : void 0;
|
|
11896
|
-
},
|
|
11897
|
-
onPastePlan: receivePastePlan,
|
|
11898
|
-
/*
|
|
11899
|
-
* TYPE-TO-EDIT (design-system 0.43 `onEditRequest`): the cell a person is on
|
|
11900
|
-
* opens ITS OWN editor — the Field's — holding what they typed (a letter, an
|
|
11901
|
-
* IME composition, an Option/AltGr character, dictation). A worked-out column
|
|
11902
|
-
* or a row this person may not write answers false, so nothing is swallowed.
|
|
11903
|
-
*/
|
|
11904
|
-
onEditRequest: (address, seed) => {
|
|
11905
|
-
const field2 = (fields.data ?? []).find((f) => f.key === address.columnId);
|
|
11906
|
-
if (!field2 || !fieldIsEditable(field2) || !mayWriteRow(address.rowId)) return false;
|
|
11907
|
-
if (seed !== null && seed !== "" && typingOpens(field2) === "none") return false;
|
|
11908
|
-
editing.begin({ rowId: address.rowId, key: field2.key }, seed);
|
|
11909
|
-
return true;
|
|
11910
|
-
},
|
|
11911
|
-
...host.notify ? { notify: (message) => host.notify?.success(message) } : {}
|
|
11912
|
-
}
|
|
11913
|
-
} : {
|
|
11914
|
-
/*
|
|
11915
|
-
* RANGE SELECTION AND COPY FOR A READER (merge step 3, 0.42 `readOnly`). A person
|
|
11916
|
-
* who may not change this table may still drag out a range, select all and press
|
|
11917
|
-
* Cmd-C for a real Excel/Sheets block — the UX walk graded range selection BROKEN
|
|
11918
|
-
* on a table whose writes were refused. Every write gesture (cut, paste, clear,
|
|
11919
|
-
* fill, undo) says why it cannot, in the store's own words.
|
|
11920
|
-
*/
|
|
11921
|
-
spreadsheet: {
|
|
11922
|
-
enabled: true,
|
|
11923
|
-
readOnly: true,
|
|
11924
|
-
...merged ? { onSelectionChange: followSelection, controllerRef: sheetController } : {},
|
|
11925
|
-
readOnlyReason: !editable || !rights.known || rights.write ? "Editing is off here, so this table can be copied but not changed." : rights.why("write")
|
|
11926
|
-
}
|
|
11927
|
-
},
|
|
12315
|
+
spreadsheet: spreadsheetConfig,
|
|
11928
12316
|
...groupingConfig ? { grouping: groupingConfig } : {},
|
|
11929
12317
|
columnState,
|
|
11930
12318
|
...look.rowHeight ? { rowHeight: look.rowHeight } : {},
|
|
11931
|
-
virtualize: fills ?
|
|
11932
|
-
coverage:
|
|
11933
|
-
|
|
11934
|
-
...merged && typeof records.data?.total === "number" ? { matched: records.data.total } : {},
|
|
11935
|
-
noun: "record",
|
|
11936
|
-
...typeof records.data?.total === "number" ? { total: records.data.total } : {}
|
|
11937
|
-
},
|
|
11938
|
-
...!(0, import_data_table9.tableStyleIsEmpty)(paint.style) ? {
|
|
11939
|
-
tableStyle: {
|
|
11940
|
-
style: paint.style,
|
|
11941
|
-
// A choice is read as its OPTION (`paintByOption`): the rule, the value and the
|
|
11942
|
-
// colour a column keeps for it all name the same option, however it is stored.
|
|
11943
|
-
documentOf: (row) => paint.documentOf(row.document ?? {}),
|
|
11944
|
-
// A value its column keeps a colour for wears THAT colour (`choiceLooks.ts`);
|
|
11945
|
-
// any other value still paints from its word.
|
|
11946
|
-
choiceColorFor: paint.choiceColorFor
|
|
11947
|
-
}
|
|
11948
|
-
} : {},
|
|
12319
|
+
virtualize: fills ? VIRTUALIZE_FILLED : true,
|
|
12320
|
+
coverage: tableCoverage,
|
|
12321
|
+
...tableStyleProp ? { tableStyle: tableStyleProp } : {},
|
|
11949
12322
|
...onOpenRecord ? { onRowOpen: (row) => onOpenRecord(row.id) } : {},
|
|
11950
|
-
...
|
|
11951
|
-
// ABSENT, NEVER DEAD: a row this person may not delete carries no
|
|
11952
|
-
// Delete at all, rather than one that refuses when pressed — and a
|
|
11953
|
-
// deployment with no chat surface bound carries no Talk.
|
|
11954
|
-
rowActions: (row) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
11955
|
-
canWrite && mayWriteRow(row.id) ? tableActions.runnable.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11956
|
-
ActionButton,
|
|
11957
|
-
{
|
|
11958
|
-
action,
|
|
11959
|
-
busy: runner.busy === action.id,
|
|
11960
|
-
onPress: () => runner.press(action, [row.id])
|
|
11961
|
-
},
|
|
11962
|
-
action.id
|
|
11963
|
-
)) : null,
|
|
11964
|
-
host.runAgentAction ? tableActions.agent.map((action) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11965
|
-
ActionButton,
|
|
11966
|
-
{
|
|
11967
|
-
action,
|
|
11968
|
-
busy: false,
|
|
11969
|
-
onPress: () => handToAgent(action, row)
|
|
11970
|
-
},
|
|
11971
|
-
action.id
|
|
11972
|
-
)) : null,
|
|
11973
|
-
host.talkToRecord ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11974
|
-
import_design_system35.Button,
|
|
11975
|
-
{
|
|
11976
|
-
size: "sm",
|
|
11977
|
-
variant: "ghost",
|
|
11978
|
-
onClick: () => host.talkToRecord?.({
|
|
11979
|
-
tableId,
|
|
11980
|
-
recordId: row.id,
|
|
11981
|
-
// ONE NAMING CALL (`names.ts`), not this file's own join
|
|
11982
|
-
// of a Table's title column to a document.
|
|
11983
|
-
title: recordNameIn(
|
|
11984
|
-
table.data,
|
|
11985
|
-
row.document ?? {}
|
|
11986
|
-
)
|
|
11987
|
-
}),
|
|
11988
|
-
children: "Talk"
|
|
11989
|
-
}
|
|
11990
|
-
) : null,
|
|
11991
|
-
Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11992
|
-
import_design_system35.Button,
|
|
11993
|
-
{
|
|
11994
|
-
size: "sm",
|
|
11995
|
-
variant: "ghost",
|
|
11996
|
-
"data-records-duplicate": row.id,
|
|
11997
|
-
title: "Duplicate this record",
|
|
11998
|
-
onClick: (event) => {
|
|
11999
|
-
event.stopPropagation();
|
|
12000
|
-
void duplicate(row);
|
|
12001
|
-
},
|
|
12002
|
-
children: "Duplicate"
|
|
12003
|
-
}
|
|
12004
|
-
) : null,
|
|
12005
|
-
canWrite && mayWriteRow(row.id) ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
12006
|
-
import_design_system35.Button,
|
|
12007
|
-
{
|
|
12008
|
-
size: "sm",
|
|
12009
|
-
variant: "ghost",
|
|
12010
|
-
title: "Delete this record",
|
|
12011
|
-
onClick: () => setDeleting(row),
|
|
12012
|
-
children: "Delete"
|
|
12013
|
-
}
|
|
12014
|
-
) : null
|
|
12015
|
-
] })
|
|
12016
|
-
} : {},
|
|
12323
|
+
...offersRowActions ? { rowActions } : {},
|
|
12017
12324
|
emptyState: emptyWords({
|
|
12018
12325
|
error: records.error,
|
|
12019
12326
|
asked: questionIsAsked({ search: query.search, columnFilters: query.columnFilters, filter }),
|
|
@@ -12022,142 +12329,7 @@ function Grid({
|
|
|
12022
12329
|
...mayAddRow ? { addFirst: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AddFirstRowButton, { onAdd: () => void addRowHere(), busy: added.busy }) } : {},
|
|
12023
12330
|
emptyDescription: rights.write ? "Add the first one and it appears here." : rights.known ? `Nothing has been written to this table. ${rights.why("write")}` : "Nothing has been written to this table."
|
|
12024
12331
|
}),
|
|
12025
|
-
toolbar:
|
|
12026
|
-
search: true,
|
|
12027
|
-
searchPlaceholder: "Search records",
|
|
12028
|
-
/*
|
|
12029
|
-
* A PHONE (tranche 6o): search and the one Tools button sit side by side at the START of
|
|
12030
|
-
* the row, so Tools is never scrolled out of reach; the search is the same query.
|
|
12031
|
-
*/
|
|
12032
|
-
...merged && phone ? {
|
|
12033
|
-
customSearch: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "flex min-w-0 flex-1 items-center gap-1.5", "data-records-grid-phone-search": "", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
12034
|
-
"input",
|
|
12035
|
-
{
|
|
12036
|
-
type: "search",
|
|
12037
|
-
value: query.search,
|
|
12038
|
-
placeholder: "Search",
|
|
12039
|
-
"aria-label": "Search records",
|
|
12040
|
-
onChange: (event) => {
|
|
12041
|
-
const search = event.target.value;
|
|
12042
|
-
setQuery((held) => ({ ...held, search, page: 1 }));
|
|
12043
|
-
},
|
|
12044
|
-
className: "h-8 w-full min-w-0 rounded-md border border-input bg-background px-2 text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
12045
|
-
style: { fontSize: "16px" }
|
|
12046
|
-
}
|
|
12047
|
-
) })
|
|
12048
|
-
} : {},
|
|
12049
|
-
/* ONE ROW (lane TABLE-PAGE-CHROME): on a table page the grid's search, columns and
|
|
12050
|
-
sort are drawn INTO the page's toolbar row, never a second bar under it. */
|
|
12051
|
-
...toolbarSlot !== void 0 ? { portalInto: toolbarSlot, singleRow: true } : {},
|
|
12052
|
-
// SCR-2 / SCR-4: PRESENT for an admin, ABSENT for everyone else.
|
|
12053
|
-
// There is no third state: this package ships no disabled variant of
|
|
12054
|
-
// these controls, so a member cannot be shown a dead one by mistake.
|
|
12055
|
-
/*
|
|
12056
|
-
* WHERE THE GRID'S CONTROLS GO (lane C, review 2026-09-26 D6). Inline when the row has
|
|
12057
|
-
* room; behind the row's "…" once the page row is folded that far (Undo / Redo and New
|
|
12058
|
-
* record stay beside it — the primary action is never folded); on a phone EVERY control
|
|
12059
|
-
* — the table's own (clear, copy/export, group, columns), these, the search, the sort and
|
|
12060
|
-
* the page's filter, layout and share — in ONE "Tools" sheet. Never dropped.
|
|
12061
|
-
*/
|
|
12062
|
-
actions: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
12063
|
-
manual ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
12064
|
-
SortStateControl,
|
|
12065
|
-
{
|
|
12066
|
-
...handOrderSortState({
|
|
12067
|
-
sortName: columnSort ? columnLabel(fields.data ?? [], columnSort.id) : null,
|
|
12068
|
-
direction: columnSort?.direction ?? null,
|
|
12069
|
-
onBack: () => setQuery((held) => ({ ...held, sort: null, page: 1 })),
|
|
12070
|
-
...viewOrder?.onUseSort && columnSort ? {
|
|
12071
|
-
onUseSort: () => {
|
|
12072
|
-
const sort = columnSort;
|
|
12073
|
-
const chosen = { field: sort.id, direction: sort.direction };
|
|
12074
|
-
setHeldOrder({ order: "sorted", sorts: [chosen] });
|
|
12075
|
-
viewOrder.onUseSort?.(chosen);
|
|
12076
|
-
host.notify?.success(
|
|
12077
|
-
`Sorted by ${columnLabel(fields.data ?? [], sort.id)} ${sortArrow(sort.direction)}. ${MANUAL_SORT.replacedToast}`
|
|
12078
|
-
);
|
|
12079
|
-
}
|
|
12080
|
-
} : {}
|
|
12081
|
-
})
|
|
12082
|
-
}
|
|
12083
|
-
) : null,
|
|
12084
|
-
viewId && viewOrder?.onPlaced && rows.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system35.Button, { size: "sm", variant: "ghost", onClick: () => setReordering(true), "data-records-reorder-open": "", children: "Reorder" }) : null,
|
|
12085
|
-
!merged && Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system35.Button, { size: "sm", disabled: editing.busy, onClick: () => void editing.addRecord(), children: editing.busy ? "Adding\u2026" : "New record" }) : null,
|
|
12086
|
-
rights.structure && onAddField ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AddFieldButton, { onClick: onAddField }) : null,
|
|
12087
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
12088
|
-
GridLayoutMenu,
|
|
12089
|
-
{
|
|
12090
|
-
look,
|
|
12091
|
-
firstColumn: sortedKeys[0] ? {
|
|
12092
|
-
key: sortedKeys[0],
|
|
12093
|
-
name: (() => {
|
|
12094
|
-
const first = (fields.data ?? []).find((f) => f.key === sortedKeys[0]);
|
|
12095
|
-
return first ? fieldName(first) : humanize(sortedKeys[0]);
|
|
12096
|
-
})()
|
|
12097
|
-
} : null,
|
|
12098
|
-
onChange: changeLayout,
|
|
12099
|
-
kept: Boolean(onPresentationChange)
|
|
12100
|
-
}
|
|
12101
|
-
)
|
|
12102
|
-
] }),
|
|
12103
|
-
...merged ? {
|
|
12104
|
-
overflow: {
|
|
12105
|
-
mode: phone ? "sheet" : toolbarFold2 >= 3 ? "menu" : "inline",
|
|
12106
|
-
pinned: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
12107
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(UndoRedoButtons, { undo }),
|
|
12108
|
-
Boolean(editable) && rights.write ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system35.Button, { size: "sm", className: "shrink-0", disabled: added.busy, onClick: () => void addRowHere(), children: added.busy ? "Adding\u2026" : "New record" }) : null
|
|
12109
|
-
] }),
|
|
12110
|
-
...phone ? {
|
|
12111
|
-
sheetTop: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-col gap-1.5 pb-1", "data-records-grid-sheet-top": "", "data-matrx-table-tools-keep-open": "", children: [
|
|
12112
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
12113
|
-
"input",
|
|
12114
|
-
{
|
|
12115
|
-
type: "search",
|
|
12116
|
-
value: query.search,
|
|
12117
|
-
placeholder: "Search",
|
|
12118
|
-
"aria-label": "Search records",
|
|
12119
|
-
onChange: (event) => {
|
|
12120
|
-
const search = event.target.value;
|
|
12121
|
-
setQuery((held) => ({ ...held, search, page: 1 }));
|
|
12122
|
-
},
|
|
12123
|
-
className: "h-10 w-full min-w-0 rounded-md border border-input bg-background px-2 text-foreground placeholder:text-muted-foreground",
|
|
12124
|
-
style: { fontSize: "16px" }
|
|
12125
|
-
}
|
|
12126
|
-
),
|
|
12127
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("label", { className: "flex items-center gap-2 text-xs text-muted-foreground", "data-records-grid-sheet-sort": "", children: [
|
|
12128
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "shrink-0", children: "Sort by" }),
|
|
12129
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
12130
|
-
"select",
|
|
12131
|
-
{
|
|
12132
|
-
"aria-label": "Sort by",
|
|
12133
|
-
value: query.sort ? `${query.sort.id}:${query.sort.direction}` : "",
|
|
12134
|
-
onChange: (event) => {
|
|
12135
|
-
const [id, direction] = event.target.value.split(":");
|
|
12136
|
-
setQuery((held) => ({
|
|
12137
|
-
...held,
|
|
12138
|
-
page: 1,
|
|
12139
|
-
sort: id ? { id, direction: direction === "desc" ? "desc" : "asc" } : null
|
|
12140
|
-
}));
|
|
12141
|
-
},
|
|
12142
|
-
className: "h-10 min-w-0 flex-1 rounded-md border border-input bg-background px-2 text-foreground",
|
|
12143
|
-
style: { fontSize: "16px" },
|
|
12144
|
-
children: [
|
|
12145
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "No sort" }),
|
|
12146
|
-
ordered.flatMap((field2) => [
|
|
12147
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: `${field2.key}:asc`, children: `${fieldName(field2)} \u2191` }, `${field2.key}:asc`),
|
|
12148
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: `${field2.key}:desc`, children: `${fieldName(field2)} \u2193` }, `${field2.key}:desc`)
|
|
12149
|
-
])
|
|
12150
|
-
]
|
|
12151
|
-
}
|
|
12152
|
-
)
|
|
12153
|
-
] }),
|
|
12154
|
-
controls.sheetTools
|
|
12155
|
-
] }),
|
|
12156
|
-
...sheetExtras ? { sheetExtras } : {}
|
|
12157
|
-
} : {}
|
|
12158
|
-
}
|
|
12159
|
-
} : {}
|
|
12160
|
-
}
|
|
12332
|
+
toolbar: tableToolbar
|
|
12161
12333
|
},
|
|
12162
12334
|
`records-grid-${tableId}:${openingKey}`
|
|
12163
12335
|
)
|
|
@@ -12259,6 +12431,58 @@ function Grid({
|
|
|
12259
12431
|
}
|
|
12260
12432
|
) });
|
|
12261
12433
|
}
|
|
12434
|
+
var DETAIL_OFF = { enabled: false };
|
|
12435
|
+
var WINDOW_OFF = { enabled: false };
|
|
12436
|
+
var VIRTUALIZE_FILLED = { threshold: 40 };
|
|
12437
|
+
function menuFace(items) {
|
|
12438
|
+
return JSON.stringify(items, (_key, value) => typeof value === "function" ? "\u0192" : value);
|
|
12439
|
+
}
|
|
12440
|
+
function menuThroughLatest(items, at, latest) {
|
|
12441
|
+
return items.map((item) => {
|
|
12442
|
+
const path = `${at}/${item.id}`;
|
|
12443
|
+
return {
|
|
12444
|
+
...item,
|
|
12445
|
+
...item.onSelect ? { onSelect: () => latest.get(path)?.() } : {},
|
|
12446
|
+
...item.submenu ? { submenu: menuThroughLatest(item.submenu, path, latest) } : {}
|
|
12447
|
+
};
|
|
12448
|
+
});
|
|
12449
|
+
}
|
|
12450
|
+
function bindLatest(items, at, latest) {
|
|
12451
|
+
for (const item of items) {
|
|
12452
|
+
const path = `${at}/${item.id}`;
|
|
12453
|
+
if (item.onSelect) latest.set(path, item.onSelect);
|
|
12454
|
+
if (item.submenu) bindLatest(item.submenu, path, latest);
|
|
12455
|
+
}
|
|
12456
|
+
}
|
|
12457
|
+
function holdHeaderMenu(held, latest, key, items) {
|
|
12458
|
+
if (!items) return items;
|
|
12459
|
+
const at = `menu:${key}`;
|
|
12460
|
+
bindLatest(items, at, latest);
|
|
12461
|
+
const sig = menuFace(items);
|
|
12462
|
+
const was = held.get(at);
|
|
12463
|
+
if (was && was.sig === sig) return was.value;
|
|
12464
|
+
const value = menuThroughLatest(items, at, latest);
|
|
12465
|
+
held.set(at, { sig, value });
|
|
12466
|
+
return value;
|
|
12467
|
+
}
|
|
12468
|
+
function holdByContent(held, at, value) {
|
|
12469
|
+
if (value === void 0) return value;
|
|
12470
|
+
const sig = JSON.stringify(value);
|
|
12471
|
+
const was = held.get(at);
|
|
12472
|
+
if (was && was.sig === sig) return was.value;
|
|
12473
|
+
held.set(at, { sig, value });
|
|
12474
|
+
return value;
|
|
12475
|
+
}
|
|
12476
|
+
function sameColumns(a, b) {
|
|
12477
|
+
if (a === b) return true;
|
|
12478
|
+
if (a.length !== b.length) return false;
|
|
12479
|
+
return a.every((column, i) => {
|
|
12480
|
+
const other = b[i];
|
|
12481
|
+
if (column === other) return true;
|
|
12482
|
+
const keys = Object.keys(column);
|
|
12483
|
+
return keys.length === Object.keys(other).length && keys.every((key) => Object.is(column[key], other[key]));
|
|
12484
|
+
});
|
|
12485
|
+
}
|
|
12262
12486
|
function withHeaderMenus(columns, menuFor, filterFor) {
|
|
12263
12487
|
return columns.map((column) => {
|
|
12264
12488
|
const items = menuFor(String(column.id));
|
|
@@ -26512,7 +26736,8 @@ function useEmbedHandshake(args) {
|
|
|
26512
26736
|
}
|
|
26513
26737
|
|
|
26514
26738
|
// src/RecordsMount.tsx
|
|
26515
|
-
var import_react160 = require("
|
|
26739
|
+
var import_react160 = require("react");
|
|
26740
|
+
var import_react161 = require("@ai-matrx/records/react");
|
|
26516
26741
|
var import_jsx_runtime91 = require("react/jsx-runtime");
|
|
26517
26742
|
var STORE_DECIDES_REASON = "This host offers exactly what the record store says this person may do: the level comes back with the table on the read door, so a control they cannot use is never drawn in the first place.";
|
|
26518
26743
|
function storeDecidesRights(_table) {
|
|
@@ -26524,9 +26749,25 @@ function RecordsMount({
|
|
|
26524
26749
|
letTheStoreDecideRights,
|
|
26525
26750
|
children
|
|
26526
26751
|
}) {
|
|
26527
|
-
const bound =
|
|
26752
|
+
const bound = useShallowStableHost(host);
|
|
26528
26753
|
void letTheStoreDecideRights;
|
|
26529
|
-
return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
26754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(import_react161.RecordsProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(RecordsUiProvider, { value: bound, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(RecordLabelProvider, { children }) }) });
|
|
26755
|
+
}
|
|
26756
|
+
function useShallowStableHost(host) {
|
|
26757
|
+
const held = (0, import_react160.useRef)(null);
|
|
26758
|
+
const next = host ?? {};
|
|
26759
|
+
const previous = held.current;
|
|
26760
|
+
if (previous !== null && sameParts(previous, next)) return previous;
|
|
26761
|
+
const bound = { ...next };
|
|
26762
|
+
held.current = bound;
|
|
26763
|
+
return bound;
|
|
26764
|
+
}
|
|
26765
|
+
function sameParts(a, b) {
|
|
26766
|
+
const aKeys = Object.keys(a);
|
|
26767
|
+
const bKeys = Object.keys(b);
|
|
26768
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
26769
|
+
for (const key of aKeys) if (a[key] !== b[key]) return false;
|
|
26770
|
+
return true;
|
|
26530
26771
|
}
|
|
26531
26772
|
function personActor(userId) {
|
|
26532
26773
|
return userId ? { actor: "user", user_id: userId } : { actor: "user" };
|
|
@@ -26545,15 +26786,15 @@ function recordsDataSource(client, fallbackSchema = "custom") {
|
|
|
26545
26786
|
}
|
|
26546
26787
|
|
|
26547
26788
|
// src/TablesHome.tsx
|
|
26548
|
-
var
|
|
26549
|
-
var
|
|
26789
|
+
var import_react166 = require("react");
|
|
26790
|
+
var import_react167 = require("@ai-matrx/records/react");
|
|
26550
26791
|
var import_core16 = require("@ai-matrx/records/core");
|
|
26551
26792
|
var import_records29 = require("@ai-matrx/records");
|
|
26552
26793
|
var import_design_system85 = require("@ai-matrx/design-system");
|
|
26553
26794
|
|
|
26554
26795
|
// src/ExampleTables.tsx
|
|
26555
|
-
var
|
|
26556
|
-
var
|
|
26796
|
+
var import_react162 = require("react");
|
|
26797
|
+
var import_react163 = require("@ai-matrx/records/react");
|
|
26557
26798
|
var import_use_cases = require("@ai-matrx/records/use-cases");
|
|
26558
26799
|
var import_design_system83 = require("@ai-matrx/design-system");
|
|
26559
26800
|
var import_jsx_runtime92 = require("react/jsx-runtime");
|
|
@@ -26562,12 +26803,12 @@ function ExampleTables({
|
|
|
26562
26803
|
onClose,
|
|
26563
26804
|
className
|
|
26564
26805
|
}) {
|
|
26565
|
-
const client = (0,
|
|
26566
|
-
const [summaries, setSummaries] = (0,
|
|
26567
|
-
const [busy, setBusy] = (0,
|
|
26568
|
-
const [error, setError] = (0,
|
|
26569
|
-
const [built, setBuilt] = (0,
|
|
26570
|
-
(0,
|
|
26806
|
+
const client = (0, import_react163.useRecordsClient)();
|
|
26807
|
+
const [summaries, setSummaries] = (0, import_react162.useState)(null);
|
|
26808
|
+
const [busy, setBusy] = (0, import_react162.useState)(null);
|
|
26809
|
+
const [error, setError] = (0, import_react162.useState)(null);
|
|
26810
|
+
const [built, setBuilt] = (0, import_react162.useState)(null);
|
|
26811
|
+
(0, import_react162.useEffect)(() => {
|
|
26571
26812
|
let alive = true;
|
|
26572
26813
|
void Promise.all((0, import_use_cases.useCaseIds)().map(async (id) => (0, import_use_cases.summarize)(await (0, import_use_cases.loadUseCase)(id)))).then((rows) => {
|
|
26573
26814
|
if (alive) setSummaries(rows);
|
|
@@ -26645,22 +26886,22 @@ function ExampleTables({
|
|
|
26645
26886
|
var import_core15 = require("@ai-matrx/records/core");
|
|
26646
26887
|
|
|
26647
26888
|
// src/WhereItLives.tsx
|
|
26648
|
-
var
|
|
26889
|
+
var import_react164 = require("react");
|
|
26649
26890
|
var import_records28 = require("@ai-matrx/records");
|
|
26650
|
-
var
|
|
26891
|
+
var import_react165 = require("@ai-matrx/records/react");
|
|
26651
26892
|
var import_design_system84 = require("@ai-matrx/design-system");
|
|
26652
26893
|
var import_jsx_runtime93 = require("react/jsx-runtime");
|
|
26653
26894
|
function WhereItLives({ tableId, knownOrganizationName, onMoved, variant = "header" }) {
|
|
26654
|
-
const client = (0,
|
|
26895
|
+
const client = (0, import_react165.useRecordsClient)();
|
|
26655
26896
|
const host = useRecordsUi();
|
|
26656
|
-
const [answer, setAnswer] = (0,
|
|
26657
|
-
const [attempt, setAttempt] = (0,
|
|
26658
|
-
const [open, setOpen] = (0,
|
|
26659
|
-
const [armed, setArmed] = (0,
|
|
26660
|
-
const [choosing, setChoosing] = (0,
|
|
26661
|
-
const [moving, setMoving] = (0,
|
|
26662
|
-
const [said, setSaid] = (0,
|
|
26663
|
-
(0,
|
|
26897
|
+
const [answer, setAnswer] = (0, import_react164.useState)(null);
|
|
26898
|
+
const [attempt, setAttempt] = (0, import_react164.useState)(0);
|
|
26899
|
+
const [open, setOpen] = (0, import_react164.useState)(false);
|
|
26900
|
+
const [armed, setArmed] = (0, import_react164.useState)(variant !== "row" || !knownOrganizationName);
|
|
26901
|
+
const [choosing, setChoosing] = (0, import_react164.useState)(null);
|
|
26902
|
+
const [moving, setMoving] = (0, import_react164.useState)(false);
|
|
26903
|
+
const [said, setSaid] = (0, import_react164.useState)(null);
|
|
26904
|
+
(0, import_react164.useEffect)(() => {
|
|
26664
26905
|
if (!armed) return;
|
|
26665
26906
|
let alive = true;
|
|
26666
26907
|
setAnswer(null);
|
|
@@ -26906,11 +27147,11 @@ function visibilityLaneFor(table) {
|
|
|
26906
27147
|
return "organization";
|
|
26907
27148
|
}
|
|
26908
27149
|
function TablesHome({ onOpenTable, organizationName, makingOnly = false, className }) {
|
|
26909
|
-
const client = (0,
|
|
26910
|
-
const tables = (0,
|
|
27150
|
+
const client = (0, import_react167.useRecordsClient)();
|
|
27151
|
+
const tables = (0, import_react167.useTables)();
|
|
26911
27152
|
const me = client.config.actor.user_id ?? null;
|
|
26912
|
-
const [facts, setFacts] = (0,
|
|
26913
|
-
(0,
|
|
27153
|
+
const [facts, setFacts] = (0, import_react166.useState)({ phase: "reading" });
|
|
27154
|
+
(0, import_react166.useEffect)(() => {
|
|
26914
27155
|
let alive = true;
|
|
26915
27156
|
void client.tableFacts().then((answered) => {
|
|
26916
27157
|
if (!alive) return;
|
|
@@ -26924,11 +27165,11 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
|
|
|
26924
27165
|
(0, import_core16.withTableFacts)(tables.data ?? [], facts.rows, me),
|
|
26925
27166
|
facts.rows
|
|
26926
27167
|
) : tables.data ?? [];
|
|
26927
|
-
const [showEverything, setShowEverything] = (0,
|
|
27168
|
+
const [showEverything, setShowEverything] = (0, import_react166.useState)(false);
|
|
26928
27169
|
const keptCount = listed.filter((t) => laneFor(t) === "app").length;
|
|
26929
|
-
const [askedName, setAskedName] = (0,
|
|
27170
|
+
const [askedName, setAskedName] = (0, import_react166.useState)(null);
|
|
26930
27171
|
const firstTableId = listed[0]?.id ?? null;
|
|
26931
|
-
(0,
|
|
27172
|
+
(0, import_react166.useEffect)(() => {
|
|
26932
27173
|
if (organizationName || !firstTableId) return;
|
|
26933
27174
|
let alive = true;
|
|
26934
27175
|
void client.tableHome({ table_id: firstTableId }).then((answered) => {
|
|
@@ -26941,14 +27182,14 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
|
|
|
26941
27182
|
const livesIn = organizationName || askedName;
|
|
26942
27183
|
const isMine = (t) => Boolean(me) && laneFor(t) !== "system" && laneFor(t) !== "app" && t.created_by === me;
|
|
26943
27184
|
const sectionsKnown = facts.phase !== "failed";
|
|
26944
|
-
const [creating, setCreating] = (0,
|
|
26945
|
-
const [name, setName] = (0,
|
|
26946
|
-
const [busy, setBusy] = (0,
|
|
26947
|
-
const [error, setError] = (0,
|
|
26948
|
-
const [importInto, setImportInto] = (0,
|
|
26949
|
-
const [examples, setExamples] = (0,
|
|
26950
|
-
const [boards, setBoards] = (0,
|
|
26951
|
-
(0,
|
|
27185
|
+
const [creating, setCreating] = (0, import_react166.useState)(false);
|
|
27186
|
+
const [name, setName] = (0, import_react166.useState)("");
|
|
27187
|
+
const [busy, setBusy] = (0, import_react166.useState)(false);
|
|
27188
|
+
const [error, setError] = (0, import_react166.useState)(null);
|
|
27189
|
+
const [importInto, setImportInto] = (0, import_react166.useState)(null);
|
|
27190
|
+
const [examples, setExamples] = (0, import_react166.useState)(false);
|
|
27191
|
+
const [boards, setBoards] = (0, import_react166.useState)(null);
|
|
27192
|
+
(0, import_react166.useEffect)(() => {
|
|
26952
27193
|
if (makingOnly) return;
|
|
26953
27194
|
let cancelled = false;
|
|
26954
27195
|
void client.dashboards({}).then((result) => {
|
|
@@ -26959,7 +27200,7 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
|
|
|
26959
27200
|
cancelled = true;
|
|
26960
27201
|
};
|
|
26961
27202
|
}, [client, makingOnly]);
|
|
26962
|
-
const create = (0,
|
|
27203
|
+
const create = (0, import_react166.useCallback)(
|
|
26963
27204
|
async (mode) => {
|
|
26964
27205
|
const trimmed = name.trim();
|
|
26965
27206
|
if (!trimmed) return;
|
|
@@ -27124,15 +27365,15 @@ function TablesHome({ onOpenTable, organizationName, makingOnly = false, classNa
|
|
|
27124
27365
|
}
|
|
27125
27366
|
|
|
27126
27367
|
// src/TablePage.tsx
|
|
27127
|
-
var
|
|
27368
|
+
var import_react171 = require("react");
|
|
27128
27369
|
var import_records30 = require("@ai-matrx/records");
|
|
27129
|
-
var
|
|
27370
|
+
var import_react172 = require("@ai-matrx/records/react");
|
|
27130
27371
|
var import_design_system87 = require("@ai-matrx/design-system");
|
|
27131
27372
|
|
|
27132
27373
|
// src/ViewFilter.tsx
|
|
27133
|
-
var
|
|
27374
|
+
var import_react168 = require("react");
|
|
27134
27375
|
var import_design_system86 = require("@ai-matrx/design-system");
|
|
27135
|
-
var
|
|
27376
|
+
var import_react169 = require("@ai-matrx/records/react");
|
|
27136
27377
|
var import_jsx_runtime95 = require("react/jsx-runtime");
|
|
27137
27378
|
function conditionCount(expr) {
|
|
27138
27379
|
if (!expr || typeof expr !== "object" || Array.isArray(expr)) return 0;
|
|
@@ -27143,15 +27384,15 @@ function conditionCount(expr) {
|
|
|
27143
27384
|
return 1;
|
|
27144
27385
|
}
|
|
27145
27386
|
function ViewFilter({ tableId, view, onApply, className }) {
|
|
27146
|
-
const fields = (0,
|
|
27147
|
-
const [open, setOpen] = (0,
|
|
27387
|
+
const fields = (0, import_react169.useFields)(tableId);
|
|
27388
|
+
const [open, setOpen] = (0, import_react168.useState)(false);
|
|
27148
27389
|
const saved = view?.where ?? null;
|
|
27149
|
-
const [draft, setDraft] = (0,
|
|
27390
|
+
const [draft, setDraft] = (0, import_react168.useState)(saved);
|
|
27150
27391
|
const savedKey = JSON.stringify(saved);
|
|
27151
|
-
(0,
|
|
27392
|
+
(0, import_react168.useEffect)(() => {
|
|
27152
27393
|
setDraft(saved);
|
|
27153
27394
|
}, [view?.id, savedKey]);
|
|
27154
|
-
const conditionFields = (0,
|
|
27395
|
+
const conditionFields = (0, import_react168.useMemo)(
|
|
27155
27396
|
() => (fields.data ?? []).map((f) => ({ id: f.id, key: f.key, label: f.label || f.key, field: f })),
|
|
27156
27397
|
[fields.data]
|
|
27157
27398
|
);
|
|
@@ -27231,7 +27472,7 @@ function ViewFilter({ tableId, view, onApply, className }) {
|
|
|
27231
27472
|
}
|
|
27232
27473
|
|
|
27233
27474
|
// src/toolbarFit.ts
|
|
27234
|
-
var
|
|
27475
|
+
var import_react170 = require("react");
|
|
27235
27476
|
var FOLDED_GUESS = { look: 104, chooser: 96, tools: 120 };
|
|
27236
27477
|
function toolbarFold(input) {
|
|
27237
27478
|
const { available, needsNow, gap, folded } = input;
|
|
@@ -27282,8 +27523,8 @@ function rowNeeds(row) {
|
|
|
27282
27523
|
return { needs: needs + gap * Math.max(0, pieces.length - 1), gap };
|
|
27283
27524
|
}
|
|
27284
27525
|
function useToolbarFit(row) {
|
|
27285
|
-
const [fold, setFold] = (0,
|
|
27286
|
-
(0,
|
|
27526
|
+
const [fold, setFold] = (0, import_react170.useState)(0);
|
|
27527
|
+
(0, import_react170.useEffect)(() => {
|
|
27287
27528
|
if (!row) return;
|
|
27288
27529
|
const widths = {
|
|
27289
27530
|
look: { full: null, folded: null },
|
|
@@ -27363,8 +27604,8 @@ function clippedEnds(scrollLeft, clientWidth, scrollWidth) {
|
|
|
27363
27604
|
return start && end ? "both" : start ? "start" : end ? "end" : "none";
|
|
27364
27605
|
}
|
|
27365
27606
|
function useSlotScroll(slot) {
|
|
27366
|
-
const [ends, setEnds] = (0,
|
|
27367
|
-
(0,
|
|
27607
|
+
const [ends, setEnds] = (0, import_react170.useState)("none");
|
|
27608
|
+
(0, import_react170.useEffect)(() => {
|
|
27368
27609
|
if (!slot) return;
|
|
27369
27610
|
let pending = 0;
|
|
27370
27611
|
const read = () => {
|
|
@@ -27480,11 +27721,11 @@ function TableNotHere({
|
|
|
27480
27721
|
leaveLabel,
|
|
27481
27722
|
className
|
|
27482
27723
|
}) {
|
|
27483
|
-
const client = (0,
|
|
27484
|
-
const [archived, setArchived] = (0,
|
|
27485
|
-
const [restoring, setRestoring] = (0,
|
|
27486
|
-
const [refusal2, setRefusal] = (0,
|
|
27487
|
-
(0,
|
|
27724
|
+
const client = (0, import_react172.useRecordsClient)();
|
|
27725
|
+
const [archived, setArchived] = (0, import_react171.useState)({ phase: "asking" });
|
|
27726
|
+
const [restoring, setRestoring] = (0, import_react171.useState)(false);
|
|
27727
|
+
const [refusal2, setRefusal] = (0, import_react171.useState)(null);
|
|
27728
|
+
(0, import_react171.useEffect)(() => {
|
|
27488
27729
|
let alive = true;
|
|
27489
27730
|
void client.tableArchived({ table_id: tableId }).then((answered) => {
|
|
27490
27731
|
if (!alive) return;
|
|
@@ -27661,15 +27902,15 @@ function TablePage({
|
|
|
27661
27902
|
onShownViewChange,
|
|
27662
27903
|
className
|
|
27663
27904
|
}) {
|
|
27664
|
-
const client = (0,
|
|
27665
|
-
const table = (0,
|
|
27905
|
+
const client = (0, import_react172.useRecordsClient)();
|
|
27906
|
+
const table = (0, import_react172.useTable)(tableId);
|
|
27666
27907
|
const rights = useTableRights(table.data);
|
|
27667
|
-
const pageFields = (0,
|
|
27908
|
+
const pageFields = (0, import_react172.useFields)(filter ? tableId : null);
|
|
27668
27909
|
const askedInWords = filter ? filterInWords(filter, pageFields.data ?? []) : null;
|
|
27669
|
-
const organizationId = (0,
|
|
27670
|
-
const [view, setView] = (0,
|
|
27671
|
-
const [looks, setLooks] = (0,
|
|
27672
|
-
(0,
|
|
27910
|
+
const organizationId = (0, import_react172.useRecordsClient)().config.organizationId;
|
|
27911
|
+
const [view, setView] = (0, import_react171.useState)(null);
|
|
27912
|
+
const [looks, setLooks] = (0, import_react171.useState)(void 0);
|
|
27913
|
+
(0, import_react171.useEffect)(() => {
|
|
27673
27914
|
let live = true;
|
|
27674
27915
|
setLooks(void 0);
|
|
27675
27916
|
void readLooks(client, tableId).then((answered) => {
|
|
@@ -27682,35 +27923,35 @@ function TablePage({
|
|
|
27682
27923
|
}, [client, tableId]);
|
|
27683
27924
|
const look = view && looks ? looks[view.id] : void 0;
|
|
27684
27925
|
const shown3 = view ? applyLook(view, look) : null;
|
|
27685
|
-
const [viewsEpoch, setViewsEpoch] = (0,
|
|
27926
|
+
const [viewsEpoch, setViewsEpoch] = (0, import_react171.useState)(0);
|
|
27686
27927
|
const opening = openingRail(activeRecordId, activeRail);
|
|
27687
27928
|
const hostLayouts = useRecordsUi().layouts ?? [];
|
|
27688
27929
|
const hostLayoutFor = (asked) => openingHostLayout(asked, hostLayouts);
|
|
27689
27930
|
const hostFromLink = hostLayoutFor(activeView);
|
|
27690
27931
|
const openedByPackage = openingView(hostFromLink ? null : activeView, activeDashboardId);
|
|
27691
27932
|
const opened = hostFromLink ? { ...openedByPackage, main: "records" } : openedByPackage;
|
|
27692
|
-
const [hostLayout, setHostLayout] = (0,
|
|
27693
|
-
const [views, setViews] = (0,
|
|
27694
|
-
const [pickedViewId, setPickedViewId] = (0,
|
|
27695
|
-
const [layoutChosen, setLayoutChosen] = (0,
|
|
27933
|
+
const [hostLayout, setHostLayout] = (0, import_react171.useState)(hostFromLink);
|
|
27934
|
+
const [views, setViews] = (0, import_react171.useState)(void 0);
|
|
27935
|
+
const [pickedViewId, setPickedViewId] = (0, import_react171.useState)(null);
|
|
27936
|
+
const [layoutChosen, setLayoutChosen] = (0, import_react171.useState)(false);
|
|
27696
27937
|
const railAsked = typeof activeRail === "string" ? activeRail.trim() : "";
|
|
27697
27938
|
const railUnknown = railAsked !== "" && railFromParam(railAsked) === null ? railAsked : null;
|
|
27698
27939
|
const shareFromLink = railFromParam(activeRail) === "share";
|
|
27699
27940
|
const canShare = useCanShare();
|
|
27700
27941
|
const itemFor = (which) => railFromParam(activeRail) === which ? activeItemId ?? null : null;
|
|
27701
|
-
const [asking, setAsking] = (0,
|
|
27702
|
-
const [layoutFromLink, setLayoutFromLink] = (0,
|
|
27703
|
-
const [surface, setSurface] = (0,
|
|
27942
|
+
const [asking, setAsking] = (0, import_react171.useState)(null);
|
|
27943
|
+
const [layoutFromLink, setLayoutFromLink] = (0, import_react171.useState)(opened.layout);
|
|
27944
|
+
const [surface, setSurface] = (0, import_react171.useState)({
|
|
27704
27945
|
main: opened.main,
|
|
27705
27946
|
rail: opening.rail
|
|
27706
27947
|
});
|
|
27707
27948
|
const { main, rail } = surface;
|
|
27708
27949
|
const setRail = (next) => setSurface((now) => ({ ...now, rail: next }));
|
|
27709
|
-
const [openRecord, setOpenRecord] = (0,
|
|
27950
|
+
const [openRecord, setOpenRecord] = (0, import_react171.useState)(opening.record);
|
|
27710
27951
|
const phone = (0, import_design_system87.useIsMobile)();
|
|
27711
|
-
const [shareAsked, setShareAsked] = (0,
|
|
27712
|
-
const [toolbarSlot, setToolbarSlot] = (0,
|
|
27713
|
-
const [toolbarRow, setToolbarRow] = (0,
|
|
27952
|
+
const [shareAsked, setShareAsked] = (0, import_react171.useState)(0);
|
|
27953
|
+
const [toolbarSlot, setToolbarSlot] = (0, import_react171.useState)(null);
|
|
27954
|
+
const [toolbarRow, setToolbarRow] = (0, import_react171.useState)(null);
|
|
27714
27955
|
const toolbarFold2 = useToolbarFit(toolbarRow);
|
|
27715
27956
|
const slotClipped = useSlotScroll(toolbarSlot);
|
|
27716
27957
|
const face = tableOpening(view, hostLayouts.map((h) => h.id));
|
|
@@ -27718,7 +27959,7 @@ function TablePage({
|
|
|
27718
27959
|
const chooserInline = !designated && !phone && toolbarFold2 < 2;
|
|
27719
27960
|
const chooserCompact = !designated && !phone && toolbarFold2 >= 2;
|
|
27720
27961
|
const controlsInSheet = phone && !designated;
|
|
27721
|
-
(0,
|
|
27962
|
+
(0, import_react171.useEffect)(() => {
|
|
27722
27963
|
if (face.kind !== "designated") return;
|
|
27723
27964
|
if (hostFromLink || opened.layout || layoutChosen) return;
|
|
27724
27965
|
setHostLayout(face.hostLayout);
|
|
@@ -27749,9 +27990,9 @@ function TablePage({
|
|
|
27749
27990
|
lookDiffers: view ? lookDiffers(view, look) : false
|
|
27750
27991
|
};
|
|
27751
27992
|
const shownSignature = JSON.stringify(shownReport);
|
|
27752
|
-
const reportRef = (0,
|
|
27993
|
+
const reportRef = (0, import_react171.useRef)(onShownViewChange);
|
|
27753
27994
|
reportRef.current = onShownViewChange;
|
|
27754
|
-
(0,
|
|
27995
|
+
(0, import_react171.useEffect)(() => {
|
|
27755
27996
|
reportRef.current?.(JSON.parse(shownSignature));
|
|
27756
27997
|
}, [shownSignature]);
|
|
27757
27998
|
const pickLayout = (next) => {
|
|
@@ -27769,18 +28010,18 @@ function TablePage({
|
|
|
27769
28010
|
onViewChanged?.(id);
|
|
27770
28011
|
};
|
|
27771
28012
|
const openedFromMenu = MENU.find((entry) => entry.press.main !== void 0 && entry.press.main === main) ?? MENU.find((entry) => entry.press.rail !== void 0 && entry.press.rail === rail) ?? null;
|
|
27772
|
-
(0,
|
|
28013
|
+
(0, import_react171.useEffect)(() => {
|
|
27773
28014
|
if (!activeRecordId) return;
|
|
27774
28015
|
setOpenRecord(activeRecordId);
|
|
27775
28016
|
setSurface((now) => ({ ...now, rail: "record" }));
|
|
27776
28017
|
}, [activeRecordId]);
|
|
27777
|
-
(0,
|
|
28018
|
+
(0, import_react171.useEffect)(() => {
|
|
27778
28019
|
if (activeRecordId) return;
|
|
27779
28020
|
const named = railFromParam(activeRail);
|
|
27780
28021
|
if (named === null || named === "share") return;
|
|
27781
28022
|
setSurface((now) => ({ ...now, rail: named }));
|
|
27782
28023
|
}, [activeRail, activeRecordId]);
|
|
27783
|
-
(0,
|
|
28024
|
+
(0, import_react171.useEffect)(() => {
|
|
27784
28025
|
const host = hostLayoutFor(activeView);
|
|
27785
28026
|
if (host) {
|
|
27786
28027
|
setHostLayout(host);
|
|
@@ -27794,8 +28035,8 @@ function TablePage({
|
|
|
27794
28035
|
setLayoutFromLink(isLayout ? named : null);
|
|
27795
28036
|
setSurface((now) => ({ ...now, main: isLayout ? "records" : named }));
|
|
27796
28037
|
}, [activeView]);
|
|
27797
|
-
const [viewSaveRefused, setViewSaveRefused] = (0,
|
|
27798
|
-
const patchView = (0,
|
|
28038
|
+
const [viewSaveRefused, setViewSaveRefused] = (0, import_react171.useState)(null);
|
|
28039
|
+
const patchView = (0, import_react171.useCallback)(
|
|
27799
28040
|
async (asked) => {
|
|
27800
28041
|
const current = view;
|
|
27801
28042
|
if (!current) return;
|
|
@@ -27812,9 +28053,9 @@ function TablePage({
|
|
|
27812
28053
|
[client, tableId, view, looks]
|
|
27813
28054
|
);
|
|
27814
28055
|
const lookShowing = Boolean(view && looks && lookDiffers(view, looks[view.id]));
|
|
27815
|
-
const [lookRefused, setLookRefused] = (0,
|
|
27816
|
-
const [namingLook, setNamingLook] = (0,
|
|
27817
|
-
const [lookName, setLookName] = (0,
|
|
28056
|
+
const [lookRefused, setLookRefused] = (0, import_react171.useState)(null);
|
|
28057
|
+
const [namingLook, setNamingLook] = (0, import_react171.useState)(false);
|
|
28058
|
+
const [lookName, setLookName] = (0, import_react171.useState)("");
|
|
27818
28059
|
const resetLook = async () => {
|
|
27819
28060
|
const current = view;
|
|
27820
28061
|
if (!current) return;
|
|
@@ -27872,7 +28113,7 @@ function TablePage({
|
|
|
27872
28113
|
setPickedViewId(written.data);
|
|
27873
28114
|
setViewsEpoch((n) => n + 1);
|
|
27874
28115
|
};
|
|
27875
|
-
const [designateRefused, setDesignateRefused] = (0,
|
|
28116
|
+
const [designateRefused, setDesignateRefused] = (0, import_react171.useState)(null);
|
|
27876
28117
|
const opensAs = view?.isDefault ? openingLayoutOf(view) : null;
|
|
27877
28118
|
const canDesignate = Boolean(rights.write && view && layoutShowing && layoutShowing !== opensAs);
|
|
27878
28119
|
const layoutShowingLabel = layoutShowing ? hostLayouts.find((h) => h.id === layoutShowing)?.label ?? (VIEW_LAYOUTS.includes(layoutShowing) ? LAYOUT_LABEL[layoutShowing] : layoutShowing) : "";
|