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