@ai-matrx/records-ui 0.83.0 → 0.84.0
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 +61 -0
- package/dist/index.cjs +91 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +192 -137
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.84.0
|
|
4
|
+
|
|
5
|
+
**A refusal is said once, with the doors that fit it, and a change a person made is kept or
|
|
6
|
+
said — never dropped.** (lane RECORDS-UI-FIX, VERIFIER-15 H2, H3, M3, M4, M6, M7.)
|
|
7
|
+
|
|
8
|
+
* **The grid's cell refusal is the one notice.** A rule refusal (`-3` in a column "at least
|
|
9
|
+
0") used to draw a small red line with *Try again* (which re-sent the refused value) and
|
|
10
|
+
*Keep theirs* (conflict wording when nobody else wrote). It is now `RefusalNotice` with
|
|
11
|
+
**Keep editing** — the cell reopens holding `-3`, the reason still beside it — and
|
|
12
|
+
**Discard**. *Try again* / *Keep theirs* appear only on a real version conflict, beside
|
|
13
|
+
the other person's value. A tick box's refusal carries Discard.
|
|
14
|
+
* **The record form says a refusal once, with Keep editing / Discard, and before Save.** The
|
|
15
|
+
mirror's per-column notice is the store's rule, so the store's copy under the form is no
|
|
16
|
+
longer drawn beside it; the mirror speaks the moment a changed column would be refused.
|
|
17
|
+
What was typed survives the (slower) version read landing late. An edit sends only the
|
|
18
|
+
columns the person changed, and a Save with nothing changed writes nothing.
|
|
19
|
+
* **A board's layout or grouping change is kept, or said.** Every view save carried a version
|
|
20
|
+
read from the view's history, which can stop short of the record, so every Kanban / Group
|
|
21
|
+
by press was refused `stale_write` and dropped in silence. New `saveViewPatch` (the one
|
|
22
|
+
view-save door) writes on the version the refusal names; a save still refused is said
|
|
23
|
+
through `RefusalNotice` with Try again / Discard.
|
|
24
|
+
* **"Someone else wrote first" only when somebody did.** The store's `contested_fields`
|
|
25
|
+
carries each patched column's current value; when every one is still what the screen
|
|
26
|
+
started from, the write goes once more on the winning version (the grid cell session, the
|
|
27
|
+
record form and saved views apply the same rule — internal `updateOnTheWinningVersion`).
|
|
28
|
+
* **The next digest summary is never in the past.** New export `nextSummaryAt(subscription,
|
|
29
|
+
now)` carries a passed due time forward by whole periods to the first slot after now,
|
|
30
|
+
keeping the store's alignment (tested at a fixed clock).
|
|
31
|
+
* **Table Settings never cuts a field name to two letters** — the name wraps with a readable
|
|
32
|
+
minimum and the row wraps its controls first.
|
|
33
|
+
* **On a phone the table's rail is a sheet over the table** — below the design system's
|
|
34
|
+
breakpoint (`useIsMobile`, 768px) it renders through the canonical `BottomSheet`, the way
|
|
35
|
+
`Dialog` and `CommandDialog` already do; dragging it down closes the rail.
|
|
36
|
+
* Tests (each shown failing on the prior bytes): `src/a-refused-cell-keeps-what-you-typed`,
|
|
37
|
+
`src/a-form-refusal-is-said-once-with-its-doors`, `src/a-board-layout-change-is-kept`,
|
|
38
|
+
`src/the-next-summary-is-never-in-the-past`, `src/a-rail-on-a-phone-is-a-sheet`, and a
|
|
39
|
+
new clause in `src/TableSettings.hooks.test`.
|
|
40
|
+
|
|
41
|
+
**Store-side, reported to the chair (not in this package):** `custom.record_update` of an
|
|
42
|
+
unchanged value moves `version` and writes no history row (reproduced on the dev clone), and
|
|
43
|
+
the digest runner computes the next slot from the last summary SENT, so an empty window
|
|
44
|
+
freezes it.
|
|
45
|
+
|
|
46
|
+
**Consumer action (matrx-frontend):** none required — install picks it up. A host that
|
|
47
|
+
shows a digest's next time outside `SubscriptionsPanel` should use `nextSummaryAt`.
|
|
48
|
+
|
|
49
|
+
## 0.83.1
|
|
50
|
+
|
|
51
|
+
**A table shared by link is in the World lane, not Community.** (lane HUB-FIX, chair ruling
|
|
52
|
+
2026-09-23.)
|
|
53
|
+
|
|
54
|
+
* `visibilityLaneFor` maps `link` → `world` (was `community`). A link anyone can open without
|
|
55
|
+
signing in reaches the world; Community is for things any SIGNED-IN account can reach, and
|
|
56
|
+
the store has no signed-in-only link yet, so no stored visibility lands in Community today.
|
|
57
|
+
`VISIBILITY_LANES` still carries all four — the chip stays.
|
|
58
|
+
* Test: `src/visibility-lanes.test.tsx` updated (link → world) plus a case pinning that no
|
|
59
|
+
stored visibility maps to Community yet — 5 cases.
|
|
60
|
+
|
|
61
|
+
**Consumer action:** none. The hub reads `visibilityLaneFor`, so link-shared tables move from
|
|
62
|
+
the Community chip to the World chip on install.
|
|
63
|
+
|
|
3
64
|
## 0.83.0
|
|
4
65
|
|
|
5
66
|
**Four visibility lanes a filter can read, and the store's own choice lists stop sitting
|
package/dist/index.cjs
CHANGED
|
@@ -256,6 +256,7 @@ __export(src_exports, {
|
|
|
256
256
|
mayNotRestoreLine: () => mayNotRestoreLine,
|
|
257
257
|
memberName: () => memberName,
|
|
258
258
|
nextInWords: () => nextInWords,
|
|
259
|
+
nextSummaryAt: () => nextSummaryAt,
|
|
259
260
|
openingRail: () => openingRail,
|
|
260
261
|
openingView: () => openingView,
|
|
261
262
|
pageViewFromParam: () => pageViewFromParam,
|
|
@@ -2388,7 +2389,7 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow }
|
|
|
2388
2389
|
startedFrom.current = null;
|
|
2389
2390
|
}, []);
|
|
2390
2391
|
const writeCellNow = (0, import_react15.useCallback)(
|
|
2391
|
-
async (rowId, key, value, resent = false) => {
|
|
2392
|
+
async (rowId, key, value, base, resent = false) => {
|
|
2392
2393
|
const id = cellKey(rowId, key);
|
|
2393
2394
|
setOptimistic((held) => ({ ...held, [id]: value }));
|
|
2394
2395
|
setSaving((held) => ({ ...held, [id]: true }));
|
|
@@ -2435,8 +2436,8 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow }
|
|
|
2435
2436
|
if (written.error.code === "stale_write") {
|
|
2436
2437
|
if (conflict) rememberVersion(versions.current, rowId, conflict.current_version);
|
|
2437
2438
|
else versions.current.delete(rowId);
|
|
2438
|
-
if (conflict && !resent &&
|
|
2439
|
-
await writeCellNow(rowId, key, value, true);
|
|
2439
|
+
if (conflict && !resent && sameValue(conflict.contested_fields[key], base)) {
|
|
2440
|
+
await writeCellNow(rowId, key, value, base, true);
|
|
2440
2441
|
return;
|
|
2441
2442
|
}
|
|
2442
2443
|
}
|
|
@@ -2453,9 +2454,9 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow }
|
|
|
2453
2454
|
[client, reload]
|
|
2454
2455
|
);
|
|
2455
2456
|
const writeCell = (0, import_react15.useCallback)(
|
|
2456
|
-
(rowId, key, value) => {
|
|
2457
|
+
(rowId, key, value, base) => {
|
|
2457
2458
|
const behind = queues.current.get(rowId) ?? Promise.resolve();
|
|
2458
|
-
const next = behind.then(() => writeCellNow(rowId, key, value));
|
|
2459
|
+
const next = behind.then(() => writeCellNow(rowId, key, value, base));
|
|
2459
2460
|
queues.current.set(
|
|
2460
2461
|
rowId,
|
|
2461
2462
|
next.then(
|
|
@@ -2473,7 +2474,7 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow }
|
|
|
2473
2474
|
const open = editing;
|
|
2474
2475
|
if (!open) return;
|
|
2475
2476
|
const value = typed.current;
|
|
2476
|
-
if (!sameValue(startedFrom.current, value)) void writeCell(open.rowId, open.key, value);
|
|
2477
|
+
if (!sameValue(startedFrom.current, value)) void writeCell(open.rowId, open.key, value, startedFrom.current);
|
|
2477
2478
|
if (!move) {
|
|
2478
2479
|
setEditing(null);
|
|
2479
2480
|
setDraft(null);
|
|
@@ -2502,7 +2503,7 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow }
|
|
|
2502
2503
|
(rowId, key) => {
|
|
2503
2504
|
const held = refusals[cellKey(rowId, key)];
|
|
2504
2505
|
if (!held) return;
|
|
2505
|
-
void writeCell(rowId, key, held.attempted);
|
|
2506
|
+
void writeCell(rowId, key, held.attempted, held.conflict?.contested_fields[key]);
|
|
2506
2507
|
},
|
|
2507
2508
|
[refusals, writeCell]
|
|
2508
2509
|
);
|
|
@@ -2598,7 +2599,7 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite, mayWriteRow }
|
|
|
2598
2599
|
commit,
|
|
2599
2600
|
setCell: (rowId, key, value) => {
|
|
2600
2601
|
if (!writable(rowId)) return;
|
|
2601
|
-
void writeCell(rowId, key, value);
|
|
2602
|
+
void writeCell(rowId, key, value, shownValue(rowId, key));
|
|
2602
2603
|
},
|
|
2603
2604
|
retry,
|
|
2604
2605
|
keepTheirs,
|
|
@@ -2683,7 +2684,7 @@ function GridCell({
|
|
|
2683
2684
|
RefusalNotice,
|
|
2684
2685
|
{
|
|
2685
2686
|
error: refusal2.error,
|
|
2686
|
-
className: "py-1.5",
|
|
2687
|
+
className: "py-1.5 text-left",
|
|
2687
2688
|
onDiscard: () => editing.discard(row.id, field.key)
|
|
2688
2689
|
}
|
|
2689
2690
|
) : null
|
|
@@ -2797,7 +2798,7 @@ function CellRefusalNotice({
|
|
|
2797
2798
|
RefusalNotice,
|
|
2798
2799
|
{
|
|
2799
2800
|
error: refusal2.error,
|
|
2800
|
-
className: "py-1.5",
|
|
2801
|
+
className: "py-1.5 text-left",
|
|
2801
2802
|
actions: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex flex-col gap-1", "data-refusal-conflict": "", children: [
|
|
2802
2803
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-[11px]", children: [
|
|
2803
2804
|
"Theirs: ",
|
|
@@ -2815,7 +2816,7 @@ function CellRefusalNotice({
|
|
|
2815
2816
|
RefusalNotice,
|
|
2816
2817
|
{
|
|
2817
2818
|
error: refusal2.error,
|
|
2818
|
-
className: "py-1.5",
|
|
2819
|
+
className: "py-1.5 text-left",
|
|
2819
2820
|
...typed ? { onKeepEditing: () => editing?.keepEditing(row.id, field.key) } : {},
|
|
2820
2821
|
onDiscard: () => editing?.discard(row.id, field.key)
|
|
2821
2822
|
}
|
|
@@ -7131,7 +7132,39 @@ var import_design_system22 = require("@ai-matrx/design-system");
|
|
|
7131
7132
|
// src/RecordForm.tsx
|
|
7132
7133
|
var import_react41 = require("react");
|
|
7133
7134
|
var import_react42 = require("@ai-matrx/records/react");
|
|
7135
|
+
var import_core7 = require("@ai-matrx/records/core");
|
|
7136
|
+
|
|
7137
|
+
// src/writeOnTheWinningVersion.ts
|
|
7134
7138
|
var import_core6 = require("@ai-matrx/records/core");
|
|
7139
|
+
function sameStoredValue(left, right) {
|
|
7140
|
+
if (left === right) return true;
|
|
7141
|
+
const empty = (v) => v === null || v === void 0 || v === "";
|
|
7142
|
+
if (empty(left) || empty(right)) return empty(left) && empty(right);
|
|
7143
|
+
if (typeof left === "object" || typeof right === "object") {
|
|
7144
|
+
try {
|
|
7145
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
7146
|
+
} catch {
|
|
7147
|
+
return false;
|
|
7148
|
+
}
|
|
7149
|
+
}
|
|
7150
|
+
return false;
|
|
7151
|
+
}
|
|
7152
|
+
async function updateOnTheWinningVersion(client, recordId, patch, expectedVersion, base) {
|
|
7153
|
+
const send = (expected) => client.recordUpdate({
|
|
7154
|
+
record_id: recordId,
|
|
7155
|
+
patch,
|
|
7156
|
+
...expected === null ? {} : { expectedVersion: expected }
|
|
7157
|
+
});
|
|
7158
|
+
const first = await send(expectedVersion);
|
|
7159
|
+
if (first.ok) return first;
|
|
7160
|
+
const conflict = (0, import_core6.asWriteConflict)(first.error, recordId);
|
|
7161
|
+
if (!conflict) return first;
|
|
7162
|
+
const untouched = base === "always" || Object.keys(patch).every((key) => sameStoredValue(conflict.contested_fields[key], base[key]));
|
|
7163
|
+
if (!untouched) return first;
|
|
7164
|
+
return send(conflict.current_version);
|
|
7165
|
+
}
|
|
7166
|
+
|
|
7167
|
+
// src/RecordForm.tsx
|
|
7135
7168
|
var import_design_system20 = require("@ai-matrx/design-system");
|
|
7136
7169
|
|
|
7137
7170
|
// src/systemTable.ts
|
|
@@ -7319,15 +7352,38 @@ function RecordForm({
|
|
|
7319
7352
|
const fields = (0, import_react42.useFields)(tableId, recordType);
|
|
7320
7353
|
const existing = (0, import_react42.useRecord)(recordId ?? null);
|
|
7321
7354
|
const mutation = (0, import_react42.useRecordMutation)();
|
|
7355
|
+
const client = (0, import_react42.useRecordsClient)();
|
|
7356
|
+
const [edit, setEdit] = (0, import_react41.useState)({
|
|
7357
|
+
saving: false,
|
|
7358
|
+
error: null,
|
|
7359
|
+
conflict: null
|
|
7360
|
+
});
|
|
7361
|
+
const said = {
|
|
7362
|
+
saving: mutation.saving || edit.saving,
|
|
7363
|
+
error: recordId ? edit.error : mutation.error,
|
|
7364
|
+
conflict: recordId ? edit.conflict : mutation.conflict,
|
|
7365
|
+
clearConflict: () => {
|
|
7366
|
+
mutation.clearConflict();
|
|
7367
|
+
setEdit((e) => ({ ...e, conflict: null }));
|
|
7368
|
+
}
|
|
7369
|
+
};
|
|
7322
7370
|
const [draft, setDraft] = (0, import_react41.useState)({});
|
|
7323
7371
|
const [touched, setTouched] = (0, import_react41.useState)(false);
|
|
7324
7372
|
const [changed, setChanged] = (0, import_react41.useState)({});
|
|
7325
7373
|
const [answered, setAnswered] = (0, import_react41.useState)(null);
|
|
7326
7374
|
const loaded = useRecordVersion(recordId ?? null);
|
|
7327
7375
|
const loadedVersion = loaded.version;
|
|
7376
|
+
const changedRef = (0, import_react41.useRef)({});
|
|
7377
|
+
changedRef.current = changed;
|
|
7328
7378
|
(0, import_react41.useEffect)(() => {
|
|
7329
7379
|
const document3 = existing.data?.document;
|
|
7330
|
-
if (document3)
|
|
7380
|
+
if (!document3) return;
|
|
7381
|
+
const mine = changedRef.current;
|
|
7382
|
+
setDraft((held) => {
|
|
7383
|
+
const next = { ...document3 };
|
|
7384
|
+
for (const key of Object.keys(mine)) next[key] = held[key];
|
|
7385
|
+
return next;
|
|
7386
|
+
});
|
|
7331
7387
|
}, [existing.data?.record_id, loadedVersion]);
|
|
7332
7388
|
const document2 = (0, import_react41.useMemo)(() => {
|
|
7333
7389
|
const out = {};
|
|
@@ -7338,15 +7394,15 @@ function RecordForm({
|
|
|
7338
7394
|
return out;
|
|
7339
7395
|
}, [draft]);
|
|
7340
7396
|
const predicted = (0, import_react41.useMemo)(
|
|
7341
|
-
() => fields.data ? (0,
|
|
7397
|
+
() => fields.data ? (0, import_core7.predictWriteRefusals)({ fields: fields.data, document: document2, ...recordType ? { recordType } : {} }) : [],
|
|
7342
7398
|
[fields.data, document2, recordType]
|
|
7343
7399
|
);
|
|
7344
7400
|
if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RefusalNotice, { error: fields.error, className });
|
|
7345
7401
|
if (existing.error) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(RefusalNotice, { error: existing.error, className });
|
|
7346
|
-
const storeSaid =
|
|
7402
|
+
const storeSaid = said.error && said.error !== answered ? said.error : null;
|
|
7347
7403
|
const fieldProblems = predicted.filter((p) => p.field_key);
|
|
7348
7404
|
const problemsShown = (key) => touched || changed[key] ? fieldProblems.filter((p) => p.field_key === key) : [];
|
|
7349
|
-
const storeRefusalIsOnAField = storeSaid !== null && !
|
|
7405
|
+
const storeRefusalIsOnAField = storeSaid !== null && !said.conflict && storeSaid.code === "refused_by_rule" && (fields.data ?? []).some((f) => problemsShown(f.key).length > 0);
|
|
7350
7406
|
const stored = existing.data?.document;
|
|
7351
7407
|
const focusField = (field) => {
|
|
7352
7408
|
if (!field) return;
|
|
@@ -7377,13 +7433,22 @@ function RecordForm({
|
|
|
7377
7433
|
setAnswered(null);
|
|
7378
7434
|
if (recordId) {
|
|
7379
7435
|
const version = loadedVersion;
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7436
|
+
if (Object.keys(changed).length === 0) {
|
|
7437
|
+
onSaved?.(recordId);
|
|
7438
|
+
return;
|
|
7439
|
+
}
|
|
7440
|
+
const patch = Object.fromEntries(Object.entries(document2).filter(([key]) => changed[key]));
|
|
7441
|
+
setEdit({ saving: true, error: null, conflict: null });
|
|
7442
|
+
const answered2 = await updateOnTheWinningVersion(client, recordId, patch, version, stored ?? {});
|
|
7443
|
+
setEdit({
|
|
7444
|
+
saving: false,
|
|
7445
|
+
error: answered2.ok ? null : answered2.error,
|
|
7446
|
+
conflict: answered2.ok ? null : (0, import_core7.asWriteConflict)(answered2.error, recordId)
|
|
7384
7447
|
});
|
|
7448
|
+
const moved = answered2.ok ? answered2.data : null;
|
|
7385
7449
|
if (moved !== null) {
|
|
7386
7450
|
loaded.note(moved);
|
|
7451
|
+
setChanged({});
|
|
7387
7452
|
host.notify?.success("Saved");
|
|
7388
7453
|
existing.reload();
|
|
7389
7454
|
onSaved?.(recordId);
|
|
@@ -7432,9 +7497,9 @@ function RecordForm({
|
|
|
7432
7497
|
RefusalNotice,
|
|
7433
7498
|
{
|
|
7434
7499
|
error: storeSaid,
|
|
7435
|
-
...
|
|
7500
|
+
...said.conflict ? {
|
|
7436
7501
|
actions: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "mt-1 space-y-1", children: [
|
|
7437
|
-
Object.entries(
|
|
7502
|
+
Object.entries(said.conflict.contested_fields).map(([key, theirs]) => {
|
|
7438
7503
|
const column = (fields.data ?? []).find((f) => f.key === key);
|
|
7439
7504
|
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("p", { className: "text-[11px]", children: [
|
|
7440
7505
|
column ? fieldName(column) : humanize(key),
|
|
@@ -7452,9 +7517,9 @@ function RecordForm({
|
|
|
7452
7517
|
size: "sm",
|
|
7453
7518
|
variant: "outline",
|
|
7454
7519
|
onClick: () => {
|
|
7455
|
-
if (
|
|
7520
|
+
if (said.conflict) loaded.note(said.conflict.current_version);
|
|
7456
7521
|
existing.reload();
|
|
7457
|
-
|
|
7522
|
+
said.clearConflict();
|
|
7458
7523
|
setAnswered(storeSaid);
|
|
7459
7524
|
},
|
|
7460
7525
|
children: "Take theirs and start again"
|
|
@@ -7466,7 +7531,7 @@ function RecordForm({
|
|
|
7466
7531
|
) : null,
|
|
7467
7532
|
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system20.Separator, {}),
|
|
7468
7533
|
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
7469
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system20.Button, { type: "submit", size: "sm", disabled:
|
|
7534
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system20.Button, { type: "submit", size: "sm", disabled: said.saving, children: said.saving ? "Saving\u2026" : recordId ? "Save" : "Create" }),
|
|
7470
7535
|
onCancel ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_design_system20.Button, { type: "button", size: "sm", variant: "ghost", onClick: onCancel, children: "Cancel" }) : null
|
|
7471
7536
|
] })
|
|
7472
7537
|
]
|
|
@@ -7661,7 +7726,6 @@ function computedInPlainWords(row, field) {
|
|
|
7661
7726
|
}
|
|
7662
7727
|
|
|
7663
7728
|
// src/views.ts
|
|
7664
|
-
var import_core7 = require("@ai-matrx/records/core");
|
|
7665
7729
|
var VIEW_LAYOUTS = ["grid", "kanban", "calendar", "gallery"];
|
|
7666
7730
|
var LAYOUT_LABEL = {
|
|
7667
7731
|
grid: "Grid",
|
|
@@ -7786,16 +7850,7 @@ function viewFromRecord(row) {
|
|
|
7786
7850
|
};
|
|
7787
7851
|
}
|
|
7788
7852
|
async function saveViewPatch(client, viewId, document2, expectedVersion) {
|
|
7789
|
-
|
|
7790
|
-
record_id: viewId,
|
|
7791
|
-
patch: document2,
|
|
7792
|
-
...expected === null ? {} : { expectedVersion: expected }
|
|
7793
|
-
});
|
|
7794
|
-
const first = await send(expectedVersion);
|
|
7795
|
-
if (first.ok) return first;
|
|
7796
|
-
const conflict = (0, import_core7.asWriteConflict)(first.error, viewId);
|
|
7797
|
-
if (!conflict) return first;
|
|
7798
|
-
return send(conflict.current_version);
|
|
7853
|
+
return updateOnTheWinningVersion(client, viewId, document2, expectedVersion, "always");
|
|
7799
7854
|
}
|
|
7800
7855
|
function viewPatchDocument(patch) {
|
|
7801
7856
|
const out = {};
|
|
@@ -16505,8 +16560,7 @@ function visibilityLaneFor(table) {
|
|
|
16505
16560
|
if (table.is_kernel) return null;
|
|
16506
16561
|
if ((table.slug ?? "").startsWith(APP_TABLE_PREFIX) || keptByTheApp(table)) return null;
|
|
16507
16562
|
if (table.visibility === "personal") return "mine";
|
|
16508
|
-
if (table.visibility === "link") return "
|
|
16509
|
-
if (table.visibility === "public") return "world";
|
|
16563
|
+
if (table.visibility === "link" || table.visibility === "public") return "world";
|
|
16510
16564
|
return "organization";
|
|
16511
16565
|
}
|
|
16512
16566
|
function TablesHome({ onOpenTable, className }) {
|