@dxos/react-ui-table 0.8.4-main.72ec0f3 → 0.8.4-main.8360d9e660
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/dist/lib/browser/chunk-BF54SSNL.mjs +70 -0
- package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GS2UNGJK.mjs → chunk-PTHMYAAM.mjs} +656 -680
- package/dist/lib/browser/chunk-PTHMYAAM.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1158 -1028
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +30 -42
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/types/index.mjs +3 -3
- package/dist/lib/node-esm/{chunk-TRR3C5NX.mjs → chunk-GI72MQSG.mjs} +656 -679
- package/dist/lib/node-esm/chunk-GI72MQSG.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs +71 -0
- package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1158 -1028
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +30 -42
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/types/index.mjs +3 -3
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -2
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts +2 -2
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +4 -18
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +12 -8
- package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +11 -11
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +71 -5
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +10 -12
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -7
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +4 -4
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +3 -3
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +22 -15
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts +5 -6
- package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
- package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
- package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
- package/dist/types/src/hooks/useTableModel.d.ts +9 -9
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/modal-controller.d.ts +5 -1
- package/dist/types/src/model/modal-controller.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts +17 -8
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +104 -24
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +3 -1
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/playwright/TableManager.d.ts +2 -1
- package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
- package/dist/types/src/testing/useTestTableModel.d.ts +18 -15
- package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +4 -4
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Table.d.ts +26 -0
- package/dist/types/src/types/Table.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +14 -11
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
- package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +2 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/query-ast.d.ts +7 -0
- package/dist/types/src/util/query-ast.d.ts.map +1 -0
- package/dist/types/src/util/sort.d.ts +12 -0
- package/dist/types/src/util/sort.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +54 -55
- package/src/components/Table/ColumnActionsMenu.tsx +10 -6
- package/src/components/Table/ColumnSettings.tsx +8 -9
- package/src/components/Table/DynamicTable.stories.tsx +16 -16
- package/src/components/Table/DynamicTable.tsx +30 -22
- package/src/components/Table/Relations.stories.tsx +39 -41
- package/src/components/Table/RowActionsMenu.tsx +3 -2
- package/src/components/Table/Table.stories.tsx +110 -92
- package/src/components/Table/Table.tsx +324 -299
- package/src/components/TableCellEditor/CellValidationMessage.tsx +5 -5
- package/src/components/TableCellEditor/FormCellEditor.tsx +118 -135
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +14 -10
- package/src/components/TableCellEditor/TableCellEditor.tsx +31 -31
- package/src/components/TableToolbar/TableToolbar.tsx +25 -19
- package/src/components/testing.ts +38 -12
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useAddRow.ts +8 -10
- package/src/hooks/useProjectionModel.ts +39 -0
- package/src/hooks/useTableModel.ts +36 -34
- package/src/model/modal-controller.ts +23 -12
- package/src/model/selection-model.ts +75 -44
- package/src/model/table-model.test.ts +82 -54
- package/src/model/table-model.ts +430 -167
- package/src/model/table-presentation.test.ts +59 -49
- package/src/model/table-presentation.ts +43 -37
- package/src/playwright/TableManager.ts +13 -6
- package/src/playwright/playwright.config.ts +1 -1
- package/src/playwright/smoke.spec.ts +49 -5
- package/src/testing/useTestTableModel.ts +45 -38
- package/src/translations.ts +3 -3
- package/src/types/Table.ts +79 -0
- package/src/types/index.ts +1 -1
- package/src/util/dynamic-table.test.ts +70 -0
- package/src/util/dynamic-table.ts +40 -26
- package/src/util/index.ts +2 -0
- package/src/util/query-ast.ts +22 -0
- package/src/util/sort.ts +90 -0
- package/src/util/table-buttons.ts +1 -1
- package/src/util/table-controls.ts +2 -2
- package/dist/lib/browser/chunk-2PFAPQL4.mjs +0 -66
- package/dist/lib/browser/chunk-2PFAPQL4.mjs.map +0 -7
- package/dist/lib/browser/chunk-GS2UNGJK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-6POOFFYF.mjs +0 -67
- package/dist/lib/node-esm/chunk-6POOFFYF.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-TRR3C5NX.mjs.map +0 -7
- package/dist/types/src/model/table-sorting.d.ts +0 -52
- package/dist/types/src/model/table-sorting.d.ts.map +0 -1
- package/dist/types/src/types/schema.d.ts +0 -28
- package/dist/types/src/types/schema.d.ts.map +0 -1
- package/src/model/table-sorting.ts +0 -225
- package/src/types/schema.ts +0 -73
|
@@ -1,86 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// src/util/dynamic-table.ts
|
|
6
|
-
import { Filter, Obj, Query } from "@dxos/echo";
|
|
7
|
-
import { getTypename, toJsonSchema } from "@dxos/echo/internal";
|
|
8
|
-
import { ProjectionModel, View, getSchemaFromPropertyDefinitions } from "@dxos/schema";
|
|
9
|
-
var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
|
|
10
|
-
if (typename && properties) {
|
|
11
|
-
const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
|
|
12
|
-
return {
|
|
13
|
-
typename: schema2.typename,
|
|
14
|
-
jsonSchema: schema2.jsonSchema
|
|
15
|
-
};
|
|
16
|
-
} else if (schema) {
|
|
17
|
-
return {
|
|
18
|
-
typename: getTypename(schema),
|
|
19
|
-
jsonSchema: toJsonSchema(schema)
|
|
20
|
-
};
|
|
21
|
-
} else if (typename && jsonSchema) {
|
|
22
|
-
return {
|
|
23
|
-
typename,
|
|
24
|
-
jsonSchema
|
|
25
|
-
};
|
|
26
|
-
} else {
|
|
27
|
-
throw new Error("invalid properties");
|
|
1
|
+
// src/util/query-ast.ts
|
|
2
|
+
var extractOrder = (queryAst) => {
|
|
3
|
+
if (queryAst.type === "order") {
|
|
4
|
+
return queryAst.order;
|
|
28
5
|
}
|
|
6
|
+
if (queryAst.type === "options") {
|
|
7
|
+
return extractOrder(queryAst.query);
|
|
8
|
+
}
|
|
9
|
+
if (queryAst.type === "from") {
|
|
10
|
+
return extractOrder(queryAst.query);
|
|
11
|
+
}
|
|
12
|
+
return void 0;
|
|
29
13
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
view
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
var setProperties = (view, projection, table, properties) => {
|
|
53
|
-
for (const property of properties) {
|
|
54
|
-
const field = projection.fields.find((field2) => field2.path === property.name);
|
|
55
|
-
if (field) {
|
|
56
|
-
if (property.size !== void 0) {
|
|
57
|
-
table.sizes[field.path] = property.size;
|
|
58
|
-
}
|
|
59
|
-
if (property.title !== void 0) {
|
|
60
|
-
const fieldProjection = projection.getFieldProjection(field.id);
|
|
61
|
-
projection.setFieldProjection({
|
|
62
|
-
...fieldProjection,
|
|
63
|
-
props: {
|
|
64
|
-
...fieldProjection.props,
|
|
65
|
-
title: property.title
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
if (property.sort) {
|
|
70
|
-
const fieldId = field.id;
|
|
71
|
-
view.sort = [
|
|
72
|
-
{
|
|
73
|
-
fieldId,
|
|
74
|
-
direction: property.sort
|
|
75
|
-
}
|
|
76
|
-
];
|
|
77
|
-
}
|
|
14
|
+
|
|
15
|
+
// src/util/sort.ts
|
|
16
|
+
import { Format } from "@dxos/echo";
|
|
17
|
+
var getSortValue = (value, format) => {
|
|
18
|
+
if (value === void 0 || value === null) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const isDateFormat = format === Format.TypeFormat.DateTime || format === Format.TypeFormat.Date;
|
|
22
|
+
if (isDateFormat) {
|
|
23
|
+
const date = new Date(value);
|
|
24
|
+
if (!isNaN(date.getTime())) {
|
|
25
|
+
return date.getTime();
|
|
26
|
+
}
|
|
27
|
+
return String(value);
|
|
28
|
+
}
|
|
29
|
+
if (format === Format.TypeFormat.Number || format === Format.TypeFormat.Integer || format === Format.TypeFormat.Currency || format === Format.TypeFormat.Percent || format === Format.TypeFormat.Duration) {
|
|
30
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
31
|
+
if (!isNaN(num)) {
|
|
32
|
+
return num;
|
|
78
33
|
}
|
|
34
|
+
return String(value);
|
|
79
35
|
}
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === "number") {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
return String(value);
|
|
43
|
+
};
|
|
44
|
+
var compareValues = (aValue, bValue, format, direction) => {
|
|
45
|
+
if (aValue === void 0 || aValue === null) {
|
|
46
|
+
return bValue === void 0 || bValue === null ? 0 : 1;
|
|
47
|
+
}
|
|
48
|
+
if (bValue === void 0 || bValue === null) {
|
|
49
|
+
return -1;
|
|
50
|
+
}
|
|
51
|
+
const aSortValue = getSortValue(aValue, format);
|
|
52
|
+
const bSortValue = getSortValue(bValue, format);
|
|
53
|
+
let comparison = 0;
|
|
54
|
+
if (typeof aSortValue === "number" && typeof bSortValue === "number") {
|
|
55
|
+
comparison = aSortValue - bSortValue;
|
|
56
|
+
} else if (typeof aSortValue === "string" && typeof bSortValue === "string") {
|
|
57
|
+
comparison = aSortValue.localeCompare(bSortValue);
|
|
58
|
+
} else {
|
|
59
|
+
comparison = String(aSortValue).localeCompare(String(bSortValue));
|
|
60
|
+
}
|
|
61
|
+
return direction === "desc" ? -comparison : comparison;
|
|
80
62
|
};
|
|
81
|
-
|
|
82
|
-
// src/util/signals.ts
|
|
83
|
-
var touch = (value) => value;
|
|
84
63
|
|
|
85
64
|
// src/util/table-buttons.ts
|
|
86
65
|
var BUTTON_IDENTIFIERS = {
|
|
@@ -93,7 +72,7 @@ var BUTTON_IDENTIFIERS = {
|
|
|
93
72
|
};
|
|
94
73
|
var createButton = ({ attr, data, disabled = false, icon, testId, type: _type = "primary" }) => {
|
|
95
74
|
const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
96
|
-
return `<button ${attr} data-testid="${testId}" class="dx-button
|
|
75
|
+
return `<button ${attr} data-testid="${testId}" class="dx-button w-6 aspect-square px-0.5 min-h-0" ${dataAttrs} ${disabled ? "disabled" : ""} data-dx-grid-action="accessory"><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
|
|
97
76
|
};
|
|
98
77
|
var addColumnButton = {
|
|
99
78
|
attr: BUTTON_IDENTIFIERS.newColumn,
|
|
@@ -206,8 +185,8 @@ var CONTROL_IDENTIFIERS = {
|
|
|
206
185
|
switch: "data-table-switch"
|
|
207
186
|
};
|
|
208
187
|
var BASE_CLASSES = {
|
|
209
|
-
checkbox: "absolute inset-
|
|
210
|
-
switch: "absolute inset-
|
|
188
|
+
checkbox: "absolute inset-y-[.375rem] end-[.375rem] dx-checkbox",
|
|
189
|
+
switch: "absolute inset-y-[.25rem] end-[.25rem] dx-checkbox--switch"
|
|
211
190
|
};
|
|
212
191
|
var renderAttributes = (data) => {
|
|
213
192
|
return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
@@ -255,31 +234,17 @@ var tableControls = {
|
|
|
255
234
|
}
|
|
256
235
|
};
|
|
257
236
|
|
|
258
|
-
// src/util/schema.ts
|
|
259
|
-
import * as Schema from "effect/Schema";
|
|
260
|
-
import * as SchemaAST from "effect/SchemaAST";
|
|
261
|
-
var narrowSchema = (schema, paths) => {
|
|
262
|
-
const ast = schema?.ast;
|
|
263
|
-
if (SchemaAST.isTypeLiteral(ast)) {
|
|
264
|
-
const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
|
|
265
|
-
if (propertySignatures.length > 0) {
|
|
266
|
-
const narrowType = new SchemaAST.TypeLiteral(propertySignatures, []);
|
|
267
|
-
return Schema.make(narrowType);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return void 0;
|
|
271
|
-
};
|
|
272
|
-
|
|
273
237
|
// src/model/table-model.ts
|
|
274
|
-
import {
|
|
238
|
+
import { Atom as Atom2 } from "@effect-atom/atom-react";
|
|
275
239
|
import { Resource as Resource2 } from "@dxos/context";
|
|
276
|
-
import {
|
|
277
|
-
import {
|
|
240
|
+
import { Format as Format2, Obj, Order, Query, Ref } from "@dxos/echo";
|
|
241
|
+
import { toEffectSchema } from "@dxos/echo/internal";
|
|
242
|
+
import { getSnapshot } from "@dxos/echo/internal";
|
|
243
|
+
import { getValue, setValue } from "@dxos/effect";
|
|
278
244
|
import { invariant } from "@dxos/invariant";
|
|
279
245
|
import { ObjectId } from "@dxos/keys";
|
|
280
|
-
import { getSnapshot, isLiveObject } from "@dxos/live-object";
|
|
281
246
|
import { formatForEditing, parseValue } from "@dxos/react-ui-form";
|
|
282
|
-
import {
|
|
247
|
+
import { validateSchema } from "@dxos/schema";
|
|
283
248
|
|
|
284
249
|
// src/util/tag.ts
|
|
285
250
|
var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
@@ -298,75 +263,99 @@ var extractTagIds = (value) => {
|
|
|
298
263
|
};
|
|
299
264
|
|
|
300
265
|
// src/model/selection-model.ts
|
|
301
|
-
import {
|
|
266
|
+
import { Atom } from "@effect-atom/atom-react";
|
|
302
267
|
import { Resource } from "@dxos/context";
|
|
303
268
|
var SelectionModel = class extends Resource {
|
|
269
|
+
_registry;
|
|
304
270
|
_rows;
|
|
271
|
+
_selection;
|
|
272
|
+
_validSelectedIds;
|
|
273
|
+
_hasSelection;
|
|
274
|
+
_allSelected;
|
|
305
275
|
_selectionMode;
|
|
306
|
-
_initialSelection;
|
|
307
276
|
_onSelectionChanged;
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
277
|
+
constructor(registry, rows, selectionMode, initialSelection, onSelectionChanged) {
|
|
278
|
+
super();
|
|
279
|
+
this._registry = registry;
|
|
280
|
+
this._rows = rows;
|
|
281
|
+
this._selectionMode = selectionMode;
|
|
282
|
+
this._onSelectionChanged = onSelectionChanged;
|
|
283
|
+
this._selection = Atom.make(new Set(initialSelection));
|
|
284
|
+
this._validSelectedIds = Atom.make((get) => {
|
|
285
|
+
const rows2 = get(this._rows);
|
|
286
|
+
if (!rows2) {
|
|
287
|
+
return /* @__PURE__ */ new Set();
|
|
288
|
+
}
|
|
289
|
+
const validIds = new Set(rows2.map((row) => row.id));
|
|
290
|
+
const selection = get(this._selection);
|
|
291
|
+
return new Set([
|
|
292
|
+
...selection
|
|
293
|
+
].filter((id) => validIds.has(id)));
|
|
294
|
+
});
|
|
295
|
+
this._hasSelection = Atom.make((get) => get(this._validSelectedIds).size > 0);
|
|
296
|
+
this._allSelected = Atom.make((get) => {
|
|
297
|
+
const rows2 = get(this._rows);
|
|
298
|
+
if (rows2.length === 0) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
const selection = get(this._selection);
|
|
302
|
+
return rows2.every((row) => selection.has(row.id));
|
|
303
|
+
});
|
|
330
304
|
}
|
|
331
305
|
async _open() {
|
|
332
|
-
const
|
|
333
|
-
touch(this._selection.value);
|
|
306
|
+
const selectionUnsubscribe = this._registry.subscribe(this._selection, () => {
|
|
334
307
|
this._onSelectionChanged?.();
|
|
335
308
|
});
|
|
336
|
-
this._ctx.onDispose(
|
|
309
|
+
this._ctx.onDispose(selectionUnsubscribe);
|
|
337
310
|
}
|
|
338
311
|
//
|
|
339
312
|
// Getters
|
|
340
313
|
//
|
|
341
|
-
|
|
314
|
+
/** Get the selection atom for reactive access. */
|
|
315
|
+
get selectionAtom() {
|
|
342
316
|
return this._selection;
|
|
343
317
|
}
|
|
344
|
-
|
|
318
|
+
/** Get the current selection value. */
|
|
319
|
+
get selection() {
|
|
320
|
+
return this._registry.get(this._selection);
|
|
321
|
+
}
|
|
322
|
+
/** Get the hasSelection atom for reactive access. */
|
|
323
|
+
get hasSelectionAtom() {
|
|
345
324
|
return this._hasSelection;
|
|
346
325
|
}
|
|
347
|
-
|
|
326
|
+
/** Check if there is any selection. */
|
|
327
|
+
get hasSelection() {
|
|
328
|
+
return this._registry.get(this._hasSelection);
|
|
329
|
+
}
|
|
330
|
+
/** Get the allRowsSelected atom for reactive access. */
|
|
331
|
+
get allRowsSelectedAtom() {
|
|
348
332
|
return this._allSelected;
|
|
349
333
|
}
|
|
334
|
+
/** Check if all rows are selected. */
|
|
335
|
+
get allRowsSelected() {
|
|
336
|
+
return this._registry.get(this._allSelected);
|
|
337
|
+
}
|
|
350
338
|
get selectionMode() {
|
|
351
339
|
return this._selectionMode;
|
|
352
340
|
}
|
|
353
341
|
getSelectedRows = () => {
|
|
354
|
-
const selectedIds = this._validSelectedIds
|
|
355
|
-
return this._rows.
|
|
342
|
+
const selectedIds = this._registry.get(this._validSelectedIds);
|
|
343
|
+
return this._registry.get(this._rows).filter((row) => selectedIds.has(row.id));
|
|
356
344
|
};
|
|
357
345
|
isRowIndexSelected = (rowIndex) => {
|
|
358
|
-
const row = this._rows
|
|
359
|
-
return this._selection.
|
|
346
|
+
const row = this._registry.get(this._rows)[rowIndex];
|
|
347
|
+
return this._registry.get(this._selection).has(row.id);
|
|
360
348
|
};
|
|
361
349
|
isObjectSelected = (object) => {
|
|
362
|
-
return this._selection.
|
|
350
|
+
return this._registry.get(this._selection).has(object.id);
|
|
363
351
|
};
|
|
364
352
|
//
|
|
365
353
|
// Manipulation
|
|
366
354
|
//
|
|
367
355
|
toggleSelectionForRowIndex = (rowIndex) => {
|
|
368
|
-
const row = this._rows
|
|
369
|
-
const
|
|
356
|
+
const row = this._registry.get(this._rows)[rowIndex];
|
|
357
|
+
const currentSelection = this._registry.get(this._selection);
|
|
358
|
+
const newSelection = new Set(currentSelection);
|
|
370
359
|
if (newSelection.has(row.id)) {
|
|
371
360
|
newSelection.delete(row.id);
|
|
372
361
|
} else {
|
|
@@ -375,194 +364,38 @@ var SelectionModel = class extends Resource {
|
|
|
375
364
|
}
|
|
376
365
|
newSelection.add(row.id);
|
|
377
366
|
}
|
|
378
|
-
this._selection
|
|
367
|
+
this._registry.set(this._selection, newSelection);
|
|
379
368
|
};
|
|
380
369
|
setSelection = (mode) => {
|
|
381
370
|
switch (mode) {
|
|
382
371
|
case "all": {
|
|
383
|
-
this._selection
|
|
372
|
+
this._registry.set(this._selection, new Set(this._registry.get(this._rows).map((row) => row.id)));
|
|
384
373
|
break;
|
|
385
374
|
}
|
|
386
375
|
case "none": {
|
|
387
|
-
this._selection
|
|
376
|
+
this._registry.set(this._selection, /* @__PURE__ */ new Set());
|
|
388
377
|
break;
|
|
389
378
|
}
|
|
390
379
|
}
|
|
391
380
|
};
|
|
392
381
|
};
|
|
393
382
|
|
|
394
|
-
// src/model/table-sorting.ts
|
|
395
|
-
import { computed as computed2, signal as signal2 } from "@preact/signals-core";
|
|
396
|
-
import orderBy from "lodash.orderby";
|
|
397
|
-
import { FormatEnum, TypeEnum, getValue } from "@dxos/echo/internal";
|
|
398
|
-
import { formatForDisplay } from "@dxos/react-ui-form";
|
|
399
|
-
var TableSorting = class {
|
|
400
|
-
_view;
|
|
401
|
-
_projection;
|
|
402
|
-
_displayToDataIndex = /* @__PURE__ */ new Map();
|
|
403
|
-
_rows;
|
|
404
|
-
_localSort = signal2(void 0);
|
|
405
|
-
_isDirty;
|
|
406
|
-
sortedRows;
|
|
407
|
-
constructor(rows, _view, _projection) {
|
|
408
|
-
this._view = _view;
|
|
409
|
-
this._projection = _projection;
|
|
410
|
-
this._rows = rows;
|
|
411
|
-
this._isDirty = computed2(() => {
|
|
412
|
-
const local = this._localSort.value;
|
|
413
|
-
const viewSort = this._view.sort?.[0];
|
|
414
|
-
if (local?.type === "cleared") {
|
|
415
|
-
return viewSort !== void 0;
|
|
416
|
-
}
|
|
417
|
-
if (local?.type === "active") {
|
|
418
|
-
if (!viewSort) {
|
|
419
|
-
return true;
|
|
420
|
-
}
|
|
421
|
-
return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
|
|
422
|
-
}
|
|
423
|
-
return false;
|
|
424
|
-
});
|
|
425
|
-
this.sortedRows = this.initialiseSortedRows();
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* @reactive
|
|
429
|
-
* @returns Local sort if present, falls back to view sort.
|
|
430
|
-
*/
|
|
431
|
-
get sorting() {
|
|
432
|
-
const local = this._localSort.value;
|
|
433
|
-
if (local?.type === "cleared") {
|
|
434
|
-
return void 0;
|
|
435
|
-
}
|
|
436
|
-
if (local?.type === "active") {
|
|
437
|
-
return local.sort;
|
|
438
|
-
}
|
|
439
|
-
return this._view.sort?.[0];
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* @reactive
|
|
443
|
-
* @returns Whether local sort differs from view sort.
|
|
444
|
-
*/
|
|
445
|
-
get isDirty() {
|
|
446
|
-
return this._isDirty.value;
|
|
447
|
-
}
|
|
448
|
-
getDataIndex(displayIndex) {
|
|
449
|
-
return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
|
|
450
|
-
}
|
|
451
|
-
setSort(fieldId, direction) {
|
|
452
|
-
this._localSort.value = {
|
|
453
|
-
type: "active",
|
|
454
|
-
sort: {
|
|
455
|
-
fieldId,
|
|
456
|
-
direction
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
toggleSort(fieldId) {
|
|
461
|
-
if (!this.sorting || this.sorting.fieldId !== fieldId) {
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
switch (this.sorting.direction) {
|
|
465
|
-
case "asc": {
|
|
466
|
-
this.setSort(fieldId, "desc");
|
|
467
|
-
break;
|
|
468
|
-
}
|
|
469
|
-
case "desc": {
|
|
470
|
-
this.setSort(fieldId, "asc");
|
|
471
|
-
break;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
clearSort() {
|
|
476
|
-
this._localSort.value = {
|
|
477
|
-
type: "cleared"
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
save() {
|
|
481
|
-
if (this._localSort.value !== void 0) {
|
|
482
|
-
if (this._localSort.value.type === "active") {
|
|
483
|
-
this._view.sort = [
|
|
484
|
-
this._localSort.value.sort
|
|
485
|
-
];
|
|
486
|
-
} else {
|
|
487
|
-
this._view.sort = [];
|
|
488
|
-
}
|
|
489
|
-
this._localSort.value = void 0;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
//
|
|
493
|
-
// Initialisation.
|
|
494
|
-
//
|
|
495
|
-
initialiseSortedRows() {
|
|
496
|
-
return computed2(() => {
|
|
497
|
-
this._displayToDataIndex.clear();
|
|
498
|
-
const sort = this.sorting;
|
|
499
|
-
if (!sort) {
|
|
500
|
-
return this._rows.value;
|
|
501
|
-
}
|
|
502
|
-
const field = this._projection.fields.find((f) => f.id === sort.fieldId);
|
|
503
|
-
if (!field) {
|
|
504
|
-
return this._rows.value;
|
|
505
|
-
}
|
|
506
|
-
const { props } = this._projection.getFieldProjection(field.id);
|
|
507
|
-
const dataWithIndices = this._rows.value.map((item, index) => {
|
|
508
|
-
const sortValue = this.getSortValue(props, field, item);
|
|
509
|
-
const isEmpty = !(props.type === TypeEnum.Boolean) && (sortValue == null || sortValue === "");
|
|
510
|
-
return {
|
|
511
|
-
item,
|
|
512
|
-
index,
|
|
513
|
-
value: sortValue,
|
|
514
|
-
isEmpty
|
|
515
|
-
};
|
|
516
|
-
});
|
|
517
|
-
const ordered = orderBy(dataWithIndices, [
|
|
518
|
-
"isEmpty",
|
|
519
|
-
"value"
|
|
520
|
-
], [
|
|
521
|
-
"asc",
|
|
522
|
-
sort.direction
|
|
523
|
-
]);
|
|
524
|
-
ordered.forEach(({ index: dataIndex }, displayIndex) => {
|
|
525
|
-
if (displayIndex !== dataIndex) {
|
|
526
|
-
this._displayToDataIndex.set(displayIndex, dataIndex);
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
return ordered.map(({ item }) => item);
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
getSortValue(props, field, item) {
|
|
533
|
-
const { type, format } = props;
|
|
534
|
-
const value = getValue(item, field.path);
|
|
535
|
-
if (type === TypeEnum.Boolean) {
|
|
536
|
-
return !!value;
|
|
537
|
-
}
|
|
538
|
-
if (type === TypeEnum.Number) {
|
|
539
|
-
return value;
|
|
540
|
-
}
|
|
541
|
-
if (value == null) {
|
|
542
|
-
return value;
|
|
543
|
-
}
|
|
544
|
-
if (format === FormatEnum.SingleSelect) {
|
|
545
|
-
const options = props.options;
|
|
546
|
-
if (!options) {
|
|
547
|
-
return void 0;
|
|
548
|
-
}
|
|
549
|
-
const option = options.find((option2) => option2.id === value);
|
|
550
|
-
return option ? options.indexOf(option) : void 0;
|
|
551
|
-
}
|
|
552
|
-
if (format === FormatEnum.Ref && field.referencePath) {
|
|
553
|
-
const refValue = getValue(value.target, field.referencePath);
|
|
554
|
-
return refValue;
|
|
555
|
-
}
|
|
556
|
-
return formatForDisplay({
|
|
557
|
-
type,
|
|
558
|
-
format,
|
|
559
|
-
value
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
};
|
|
563
|
-
|
|
564
383
|
// src/model/table-model.ts
|
|
565
384
|
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
|
|
385
|
+
var createEchoChangeCallback = (table) => ({
|
|
386
|
+
table: (mutate) => Obj.change(table, (mutableTable) => mutate(mutableTable)),
|
|
387
|
+
row: (row, mutate) => {
|
|
388
|
+
if (Obj.isObject(row)) {
|
|
389
|
+
Obj.change(row, (mutableRow) => mutate(mutableRow));
|
|
390
|
+
} else {
|
|
391
|
+
mutate(row);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
var createDirectChangeCallback = (table) => ({
|
|
396
|
+
table: (mutate) => mutate(table),
|
|
397
|
+
row: (row, mutate) => mutate(row)
|
|
398
|
+
});
|
|
566
399
|
var defaultFeatures = {
|
|
567
400
|
selection: {
|
|
568
401
|
enabled: true,
|
|
@@ -572,110 +405,206 @@ var defaultFeatures = {
|
|
|
572
405
|
schemaEditable: false
|
|
573
406
|
};
|
|
574
407
|
var TableModel = class extends Resource2 {
|
|
575
|
-
|
|
408
|
+
_registry;
|
|
409
|
+
_object;
|
|
576
410
|
_projection;
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
row: 0,
|
|
581
|
-
col: 0
|
|
582
|
-
},
|
|
583
|
-
end: {
|
|
584
|
-
row: 0,
|
|
585
|
-
col: 0
|
|
586
|
-
}
|
|
587
|
-
});
|
|
411
|
+
_db;
|
|
412
|
+
_change;
|
|
413
|
+
_visibleRange;
|
|
588
414
|
_onInsertRow;
|
|
589
415
|
_onDeleteRows;
|
|
590
|
-
|
|
416
|
+
_onColumnDelete;
|
|
591
417
|
_onCellUpdate;
|
|
592
418
|
_onRowOrderChange;
|
|
593
419
|
_onRowAction;
|
|
594
420
|
_rowActions;
|
|
595
421
|
_features;
|
|
596
|
-
_rows
|
|
597
|
-
_draftRows
|
|
422
|
+
_rows;
|
|
423
|
+
_draftRows;
|
|
424
|
+
// In-memory sort state - changes are local until saved.
|
|
425
|
+
_inMemorySort;
|
|
426
|
+
// Derived atom for persisted sort from view.query.ast.
|
|
427
|
+
_persistedSort;
|
|
428
|
+
// Derived atom for current sort (in-memory takes precedence over persisted).
|
|
598
429
|
_sorting;
|
|
430
|
+
// Derived atom for sorted rows (used by rows getter and SelectionModel).
|
|
431
|
+
_sortedRows;
|
|
432
|
+
// Derived atom for viewDirty state.
|
|
433
|
+
_viewDirty;
|
|
599
434
|
_pinnedRows;
|
|
600
435
|
_selection;
|
|
601
436
|
_columnMeta;
|
|
602
|
-
|
|
437
|
+
// Counter atom that increments when cells are updated - allows UI to react to cell changes.
|
|
438
|
+
_cellUpdateCounter;
|
|
439
|
+
constructor({ registry, object, projection, db, change, features = {}, initialSelection = [], pinnedRows = {
|
|
603
440
|
top: [],
|
|
604
441
|
bottom: []
|
|
605
|
-
}, rowActions = [], onCellUpdate,
|
|
442
|
+
}, rowActions = [], onCellUpdate, onColumnDelete, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
|
|
606
443
|
super();
|
|
607
|
-
this.
|
|
608
|
-
this.
|
|
444
|
+
this._registry = registry;
|
|
445
|
+
this._object = object;
|
|
446
|
+
this._projection = projection;
|
|
609
447
|
this._projection.normalizeView();
|
|
448
|
+
this._db = db;
|
|
449
|
+
this._change = change ?? createEchoChangeCallback(object);
|
|
610
450
|
this._features = {
|
|
611
451
|
...defaultFeatures,
|
|
612
452
|
...features
|
|
613
453
|
};
|
|
614
454
|
invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
|
|
615
455
|
F: __dxlog_file,
|
|
616
|
-
L:
|
|
456
|
+
L: 197,
|
|
617
457
|
S: this,
|
|
618
458
|
A: [
|
|
619
459
|
"!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
|
|
620
460
|
"'Single selection is not compatible with editable tables.'"
|
|
621
461
|
]
|
|
622
462
|
});
|
|
623
|
-
this.
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
463
|
+
this._visibleRange = Atom2.make({
|
|
464
|
+
start: {
|
|
465
|
+
row: 0,
|
|
466
|
+
col: 0
|
|
467
|
+
},
|
|
468
|
+
end: {
|
|
469
|
+
row: 0,
|
|
470
|
+
col: 0
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
this._rows = Atom2.make([]);
|
|
474
|
+
this._draftRows = Atom2.make([]);
|
|
475
|
+
this._inMemorySort = Atom2.make(void 0);
|
|
476
|
+
this._cellUpdateCounter = Atom2.make(0);
|
|
477
|
+
this._persistedSort = Atom2.make((_get) => {
|
|
478
|
+
const viewSnapshot = Obj.getSnapshot(this.view);
|
|
479
|
+
const ast = viewSnapshot.query.ast;
|
|
480
|
+
const orders = extractOrder(ast);
|
|
481
|
+
if (orders && orders.length > 0) {
|
|
482
|
+
const firstOrder = orders[0];
|
|
483
|
+
if (firstOrder.kind === "property") {
|
|
484
|
+
const field = this._projection.getFields().find((f) => f.path === firstOrder.property);
|
|
485
|
+
if (field) {
|
|
486
|
+
return {
|
|
487
|
+
fieldId: field.id,
|
|
488
|
+
direction: firstOrder.direction
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return void 0;
|
|
494
|
+
});
|
|
495
|
+
this._sorting = Atom2.make((get) => {
|
|
496
|
+
const inMemorySort = get(this._inMemorySort);
|
|
497
|
+
return inMemorySort ?? get(this._persistedSort);
|
|
498
|
+
});
|
|
499
|
+
this._sortedRows = Atom2.make((get) => {
|
|
500
|
+
const rows = get(this._rows);
|
|
501
|
+
const sort = get(this._sorting);
|
|
502
|
+
if (!sort || rows.length === 0) {
|
|
503
|
+
return rows;
|
|
504
|
+
}
|
|
505
|
+
const field = this._projection.getFields().find((f) => f.id === sort.fieldId);
|
|
506
|
+
if (!field) {
|
|
507
|
+
return rows;
|
|
508
|
+
}
|
|
509
|
+
const fieldProjection = this._projection.getFieldProjection(field.id);
|
|
510
|
+
const sorted = [
|
|
511
|
+
...rows
|
|
512
|
+
].sort((a, b) => {
|
|
513
|
+
const aValue = getValue(a, field.path);
|
|
514
|
+
const bValue = getValue(b, field.path);
|
|
515
|
+
return compareValues(aValue, bValue, fieldProjection.props.format, sort.direction);
|
|
516
|
+
});
|
|
517
|
+
return sorted;
|
|
518
|
+
});
|
|
519
|
+
this._selection = new SelectionModel(this._registry, this._sortedRows, this._features.selection.mode ?? "multiple", initialSelection, () => this._onRowOrderChange?.());
|
|
520
|
+
this._viewDirty = Atom2.make((get) => {
|
|
521
|
+
const inMemorySort = get(this._inMemorySort);
|
|
522
|
+
if (!inMemorySort) {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
const persisted = get(this._persistedSort);
|
|
526
|
+
if (!persisted) {
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
return inMemorySort.fieldId !== persisted.fieldId || inMemorySort.direction !== persisted.direction;
|
|
530
|
+
});
|
|
629
531
|
this._pinnedRows = pinnedRows;
|
|
630
532
|
this._rowActions = rowActions;
|
|
631
533
|
this._onInsertRow = onInsertRow;
|
|
632
534
|
this._onDeleteRows = onDeleteRows;
|
|
633
|
-
this.
|
|
535
|
+
this._onColumnDelete = onColumnDelete;
|
|
634
536
|
this._onCellUpdate = onCellUpdate;
|
|
635
537
|
this._onRowOrderChange = onRowOrderChange;
|
|
636
538
|
this._onRowAction = onRowAction;
|
|
637
539
|
}
|
|
638
540
|
get id() {
|
|
639
|
-
return
|
|
541
|
+
return Obj.getDXN(this._object).toString();
|
|
640
542
|
}
|
|
641
543
|
get view() {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
get table() {
|
|
645
|
-
invariant(this._table, "Model not initialized", {
|
|
544
|
+
const view = this._object.view.target;
|
|
545
|
+
invariant(view, "Table model not initialized", {
|
|
646
546
|
F: __dxlog_file,
|
|
647
|
-
L:
|
|
547
|
+
L: 308,
|
|
648
548
|
S: this,
|
|
649
549
|
A: [
|
|
650
|
-
"
|
|
651
|
-
"'
|
|
550
|
+
"view",
|
|
551
|
+
"'Table model not initialized'"
|
|
652
552
|
]
|
|
653
553
|
});
|
|
654
|
-
return
|
|
554
|
+
return view;
|
|
555
|
+
}
|
|
556
|
+
get table() {
|
|
557
|
+
return this._object;
|
|
655
558
|
}
|
|
656
559
|
get projection() {
|
|
657
560
|
return this._projection;
|
|
658
561
|
}
|
|
562
|
+
get db() {
|
|
563
|
+
return this._db;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Atom for reactive access to rows with in-memory sorting applied.
|
|
567
|
+
*/
|
|
659
568
|
get rows() {
|
|
660
|
-
return this.
|
|
569
|
+
return this._sortedRows;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Gets rows with in-memory sorting applied.
|
|
573
|
+
* In-memory sort is local to this instance until saved.
|
|
574
|
+
*/
|
|
575
|
+
getRows() {
|
|
576
|
+
return this._registry.get(this._sortedRows);
|
|
577
|
+
}
|
|
578
|
+
/** Atom for reactive access to cell changes. */
|
|
579
|
+
get cellUpdate() {
|
|
580
|
+
return this._cellUpdateCounter;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Change a row using the configured change callback.
|
|
584
|
+
* Use this instead of directly mutating to ensure consistent mutation handling.
|
|
585
|
+
*/
|
|
586
|
+
changeRow(row, mutate) {
|
|
587
|
+
this._change.row(row, mutate);
|
|
661
588
|
}
|
|
662
589
|
get features() {
|
|
663
590
|
return this._features;
|
|
664
591
|
}
|
|
665
592
|
/**
|
|
666
|
-
*
|
|
593
|
+
* Gets the current sort state.
|
|
594
|
+
* Priority: in-memory sort (local changes) > persisted sort (from query AST).
|
|
667
595
|
*/
|
|
668
|
-
|
|
669
|
-
return this._sorting;
|
|
596
|
+
getSorting() {
|
|
597
|
+
return this._registry.get(this._sorting);
|
|
670
598
|
}
|
|
671
599
|
/**
|
|
672
600
|
* Gets the row data at the specified display index.
|
|
673
601
|
*/
|
|
674
602
|
getRowAt(displayIndex) {
|
|
675
|
-
|
|
603
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
604
|
+
if (displayIndex < 0 || displayIndex >= sortedRows.length) {
|
|
676
605
|
return void 0;
|
|
677
606
|
}
|
|
678
|
-
return
|
|
607
|
+
return sortedRows[displayIndex];
|
|
679
608
|
}
|
|
680
609
|
get pinnedRows() {
|
|
681
610
|
return this._pinnedRows;
|
|
@@ -683,7 +612,7 @@ var TableModel = class extends Resource2 {
|
|
|
683
612
|
get columnMeta() {
|
|
684
613
|
invariant(this._columnMeta, void 0, {
|
|
685
614
|
F: __dxlog_file,
|
|
686
|
-
L:
|
|
615
|
+
L: 381,
|
|
687
616
|
S: this,
|
|
688
617
|
A: [
|
|
689
618
|
"this._columnMeta",
|
|
@@ -695,10 +624,6 @@ var TableModel = class extends Resource2 {
|
|
|
695
624
|
get selection() {
|
|
696
625
|
return this._selection;
|
|
697
626
|
}
|
|
698
|
-
/** @reactive */
|
|
699
|
-
get isViewDirty() {
|
|
700
|
-
return this.sorting.isDirty;
|
|
701
|
-
}
|
|
702
627
|
get rowActions() {
|
|
703
628
|
return this._rowActions;
|
|
704
629
|
}
|
|
@@ -706,24 +631,23 @@ var TableModel = class extends Resource2 {
|
|
|
706
631
|
// Initialisation
|
|
707
632
|
//
|
|
708
633
|
async _open() {
|
|
709
|
-
|
|
710
|
-
invariant(Obj2.instanceOf(schema_exports.Table, presentation), void 0, {
|
|
711
|
-
F: __dxlog_file,
|
|
712
|
-
L: 248,
|
|
713
|
-
S: this,
|
|
714
|
-
A: [
|
|
715
|
-
"Obj.instanceOf(Table.Table, presentation)",
|
|
716
|
-
""
|
|
717
|
-
]
|
|
718
|
-
});
|
|
719
|
-
this._table = presentation;
|
|
634
|
+
await this._object.view.load();
|
|
720
635
|
this.initializeColumnMeta();
|
|
721
636
|
this.initializeEffects();
|
|
722
637
|
await this._selection.open(this._ctx);
|
|
723
638
|
}
|
|
724
639
|
initializeColumnMeta() {
|
|
725
|
-
this.
|
|
726
|
-
|
|
640
|
+
invariant(this._object.view.target, "View must be loaded before initializing column meta", {
|
|
641
|
+
F: __dxlog_file,
|
|
642
|
+
L: 405,
|
|
643
|
+
S: this,
|
|
644
|
+
A: [
|
|
645
|
+
"this._object.view.target",
|
|
646
|
+
"'View must be loaded before initializing column meta'"
|
|
647
|
+
]
|
|
648
|
+
});
|
|
649
|
+
this._columnMeta = Atom2.make((get) => {
|
|
650
|
+
const fields = get(this._projection.fields);
|
|
727
651
|
const meta = Object.fromEntries(fields.map((field, index) => [
|
|
728
652
|
index,
|
|
729
653
|
{
|
|
@@ -749,49 +673,62 @@ var TableModel = class extends Resource2 {
|
|
|
749
673
|
});
|
|
750
674
|
}
|
|
751
675
|
initializeEffects() {
|
|
752
|
-
const
|
|
753
|
-
touch(this.sorting.sortedRows.value);
|
|
676
|
+
const rowsUnsubscribe = this._registry.subscribe(this._rows, () => {
|
|
754
677
|
this._onRowOrderChange?.();
|
|
755
678
|
});
|
|
756
|
-
this._ctx.onDispose(
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
679
|
+
this._ctx.onDispose(rowsUnsubscribe);
|
|
680
|
+
const rowSubscriptions = /* @__PURE__ */ new Map();
|
|
681
|
+
const visibleRangeUnsubscribe = this._registry.subscribe(this._visibleRange, () => {
|
|
682
|
+
for (const [id, unsub] of rowSubscriptions) {
|
|
683
|
+
unsub();
|
|
684
|
+
rowSubscriptions.delete(id);
|
|
685
|
+
}
|
|
686
|
+
const { start, end } = this._registry.get(this._visibleRange);
|
|
687
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
688
|
+
for (let row = start.row; row <= end.row && row < sortedRows.length; row++) {
|
|
689
|
+
const obj = sortedRows[row];
|
|
690
|
+
if (Obj.isObject(obj) && !rowSubscriptions.has(obj.id)) {
|
|
691
|
+
const unsub = Obj.subscribe(obj, () => {
|
|
692
|
+
this._registry.set(this._cellUpdateCounter, this._registry.get(this._cellUpdateCounter) + 1);
|
|
693
|
+
this._onCellUpdate?.({
|
|
694
|
+
row,
|
|
695
|
+
col: start.col,
|
|
696
|
+
plane: "grid"
|
|
697
|
+
});
|
|
768
698
|
});
|
|
769
|
-
|
|
699
|
+
rowSubscriptions.set(obj.id, unsub);
|
|
700
|
+
}
|
|
770
701
|
}
|
|
771
|
-
return () => rowEffects.forEach((cleanup) => cleanup());
|
|
772
702
|
});
|
|
773
|
-
this._ctx.onDispose(
|
|
774
|
-
|
|
775
|
-
|
|
703
|
+
this._ctx.onDispose(() => {
|
|
704
|
+
visibleRangeUnsubscribe();
|
|
705
|
+
for (const unsub of rowSubscriptions.values()) {
|
|
706
|
+
unsub();
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
const draftRowsUnsubscribe = this._registry.subscribe(this._draftRows, () => {
|
|
776
710
|
this._onRowOrderChange?.();
|
|
777
711
|
});
|
|
778
|
-
this._ctx.onDispose(
|
|
712
|
+
this._ctx.onDispose(draftRowsUnsubscribe);
|
|
779
713
|
}
|
|
780
714
|
//
|
|
781
715
|
// Data
|
|
782
716
|
//
|
|
783
717
|
setRows = (obj) => {
|
|
784
|
-
this._rows
|
|
718
|
+
this._registry.set(this._rows, obj);
|
|
785
719
|
};
|
|
786
|
-
getRowCount = () => this.
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
// TODO(ZaymonFC): Return .value instead of exposing the signal.
|
|
720
|
+
getRowCount = () => this._registry.get(this._sortedRows).length;
|
|
721
|
+
getDraftRowCount() {
|
|
722
|
+
return this._registry.get(this._draftRows).length;
|
|
723
|
+
}
|
|
724
|
+
/** Atom for reactive access to draft rows. */
|
|
792
725
|
get draftRows() {
|
|
793
726
|
return this._draftRows;
|
|
794
727
|
}
|
|
728
|
+
/** Gets the current draft rows. */
|
|
729
|
+
getDraftRows() {
|
|
730
|
+
return this._registry.get(this._draftRows);
|
|
731
|
+
}
|
|
795
732
|
/**
|
|
796
733
|
* Checks if a specific field path has validation errors for a given draft row.
|
|
797
734
|
* @param draftRowIndex - The index of the draft row to check
|
|
@@ -799,17 +736,17 @@ var TableModel = class extends Resource2 {
|
|
|
799
736
|
* @returns true if the field has validation errors, false otherwise
|
|
800
737
|
*/
|
|
801
738
|
hasDraftRowValidationError(draftRowIndex, fieldPath) {
|
|
802
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
739
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
803
740
|
return false;
|
|
804
741
|
}
|
|
805
|
-
const draftRow = this._draftRows
|
|
742
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
806
743
|
const validationErrors = draftRow.validationErrors || [];
|
|
807
744
|
return validationErrors.some((error) => error.path === fieldPath);
|
|
808
745
|
}
|
|
809
|
-
getColumnCount = () => this._projection?.
|
|
746
|
+
getColumnCount = () => this._projection?.getFields().length ?? 0;
|
|
810
747
|
insertRow = () => {
|
|
811
748
|
const result = this._onInsertRow?.();
|
|
812
|
-
if (result === "draft" && this._draftRows.
|
|
749
|
+
if (result === "draft" && this._registry.get(this._draftRows).length === 0) {
|
|
813
750
|
this.createDraftRow();
|
|
814
751
|
}
|
|
815
752
|
return result ?? "final";
|
|
@@ -827,16 +764,16 @@ var TableModel = class extends Resource2 {
|
|
|
827
764
|
valid: validationErrors.length === 0,
|
|
828
765
|
validationErrors
|
|
829
766
|
};
|
|
830
|
-
this._draftRows
|
|
831
|
-
...this._draftRows
|
|
767
|
+
this._registry.set(this._draftRows, [
|
|
768
|
+
...this._registry.get(this._draftRows),
|
|
832
769
|
draftRow
|
|
833
|
-
];
|
|
770
|
+
]);
|
|
834
771
|
}
|
|
835
772
|
validateDraftRow(draftRowIndex) {
|
|
836
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
773
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
837
774
|
return;
|
|
838
775
|
}
|
|
839
|
-
const draftRow = this._draftRows
|
|
776
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
840
777
|
const validationErrors = this.validateDraftRowData(draftRow.data);
|
|
841
778
|
const updatedDraftRow = {
|
|
842
779
|
...draftRow,
|
|
@@ -844,80 +781,82 @@ var TableModel = class extends Resource2 {
|
|
|
844
781
|
validationErrors
|
|
845
782
|
};
|
|
846
783
|
const newDraftRows = [
|
|
847
|
-
...this._draftRows
|
|
784
|
+
...this._registry.get(this._draftRows)
|
|
848
785
|
];
|
|
849
786
|
newDraftRows[draftRowIndex] = updatedDraftRow;
|
|
850
|
-
this._draftRows
|
|
787
|
+
this._registry.set(this._draftRows, newDraftRows);
|
|
851
788
|
}
|
|
852
789
|
validateDraftRowData(data) {
|
|
853
790
|
const schema = toEffectSchema(this._projection.baseSchema);
|
|
854
791
|
return validateSchema(schema, data) || [];
|
|
855
792
|
}
|
|
856
793
|
commitDraftRow = (draftRowIndex) => {
|
|
857
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
794
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
858
795
|
return false;
|
|
859
796
|
}
|
|
860
|
-
const draftRow = this._draftRows
|
|
797
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
861
798
|
if (!draftRow.valid) {
|
|
862
799
|
return false;
|
|
863
800
|
}
|
|
864
801
|
const insertRowResult = this._onInsertRow?.(draftRow.data);
|
|
865
802
|
if (insertRowResult === "final") {
|
|
866
|
-
const newDraftRows = this._draftRows.
|
|
867
|
-
this._draftRows
|
|
803
|
+
const newDraftRows = this._registry.get(this._draftRows).filter((_, index) => index !== draftRowIndex);
|
|
804
|
+
this._registry.set(this._draftRows, newDraftRows);
|
|
868
805
|
}
|
|
869
806
|
return insertRowResult === "final";
|
|
870
807
|
};
|
|
871
808
|
deleteRow = (rowIndex) => {
|
|
872
|
-
const
|
|
873
|
-
const obj =
|
|
809
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
810
|
+
const obj = sortedRows[rowIndex];
|
|
874
811
|
const objectsToDelete = [];
|
|
875
|
-
if (this.features.selection.enabled && this._selection.hasSelection
|
|
812
|
+
if (this.features.selection.enabled && this._selection.hasSelection) {
|
|
876
813
|
const selectedRows = this._selection.getSelectedRows();
|
|
877
814
|
objectsToDelete.push(...selectedRows);
|
|
878
|
-
} else {
|
|
815
|
+
} else if (obj) {
|
|
879
816
|
objectsToDelete.push(obj);
|
|
880
817
|
}
|
|
881
|
-
|
|
818
|
+
if (objectsToDelete.length > 0) {
|
|
819
|
+
this._onDeleteRows?.(rowIndex, objectsToDelete);
|
|
820
|
+
}
|
|
882
821
|
};
|
|
883
822
|
handleRowAction = (actionId, rowIndex) => {
|
|
884
823
|
if (!this._onRowAction) {
|
|
885
824
|
return;
|
|
886
825
|
}
|
|
887
|
-
const
|
|
888
|
-
const data =
|
|
826
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
827
|
+
const data = sortedRows[rowIndex];
|
|
889
828
|
if (data) {
|
|
890
829
|
this._onRowAction(actionId, data);
|
|
891
830
|
}
|
|
892
831
|
};
|
|
893
832
|
getCellData = (cell) => {
|
|
894
833
|
const { col, row, plane } = cell;
|
|
895
|
-
const fields = this._projection?.
|
|
834
|
+
const fields = this._projection?.getFields() ?? [];
|
|
896
835
|
if (col < 0 || col >= fields.length) {
|
|
897
836
|
return void 0;
|
|
898
837
|
}
|
|
899
838
|
const field = fields[col];
|
|
900
839
|
let value;
|
|
901
840
|
if (plane === "frozenRowsEnd") {
|
|
902
|
-
if (row >= 0 && row < this._draftRows.
|
|
903
|
-
value =
|
|
841
|
+
if (row >= 0 && row < this._registry.get(this._draftRows).length) {
|
|
842
|
+
value = getValue(this._registry.get(this._draftRows)[row].data, field.path);
|
|
904
843
|
} else {
|
|
905
844
|
return void 0;
|
|
906
845
|
}
|
|
907
846
|
} else {
|
|
908
|
-
const
|
|
909
|
-
value =
|
|
847
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
848
|
+
value = getValue(sortedRows[row], field.path);
|
|
910
849
|
}
|
|
911
850
|
if (value == null) {
|
|
912
851
|
return "";
|
|
913
852
|
}
|
|
914
853
|
const { props } = this._projection.getFieldProjection(field.id);
|
|
915
854
|
switch (props.format) {
|
|
916
|
-
case
|
|
855
|
+
case Format2.TypeFormat.Ref: {
|
|
917
856
|
if (!field.referencePath) {
|
|
918
857
|
return "";
|
|
919
858
|
}
|
|
920
|
-
return
|
|
859
|
+
return getValue(value.target, field.referencePath);
|
|
921
860
|
}
|
|
922
861
|
default: {
|
|
923
862
|
return formatForEditing({
|
|
@@ -929,7 +868,7 @@ var TableModel = class extends Resource2 {
|
|
|
929
868
|
}
|
|
930
869
|
};
|
|
931
870
|
validateCellData = async ({ col, row, plane }, value) => {
|
|
932
|
-
const fields = this._projection?.
|
|
871
|
+
const fields = this._projection?.getFields() ?? [];
|
|
933
872
|
if (col < 0 || col >= fields.length) {
|
|
934
873
|
return {
|
|
935
874
|
valid: false,
|
|
@@ -941,14 +880,14 @@ var TableModel = class extends Resource2 {
|
|
|
941
880
|
const transformedValue = editorTextToCellValue(props, value);
|
|
942
881
|
const isDraftRow = plane === "frozenRowsEnd";
|
|
943
882
|
if (isDraftRow) {
|
|
944
|
-
const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.
|
|
883
|
+
const isInvalidDraftRowIndex = row < 0 || row >= this._registry.get(this._draftRows).length;
|
|
945
884
|
if (isInvalidDraftRowIndex) {
|
|
946
885
|
return {
|
|
947
886
|
valid: false,
|
|
948
887
|
error: "Invalid draft row index"
|
|
949
888
|
};
|
|
950
889
|
}
|
|
951
|
-
const draftRow = this._draftRows
|
|
890
|
+
const draftRow = this._registry.get(this._draftRows)[row];
|
|
952
891
|
const snapshot = {
|
|
953
892
|
...draftRow.data
|
|
954
893
|
};
|
|
@@ -967,23 +906,24 @@ var TableModel = class extends Resource2 {
|
|
|
967
906
|
valid: true
|
|
968
907
|
};
|
|
969
908
|
} else {
|
|
970
|
-
const
|
|
971
|
-
const currentRow = this._rows.value[rowIdx];
|
|
909
|
+
const currentRow = this._registry.get(this._rows)[row];
|
|
972
910
|
invariant(currentRow, "Invalid row index", {
|
|
973
911
|
F: __dxlog_file,
|
|
974
|
-
L:
|
|
912
|
+
L: 693,
|
|
975
913
|
S: this,
|
|
976
914
|
A: [
|
|
977
915
|
"currentRow",
|
|
978
916
|
"'Invalid row index'"
|
|
979
917
|
]
|
|
980
918
|
});
|
|
981
|
-
const snapshot =
|
|
919
|
+
const snapshot = {
|
|
920
|
+
...getSnapshot(currentRow)
|
|
921
|
+
};
|
|
982
922
|
setValue(snapshot, field.path, transformedValue);
|
|
983
|
-
const schema = getSchema(currentRow);
|
|
923
|
+
const schema = Obj.getSchema(currentRow);
|
|
984
924
|
invariant(schema, void 0, {
|
|
985
925
|
F: __dxlog_file,
|
|
986
|
-
L:
|
|
926
|
+
L: 699,
|
|
987
927
|
S: this,
|
|
988
928
|
A: [
|
|
989
929
|
"schema",
|
|
@@ -995,7 +935,7 @@ var TableModel = class extends Resource2 {
|
|
|
995
935
|
const error = validationResult[0];
|
|
996
936
|
invariant(error.path === field.path, void 0, {
|
|
997
937
|
F: __dxlog_file,
|
|
998
|
-
L:
|
|
938
|
+
L: 704,
|
|
999
939
|
S: this,
|
|
1000
940
|
A: [
|
|
1001
941
|
"error.path === field.path",
|
|
@@ -1014,24 +954,27 @@ var TableModel = class extends Resource2 {
|
|
|
1014
954
|
};
|
|
1015
955
|
setCellData = (cell, value) => {
|
|
1016
956
|
const { col, row, plane } = cell;
|
|
1017
|
-
const fields = this._projection?.
|
|
957
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1018
958
|
if (col < 0 || col >= fields.length) {
|
|
1019
959
|
return;
|
|
1020
960
|
}
|
|
1021
961
|
const field = fields[col];
|
|
1022
962
|
const { props } = this._projection.getFieldProjection(field.id);
|
|
1023
963
|
const transformedValue = editorTextToCellValue(props, value);
|
|
1024
|
-
if (props.format ===
|
|
964
|
+
if (props.format === Format2.TypeFormat.Ref && !Obj.isObject(value)) {
|
|
1025
965
|
return;
|
|
1026
966
|
}
|
|
1027
967
|
if (plane === "frozenRowsEnd") {
|
|
1028
|
-
if (row >= 0 && row < this._draftRows.
|
|
1029
|
-
setValue(this._draftRows
|
|
968
|
+
if (row >= 0 && row < this._registry.get(this._draftRows).length) {
|
|
969
|
+
setValue(this._registry.get(this._draftRows)[row].data, field.path, transformedValue);
|
|
1030
970
|
this.validateDraftRow(row);
|
|
1031
971
|
}
|
|
1032
972
|
} else {
|
|
1033
|
-
const
|
|
1034
|
-
|
|
973
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
974
|
+
const rowData = sortedRows[row];
|
|
975
|
+
this._change.row(rowData, (mutableRow) => {
|
|
976
|
+
setValue(mutableRow, field.path, transformedValue);
|
|
977
|
+
});
|
|
1035
978
|
}
|
|
1036
979
|
};
|
|
1037
980
|
/**
|
|
@@ -1040,12 +983,15 @@ var TableModel = class extends Resource2 {
|
|
|
1040
983
|
* @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
|
|
1041
984
|
*/
|
|
1042
985
|
updateCellData({ col, row }, update) {
|
|
1043
|
-
const
|
|
1044
|
-
const fields = this._projection?.fields ?? [];
|
|
986
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1045
987
|
const field = fields[col];
|
|
1046
|
-
const
|
|
988
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
989
|
+
const rowData = sortedRows[row];
|
|
990
|
+
const value = getValue(rowData, field.path);
|
|
1047
991
|
const updatedValue = update(value);
|
|
1048
|
-
|
|
992
|
+
this._change.row(rowData, (mutableRow) => {
|
|
993
|
+
setValue(mutableRow, field.path, updatedValue);
|
|
994
|
+
});
|
|
1049
995
|
}
|
|
1050
996
|
/**
|
|
1051
997
|
* Gets the domain-appropriate cell type for a given cell position.
|
|
@@ -1079,21 +1025,23 @@ var TableModel = class extends Resource2 {
|
|
|
1079
1025
|
if (!this._projection) {
|
|
1080
1026
|
return;
|
|
1081
1027
|
}
|
|
1082
|
-
const field = this._projection?.
|
|
1083
|
-
if (field && this.
|
|
1084
|
-
this.
|
|
1028
|
+
const field = this._projection?.getFields().find((field2) => field2.id === fieldId);
|
|
1029
|
+
if (field && this._onColumnDelete) {
|
|
1030
|
+
this._onColumnDelete(field.id);
|
|
1085
1031
|
}
|
|
1086
1032
|
}
|
|
1087
1033
|
//
|
|
1088
1034
|
// Resize
|
|
1089
1035
|
//
|
|
1090
1036
|
setColumnWidth(columnIndex, width) {
|
|
1091
|
-
const fields = this._projection?.
|
|
1037
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1092
1038
|
if (columnIndex < fields.length) {
|
|
1093
1039
|
const newWidth = Math.max(0, width);
|
|
1094
1040
|
const field = fields[columnIndex];
|
|
1095
1041
|
if (field) {
|
|
1096
|
-
this.table
|
|
1042
|
+
this._change.table((mutableTable) => {
|
|
1043
|
+
mutableTable.sizes[field.path] = newWidth;
|
|
1044
|
+
});
|
|
1097
1045
|
}
|
|
1098
1046
|
}
|
|
1099
1047
|
}
|
|
@@ -1109,22 +1057,92 @@ var TableModel = class extends Resource2 {
|
|
|
1109
1057
|
this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
|
|
1110
1058
|
}
|
|
1111
1059
|
//
|
|
1112
|
-
//
|
|
1060
|
+
// Sort operations
|
|
1113
1061
|
//
|
|
1062
|
+
/**
|
|
1063
|
+
* Sets the sort order for a field in-memory (local to this instance).
|
|
1064
|
+
* Use saveView() to persist the sort to the view query.
|
|
1065
|
+
*/
|
|
1066
|
+
setSort(fieldId, direction) {
|
|
1067
|
+
const field = this._projection.getFields().find((f) => f.id === fieldId);
|
|
1068
|
+
if (!field) {
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
this._registry.set(this._inMemorySort, {
|
|
1072
|
+
fieldId,
|
|
1073
|
+
direction
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Toggles the sort direction for a field in-memory.
|
|
1078
|
+
*/
|
|
1079
|
+
toggleSort(fieldId) {
|
|
1080
|
+
const currentSort = this.getSorting();
|
|
1081
|
+
if (!currentSort || currentSort.fieldId !== fieldId) {
|
|
1082
|
+
this.setSort(fieldId, "asc");
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
const newDirection = currentSort.direction === "asc" ? "desc" : "asc";
|
|
1086
|
+
this.setSort(fieldId, newDirection);
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Clears the in-memory sort order.
|
|
1090
|
+
*/
|
|
1091
|
+
clearSort() {
|
|
1092
|
+
this._registry.set(this._inMemorySort, void 0);
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Saves the current in-memory sort to the view query AST.
|
|
1096
|
+
* This persists the sort so it becomes the default for all viewers.
|
|
1097
|
+
*/
|
|
1114
1098
|
saveView() {
|
|
1115
|
-
this.
|
|
1099
|
+
const view = this.view;
|
|
1100
|
+
const inMemorySort = this._registry.get(this._inMemorySort);
|
|
1101
|
+
const viewSnapshot = Obj.getSnapshot(view);
|
|
1102
|
+
const currentQuery = Query.fromAst(viewSnapshot.query.ast);
|
|
1103
|
+
const baseQuery = this._getBaseQuery(currentQuery);
|
|
1104
|
+
if (inMemorySort) {
|
|
1105
|
+
const field = this._projection.getFields().find((f) => f.id === inMemorySort.fieldId);
|
|
1106
|
+
if (field) {
|
|
1107
|
+
const newQuery = baseQuery.orderBy(Order.property(field.path, inMemorySort.direction));
|
|
1108
|
+
Obj.change(view, (v) => {
|
|
1109
|
+
v.query.ast = newQuery.ast;
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
} else {
|
|
1113
|
+
Obj.change(view, (v) => {
|
|
1114
|
+
v.query.ast = baseQuery.ast;
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
this._registry.set(this._inMemorySort, void 0);
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Extracts the base query without order clauses.
|
|
1121
|
+
*/
|
|
1122
|
+
_getBaseQuery(query) {
|
|
1123
|
+
const ast = query.ast;
|
|
1124
|
+
if (ast.type === "order") {
|
|
1125
|
+
return Query.fromAst(ast.query);
|
|
1126
|
+
}
|
|
1127
|
+
return query;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Checks if the view has unsaved changes (in-memory sort differs from persisted sort).
|
|
1131
|
+
*/
|
|
1132
|
+
getViewDirty() {
|
|
1133
|
+
return this._registry.get(this._viewDirty);
|
|
1116
1134
|
}
|
|
1117
1135
|
};
|
|
1118
1136
|
var editorTextToCellValue = (props, value) => {
|
|
1119
1137
|
switch (props.format) {
|
|
1120
|
-
case
|
|
1121
|
-
if (
|
|
1138
|
+
case Format2.TypeFormat.Ref: {
|
|
1139
|
+
if (Obj.isObject(value)) {
|
|
1122
1140
|
return Ref.make(value);
|
|
1123
1141
|
} else {
|
|
1124
1142
|
return value;
|
|
1125
1143
|
}
|
|
1126
1144
|
}
|
|
1127
|
-
case
|
|
1145
|
+
case Format2.TypeFormat.SingleSelect: {
|
|
1128
1146
|
const ids = extractTagIds(value);
|
|
1129
1147
|
if (ids && ids.length > 0) {
|
|
1130
1148
|
return ids[0];
|
|
@@ -1132,7 +1150,7 @@ var editorTextToCellValue = (props, value) => {
|
|
|
1132
1150
|
return value;
|
|
1133
1151
|
}
|
|
1134
1152
|
}
|
|
1135
|
-
case
|
|
1153
|
+
case Format2.TypeFormat.MultiSelect: {
|
|
1136
1154
|
const ids = extractTagIds(value);
|
|
1137
1155
|
return ids || value;
|
|
1138
1156
|
}
|
|
@@ -1146,104 +1164,40 @@ var editorTextToCellValue = (props, value) => {
|
|
|
1146
1164
|
}
|
|
1147
1165
|
};
|
|
1148
1166
|
|
|
1149
|
-
// src/model/modal-controller.ts
|
|
1150
|
-
import { signal as signal4 } from "@preact/signals-core";
|
|
1151
|
-
var ModalController = class {
|
|
1152
|
-
_state = signal4({
|
|
1153
|
-
type: "closed"
|
|
1154
|
-
});
|
|
1155
|
-
_triggerRef = {
|
|
1156
|
-
current: null
|
|
1157
|
-
};
|
|
1158
|
-
get state() {
|
|
1159
|
-
return this._state;
|
|
1160
|
-
}
|
|
1161
|
-
get trigger() {
|
|
1162
|
-
return this._triggerRef;
|
|
1163
|
-
}
|
|
1164
|
-
setTrigger = (trigger) => {
|
|
1165
|
-
this._triggerRef.current = trigger;
|
|
1166
|
-
};
|
|
1167
|
-
showRowMenu = (rowIndex) => {
|
|
1168
|
-
this._state.value = {
|
|
1169
|
-
type: "row",
|
|
1170
|
-
rowIndex
|
|
1171
|
-
};
|
|
1172
|
-
};
|
|
1173
|
-
showColumnMenu = (fieldId) => {
|
|
1174
|
-
this._state.value = {
|
|
1175
|
-
type: "column",
|
|
1176
|
-
fieldId
|
|
1177
|
-
};
|
|
1178
|
-
};
|
|
1179
|
-
showColumnCreator = () => {
|
|
1180
|
-
this._state.value = {
|
|
1181
|
-
type: "columnSettings",
|
|
1182
|
-
mode: {
|
|
1183
|
-
type: "create"
|
|
1184
|
-
}
|
|
1185
|
-
};
|
|
1186
|
-
};
|
|
1187
|
-
showReferencePanel = (targetId, schemaId) => {
|
|
1188
|
-
this._state.value = {
|
|
1189
|
-
type: "refPanel",
|
|
1190
|
-
targetId,
|
|
1191
|
-
typename: schemaId
|
|
1192
|
-
};
|
|
1193
|
-
};
|
|
1194
|
-
openColumnSettings = () => {
|
|
1195
|
-
if (this._state.value.type === "column") {
|
|
1196
|
-
const fieldId = this._state.value.fieldId;
|
|
1197
|
-
requestAnimationFrame(() => {
|
|
1198
|
-
this._state.value = {
|
|
1199
|
-
type: "columnSettings",
|
|
1200
|
-
mode: {
|
|
1201
|
-
type: "edit",
|
|
1202
|
-
fieldId
|
|
1203
|
-
}
|
|
1204
|
-
};
|
|
1205
|
-
});
|
|
1206
|
-
}
|
|
1207
|
-
};
|
|
1208
|
-
close = () => {
|
|
1209
|
-
this._state.value = {
|
|
1210
|
-
type: "closed"
|
|
1211
|
-
};
|
|
1212
|
-
};
|
|
1213
|
-
};
|
|
1214
|
-
|
|
1215
1167
|
// src/model/table-presentation.ts
|
|
1216
|
-
import {
|
|
1168
|
+
import { Atom as Atom3 } from "@effect-atom/atom-react";
|
|
1217
1169
|
import * as Predicate from "effect/Predicate";
|
|
1218
|
-
import { Obj as
|
|
1219
|
-
import {
|
|
1220
|
-
import { cellClassesForFieldType, formatForDisplay
|
|
1170
|
+
import { Obj as Obj2 } from "@dxos/echo";
|
|
1171
|
+
import { Format as Format3, TypeEnum, getValue as getValue2 } from "@dxos/echo/internal";
|
|
1172
|
+
import { cellClassesForFieldType, formatForDisplay } from "@dxos/react-ui-form";
|
|
1221
1173
|
import { toPlaneCellIndex } from "@dxos/react-ui-grid";
|
|
1222
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
1223
1174
|
import { VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
1175
|
+
import { mx } from "@dxos/ui-theme";
|
|
1224
1176
|
var TablePresentation = class {
|
|
1225
1177
|
model;
|
|
1178
|
+
_registry;
|
|
1226
1179
|
_visibleRange;
|
|
1227
1180
|
fieldProjectionCache = /* @__PURE__ */ new Map();
|
|
1228
|
-
constructor(
|
|
1229
|
-
start: {
|
|
1230
|
-
row: 0,
|
|
1231
|
-
col: 0
|
|
1232
|
-
},
|
|
1233
|
-
end: {
|
|
1234
|
-
row: 0,
|
|
1235
|
-
col: 0
|
|
1236
|
-
}
|
|
1237
|
-
})) {
|
|
1181
|
+
constructor(registry, model) {
|
|
1238
1182
|
this.model = model;
|
|
1239
|
-
this.
|
|
1183
|
+
this._registry = registry;
|
|
1184
|
+
this._visibleRange = Atom3.make({
|
|
1185
|
+
start: {
|
|
1186
|
+
row: 0,
|
|
1187
|
+
col: 0
|
|
1188
|
+
},
|
|
1189
|
+
end: {
|
|
1190
|
+
row: 0,
|
|
1191
|
+
col: 0
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1240
1194
|
}
|
|
1241
1195
|
getCells(range, plane) {
|
|
1242
1196
|
this.fieldProjectionCache.clear();
|
|
1243
1197
|
let cells;
|
|
1244
1198
|
switch (plane) {
|
|
1245
1199
|
case "grid":
|
|
1246
|
-
this._visibleRange
|
|
1200
|
+
this._registry.set(this._visibleRange, range);
|
|
1247
1201
|
cells = this.getMainGridCells(range);
|
|
1248
1202
|
break;
|
|
1249
1203
|
case "frozenRowsStart":
|
|
@@ -1295,7 +1249,7 @@ var TablePresentation = class {
|
|
|
1295
1249
|
const { props } = this.getFieldProjection(field.id);
|
|
1296
1250
|
const cell = {
|
|
1297
1251
|
get value() {
|
|
1298
|
-
const value =
|
|
1252
|
+
const value = getValue2(obj, field.path);
|
|
1299
1253
|
if (value == null) {
|
|
1300
1254
|
return "";
|
|
1301
1255
|
}
|
|
@@ -1303,19 +1257,19 @@ var TablePresentation = class {
|
|
|
1303
1257
|
return "";
|
|
1304
1258
|
}
|
|
1305
1259
|
switch (props.format) {
|
|
1306
|
-
case
|
|
1307
|
-
case
|
|
1308
|
-
case
|
|
1260
|
+
case Format3.TypeFormat.Boolean:
|
|
1261
|
+
case Format3.TypeFormat.SingleSelect:
|
|
1262
|
+
case Format3.TypeFormat.MultiSelect: {
|
|
1309
1263
|
return "";
|
|
1310
1264
|
}
|
|
1311
|
-
case
|
|
1265
|
+
case Format3.TypeFormat.Ref: {
|
|
1312
1266
|
if (!field.referencePath) {
|
|
1313
1267
|
return "";
|
|
1314
1268
|
}
|
|
1315
|
-
return
|
|
1269
|
+
return getValue2(value.target, field.referencePath);
|
|
1316
1270
|
}
|
|
1317
1271
|
default: {
|
|
1318
|
-
return
|
|
1272
|
+
return formatForDisplay({
|
|
1319
1273
|
type: props.type,
|
|
1320
1274
|
format: props.format,
|
|
1321
1275
|
value
|
|
@@ -1334,8 +1288,8 @@ var TablePresentation = class {
|
|
|
1334
1288
|
classes.push(rowSelectionClasses);
|
|
1335
1289
|
}
|
|
1336
1290
|
cell.className = mx(classes);
|
|
1337
|
-
if (props.type ===
|
|
1338
|
-
const targetArray =
|
|
1291
|
+
if (props.type === TypeEnum.Array) {
|
|
1292
|
+
const targetArray = getValue2(obj, field.path);
|
|
1339
1293
|
if (targetArray && Array.isArray(targetArray)) {
|
|
1340
1294
|
const getLabel = (value) => {
|
|
1341
1295
|
if (!value) {
|
|
@@ -1361,15 +1315,15 @@ var TablePresentation = class {
|
|
|
1361
1315
|
cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
|
|
1362
1316
|
}
|
|
1363
1317
|
}
|
|
1364
|
-
if (props.format ===
|
|
1365
|
-
const targetObj =
|
|
1318
|
+
if (props.format === Format3.TypeFormat.Ref && props.referenceSchema) {
|
|
1319
|
+
const targetObj = getValue2(obj, field.path)?.target;
|
|
1366
1320
|
if (targetObj) {
|
|
1367
|
-
const dxn =
|
|
1368
|
-
cell.accessoryHtml = `<div role="none" class="absolute
|
|
1321
|
+
const dxn = Obj2.getDXN(targetObj)?.toString();
|
|
1322
|
+
cell.accessoryHtml = `<div role="none" class="absolute end-0 inset-y-0 p-(--dx-grid-cell-content-padding-block)"><dx-anchor dxn=${dxn} class="dx-button w-6 aspect-square min-h-0" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-anchor></div>`;
|
|
1369
1323
|
}
|
|
1370
1324
|
}
|
|
1371
|
-
if (props.format ===
|
|
1372
|
-
const value =
|
|
1325
|
+
if (props.format === Format3.TypeFormat.Boolean) {
|
|
1326
|
+
const value = getValue2(obj, field.path);
|
|
1373
1327
|
cell.accessoryHtml = tableControls.switch.render({
|
|
1374
1328
|
colIndex,
|
|
1375
1329
|
rowIndex: displayIndex,
|
|
@@ -1377,8 +1331,8 @@ var TablePresentation = class {
|
|
|
1377
1331
|
});
|
|
1378
1332
|
cell.readonly = "no-text-select";
|
|
1379
1333
|
}
|
|
1380
|
-
if (props.format ===
|
|
1381
|
-
const value =
|
|
1334
|
+
if (props.format === Format3.TypeFormat.SingleSelect) {
|
|
1335
|
+
const value = getValue2(obj, field.path);
|
|
1382
1336
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1383
1337
|
if (options) {
|
|
1384
1338
|
const option = options.find((o) => o.id === value);
|
|
@@ -1387,8 +1341,8 @@ var TablePresentation = class {
|
|
|
1387
1341
|
}
|
|
1388
1342
|
}
|
|
1389
1343
|
}
|
|
1390
|
-
if (props.format ===
|
|
1391
|
-
const values =
|
|
1344
|
+
if (props.format === Format3.TypeFormat.MultiSelect) {
|
|
1345
|
+
const values = getValue2(obj, field.path);
|
|
1392
1346
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1393
1347
|
if (options && values && values.length > 0) {
|
|
1394
1348
|
const tags = values.map((value) => {
|
|
@@ -1411,22 +1365,22 @@ var TablePresentation = class {
|
|
|
1411
1365
|
}
|
|
1412
1366
|
getMainGridCells(range) {
|
|
1413
1367
|
const cells = {};
|
|
1414
|
-
const fields = this.model.projection?.
|
|
1368
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1415
1369
|
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1416
1370
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1417
1371
|
const field = fields[col];
|
|
1418
1372
|
if (!field) {
|
|
1419
1373
|
continue;
|
|
1420
1374
|
}
|
|
1421
|
-
this.createDataCell(cells, this.model.
|
|
1375
|
+
this.createDataCell(cells, this.model.getRows()[row], field, col, row);
|
|
1422
1376
|
}
|
|
1423
1377
|
}
|
|
1424
1378
|
return cells;
|
|
1425
1379
|
}
|
|
1426
1380
|
getDraftRowCells(range) {
|
|
1427
1381
|
const cells = {};
|
|
1428
|
-
const fields = this.model.projection?.
|
|
1429
|
-
const draftRows = this.model.
|
|
1382
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1383
|
+
const draftRows = this.model.getDraftRows();
|
|
1430
1384
|
if (draftRows.length === 0) {
|
|
1431
1385
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1432
1386
|
cells[toPlaneCellIndex({
|
|
@@ -1466,11 +1420,11 @@ var TablePresentation = class {
|
|
|
1466
1420
|
}
|
|
1467
1421
|
getHeaderCells(range) {
|
|
1468
1422
|
const cells = {};
|
|
1469
|
-
const fields = this.model.projection?.
|
|
1423
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1424
|
+
const currentSort = this.model.getSorting();
|
|
1470
1425
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1471
1426
|
const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
|
|
1472
|
-
const
|
|
1473
|
-
const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
|
|
1427
|
+
const direction = currentSort?.fieldId === field.id ? currentSort.direction : void 0;
|
|
1474
1428
|
cells[toPlaneCellIndex({
|
|
1475
1429
|
col,
|
|
1476
1430
|
row: 0
|
|
@@ -1479,7 +1433,7 @@ var TablePresentation = class {
|
|
|
1479
1433
|
value: "",
|
|
1480
1434
|
resizeHandle: "col",
|
|
1481
1435
|
accessoryHtml: `
|
|
1482
|
-
<span class="grow min-
|
|
1436
|
+
<span class="grow min-w-0 truncate">${props.title ?? field.path}</span>
|
|
1483
1437
|
${direction !== void 0 ? tableButtons.sort.render({
|
|
1484
1438
|
fieldId: field.id,
|
|
1485
1439
|
direction
|
|
@@ -1488,7 +1442,7 @@ var TablePresentation = class {
|
|
|
1488
1442
|
fieldId: field.id
|
|
1489
1443
|
})}
|
|
1490
1444
|
`,
|
|
1491
|
-
className: "!bg-
|
|
1445
|
+
className: "!bg-toolbar-surface text-description! [&>div]:flex [&>div]:items-stretch"
|
|
1492
1446
|
};
|
|
1493
1447
|
}
|
|
1494
1448
|
return cells;
|
|
@@ -1539,7 +1493,7 @@ var TablePresentation = class {
|
|
|
1539
1493
|
col: 0,
|
|
1540
1494
|
row: 0
|
|
1541
1495
|
})]: {
|
|
1542
|
-
className: "!bg-
|
|
1496
|
+
className: "!bg-toolbar-surface",
|
|
1543
1497
|
readonly: true,
|
|
1544
1498
|
value: ""
|
|
1545
1499
|
}
|
|
@@ -1553,9 +1507,9 @@ var TablePresentation = class {
|
|
|
1553
1507
|
accessoryHtml: tableControls.checkbox.render({
|
|
1554
1508
|
rowIndex: 0,
|
|
1555
1509
|
header: true,
|
|
1556
|
-
checked: this.model.selection.
|
|
1510
|
+
checked: this.model.selection.allRowsSelected
|
|
1557
1511
|
}),
|
|
1558
|
-
className: "!bg-
|
|
1512
|
+
className: "!bg-toolbar-surface",
|
|
1559
1513
|
readonly: true,
|
|
1560
1514
|
value: ""
|
|
1561
1515
|
}
|
|
@@ -1568,9 +1522,9 @@ var TablePresentation = class {
|
|
|
1568
1522
|
row: 0
|
|
1569
1523
|
})]: {
|
|
1570
1524
|
accessoryHtml: this.model.features.schemaEditable ? tableButtons.addColumn.render({
|
|
1571
|
-
disabled: (this.model.projection?.
|
|
1525
|
+
disabled: (this.model.projection?.getFields()?.length ?? 0) >= VIEW_FIELD_LIMIT
|
|
1572
1526
|
}) : void 0,
|
|
1573
|
-
className: "!bg-
|
|
1527
|
+
className: "!bg-toolbar-surface",
|
|
1574
1528
|
readonly: true,
|
|
1575
1529
|
value: ""
|
|
1576
1530
|
}
|
|
@@ -1578,7 +1532,7 @@ var TablePresentation = class {
|
|
|
1578
1532
|
}
|
|
1579
1533
|
getDraftActionCells(range) {
|
|
1580
1534
|
const cells = {};
|
|
1581
|
-
const draftRows = this.model.
|
|
1535
|
+
const draftRows = this.model.getDraftRows();
|
|
1582
1536
|
if (draftRows.length === 0) {
|
|
1583
1537
|
cells[toPlaneCellIndex({
|
|
1584
1538
|
col: 0,
|
|
@@ -1609,7 +1563,7 @@ var TablePresentation = class {
|
|
|
1609
1563
|
}
|
|
1610
1564
|
getDraftIconCells(range) {
|
|
1611
1565
|
const cells = {};
|
|
1612
|
-
const draftRows = this.model.
|
|
1566
|
+
const draftRows = this.model.getDraftRows();
|
|
1613
1567
|
for (let row = range.start.row; row <= range.end.row; row++) {
|
|
1614
1568
|
cells[toPlaneCellIndex({
|
|
1615
1569
|
col: 0,
|
|
@@ -1628,7 +1582,7 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
|
|
|
1628
1582
|
if (!selected) {
|
|
1629
1583
|
if (selectionMode === "single") {
|
|
1630
1584
|
return [
|
|
1631
|
-
"
|
|
1585
|
+
"cursor-pointer!"
|
|
1632
1586
|
];
|
|
1633
1587
|
} else {
|
|
1634
1588
|
return void 0;
|
|
@@ -1637,111 +1591,23 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
|
|
|
1637
1591
|
switch (selectionMode) {
|
|
1638
1592
|
case "single":
|
|
1639
1593
|
return [
|
|
1640
|
-
"
|
|
1594
|
+
"dx-grid__cell--no-focus-unfurl !bg-current-surface hover:bg-hover-surface cursor-pointer!"
|
|
1641
1595
|
];
|
|
1642
1596
|
case "multiple":
|
|
1643
1597
|
return [
|
|
1644
|
-
"!bg-
|
|
1598
|
+
"!bg-grid-cell-selected"
|
|
1645
1599
|
];
|
|
1646
1600
|
}
|
|
1647
1601
|
};
|
|
1648
1602
|
|
|
1649
|
-
// src/hooks/useTableModel.ts
|
|
1650
|
-
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
1651
|
-
import { effect as effect3 } from "@preact/signals-core";
|
|
1652
|
-
import orderBy2 from "lodash.orderby";
|
|
1653
|
-
import { useEffect, useMemo, useState } from "react";
|
|
1654
|
-
import { Obj as Obj4 } from "@dxos/echo";
|
|
1655
|
-
import { useSelected, useSelectionActions } from "@dxos/react-ui-attention";
|
|
1656
|
-
import { isNonNullable } from "@dxos/util";
|
|
1657
|
-
var useTableModel = ({ view, schema, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
|
|
1658
|
-
var _effect = _useSignals();
|
|
1659
|
-
try {
|
|
1660
|
-
const selected = useSelected(view && Obj4.getDXN(view).toString(), "multi");
|
|
1661
|
-
const initialSelection = useMemo(() => selected, [
|
|
1662
|
-
view
|
|
1663
|
-
]);
|
|
1664
|
-
const [model, setModel] = useState();
|
|
1665
|
-
useEffect(() => {
|
|
1666
|
-
if (!view || !schema) {
|
|
1667
|
-
return;
|
|
1668
|
-
}
|
|
1669
|
-
let model2;
|
|
1670
|
-
const t = setTimeout(async () => {
|
|
1671
|
-
model2 = new TableModel({
|
|
1672
|
-
view,
|
|
1673
|
-
schema,
|
|
1674
|
-
projection,
|
|
1675
|
-
features,
|
|
1676
|
-
rowActions,
|
|
1677
|
-
initialSelection,
|
|
1678
|
-
onRowAction,
|
|
1679
|
-
...props
|
|
1680
|
-
});
|
|
1681
|
-
await model2.open();
|
|
1682
|
-
setModel(model2);
|
|
1683
|
-
});
|
|
1684
|
-
return () => {
|
|
1685
|
-
clearTimeout(t);
|
|
1686
|
-
void model2?.close();
|
|
1687
|
-
};
|
|
1688
|
-
}, [
|
|
1689
|
-
view,
|
|
1690
|
-
schema,
|
|
1691
|
-
projection,
|
|
1692
|
-
features,
|
|
1693
|
-
rowActions,
|
|
1694
|
-
initialSelection
|
|
1695
|
-
]);
|
|
1696
|
-
useEffect(() => {
|
|
1697
|
-
if (rows) {
|
|
1698
|
-
const sortedRows = orderBy2(rows, [
|
|
1699
|
-
(row) => String(row.id)
|
|
1700
|
-
], [
|
|
1701
|
-
"asc"
|
|
1702
|
-
]);
|
|
1703
|
-
model?.setRows(sortedRows);
|
|
1704
|
-
}
|
|
1705
|
-
}, [
|
|
1706
|
-
model,
|
|
1707
|
-
rows
|
|
1708
|
-
]);
|
|
1709
|
-
const { multiSelect, clear } = useSelectionActions([
|
|
1710
|
-
model?.id
|
|
1711
|
-
].filter(isNonNullable));
|
|
1712
|
-
useEffect(() => {
|
|
1713
|
-
if (!model) {
|
|
1714
|
-
return;
|
|
1715
|
-
}
|
|
1716
|
-
const unsubscribe = effect3(() => {
|
|
1717
|
-
const selectedItems = [
|
|
1718
|
-
...model.selection.selection.value
|
|
1719
|
-
];
|
|
1720
|
-
multiSelect(selectedItems);
|
|
1721
|
-
onSelectionChanged?.(selectedItems);
|
|
1722
|
-
});
|
|
1723
|
-
return () => {
|
|
1724
|
-
clear();
|
|
1725
|
-
unsubscribe();
|
|
1726
|
-
};
|
|
1727
|
-
}, [
|
|
1728
|
-
model,
|
|
1729
|
-
onSelectionChanged
|
|
1730
|
-
]);
|
|
1731
|
-
return model;
|
|
1732
|
-
} finally {
|
|
1733
|
-
_effect.f();
|
|
1734
|
-
}
|
|
1735
|
-
};
|
|
1736
|
-
|
|
1737
1603
|
// src/hooks/useAddRow.ts
|
|
1738
1604
|
import { useCallback } from "react";
|
|
1739
|
-
import { Obj as
|
|
1740
|
-
var useAddRow = ({
|
|
1605
|
+
import { Obj as Obj3 } from "@dxos/echo";
|
|
1606
|
+
var useAddRow = ({ db, schema }) => {
|
|
1741
1607
|
return useCallback((data) => {
|
|
1742
|
-
if (
|
|
1608
|
+
if (db && schema) {
|
|
1743
1609
|
try {
|
|
1744
|
-
|
|
1610
|
+
db.add(Obj3.make(schema, data ?? {}));
|
|
1745
1611
|
return "final";
|
|
1746
1612
|
} catch (error) {
|
|
1747
1613
|
return "draft";
|
|
@@ -1749,27 +1615,137 @@ var useAddRow = ({ space, schema }) => {
|
|
|
1749
1615
|
}
|
|
1750
1616
|
return "final";
|
|
1751
1617
|
}, [
|
|
1752
|
-
|
|
1618
|
+
db,
|
|
1753
1619
|
schema
|
|
1754
1620
|
]);
|
|
1755
1621
|
};
|
|
1756
1622
|
|
|
1623
|
+
// src/hooks/useProjectionModel.ts
|
|
1624
|
+
import { useState } from "react";
|
|
1625
|
+
import { JsonSchema, Type } from "@dxos/echo";
|
|
1626
|
+
import { useAsyncEffect } from "@dxos/react-ui";
|
|
1627
|
+
import { ProjectionModel, createEchoChangeCallback as createEchoChangeCallback2 } from "@dxos/schema";
|
|
1628
|
+
var useProjectionModel = (schema, table, registry) => {
|
|
1629
|
+
const [projection, setProjection] = useState();
|
|
1630
|
+
useAsyncEffect(async () => {
|
|
1631
|
+
if (schema && table) {
|
|
1632
|
+
const view = await table.view.load();
|
|
1633
|
+
const jsonSchema = Type.isMutable(schema) ? schema.jsonSchema : JsonSchema.toJsonSchema(schema);
|
|
1634
|
+
const change = createEchoChangeCallback2(view, Type.isMutable(schema) ? schema : void 0);
|
|
1635
|
+
const projection2 = new ProjectionModel({
|
|
1636
|
+
registry,
|
|
1637
|
+
view,
|
|
1638
|
+
baseSchema: jsonSchema,
|
|
1639
|
+
change
|
|
1640
|
+
});
|
|
1641
|
+
projection2.normalizeView();
|
|
1642
|
+
setProjection(projection2);
|
|
1643
|
+
}
|
|
1644
|
+
}, [
|
|
1645
|
+
schema,
|
|
1646
|
+
table,
|
|
1647
|
+
registry
|
|
1648
|
+
]);
|
|
1649
|
+
return projection;
|
|
1650
|
+
};
|
|
1651
|
+
|
|
1652
|
+
// src/hooks/useTableModel.ts
|
|
1653
|
+
import { RegistryContext } from "@effect-atom/atom-react";
|
|
1654
|
+
import { useContext, useEffect, useMemo, useState as useState2 } from "react";
|
|
1655
|
+
import { Obj as Obj4 } from "@dxos/echo";
|
|
1656
|
+
import { useSelected, useSelectionActions } from "@dxos/react-ui-attention";
|
|
1657
|
+
import { isNonNullable } from "@dxos/util";
|
|
1658
|
+
var useTableModel = ({ object, projection, db, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
|
|
1659
|
+
const registry = useContext(RegistryContext);
|
|
1660
|
+
const selected = useSelected(object && Obj4.getDXN(object).toString(), "multi");
|
|
1661
|
+
const initialSelection = useMemo(() => selected, [
|
|
1662
|
+
object
|
|
1663
|
+
]);
|
|
1664
|
+
const [model, setModel] = useState2();
|
|
1665
|
+
useEffect(() => {
|
|
1666
|
+
if (!object || !projection) {
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
let model2;
|
|
1670
|
+
const t = setTimeout(async () => {
|
|
1671
|
+
model2 = new TableModel({
|
|
1672
|
+
registry,
|
|
1673
|
+
object,
|
|
1674
|
+
projection,
|
|
1675
|
+
db,
|
|
1676
|
+
change: createEchoChangeCallback(object),
|
|
1677
|
+
features,
|
|
1678
|
+
rowActions,
|
|
1679
|
+
initialSelection,
|
|
1680
|
+
onRowAction,
|
|
1681
|
+
...props
|
|
1682
|
+
});
|
|
1683
|
+
await model2.open();
|
|
1684
|
+
setModel(model2);
|
|
1685
|
+
});
|
|
1686
|
+
return () => {
|
|
1687
|
+
clearTimeout(t);
|
|
1688
|
+
void model2?.close();
|
|
1689
|
+
};
|
|
1690
|
+
}, [
|
|
1691
|
+
registry,
|
|
1692
|
+
object,
|
|
1693
|
+
projection,
|
|
1694
|
+
features,
|
|
1695
|
+
rowActions,
|
|
1696
|
+
initialSelection
|
|
1697
|
+
]);
|
|
1698
|
+
useEffect(() => {
|
|
1699
|
+
if (rows && model) {
|
|
1700
|
+
model.setRows(rows);
|
|
1701
|
+
}
|
|
1702
|
+
}, [
|
|
1703
|
+
model,
|
|
1704
|
+
rows
|
|
1705
|
+
]);
|
|
1706
|
+
const { multiSelect, clear } = useSelectionActions([
|
|
1707
|
+
model?.id
|
|
1708
|
+
].filter(isNonNullable));
|
|
1709
|
+
useEffect(() => {
|
|
1710
|
+
if (!model) {
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
const unsubscribe = registry.subscribe(model.selection.selectionAtom, () => {
|
|
1714
|
+
const selectedItems = [
|
|
1715
|
+
...model.selection.selection
|
|
1716
|
+
];
|
|
1717
|
+
multiSelect(selectedItems);
|
|
1718
|
+
onSelectionChanged?.(selectedItems);
|
|
1719
|
+
});
|
|
1720
|
+
return () => {
|
|
1721
|
+
clear();
|
|
1722
|
+
unsubscribe();
|
|
1723
|
+
};
|
|
1724
|
+
}, [
|
|
1725
|
+
registry,
|
|
1726
|
+
model,
|
|
1727
|
+
onSelectionChanged
|
|
1728
|
+
]);
|
|
1729
|
+
return model;
|
|
1730
|
+
};
|
|
1731
|
+
|
|
1757
1732
|
export {
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1733
|
+
extractOrder,
|
|
1734
|
+
getSortValue,
|
|
1735
|
+
compareValues,
|
|
1761
1736
|
BUTTON_IDENTIFIERS,
|
|
1762
1737
|
tableButtons,
|
|
1763
1738
|
CONTROL_IDENTIFIERS,
|
|
1764
1739
|
CheckboxStory,
|
|
1765
1740
|
SwitchStory,
|
|
1766
1741
|
tableControls,
|
|
1767
|
-
|
|
1742
|
+
createEchoChangeCallback,
|
|
1743
|
+
createDirectChangeCallback,
|
|
1768
1744
|
TableModel,
|
|
1769
|
-
ModalController,
|
|
1770
1745
|
TablePresentation,
|
|
1771
1746
|
cellClassesForRowSelection,
|
|
1772
|
-
|
|
1773
|
-
|
|
1747
|
+
useAddRow,
|
|
1748
|
+
useProjectionModel,
|
|
1749
|
+
useTableModel
|
|
1774
1750
|
};
|
|
1775
|
-
//# sourceMappingURL=chunk-
|
|
1751
|
+
//# sourceMappingURL=chunk-PTHMYAAM.mjs.map
|