@dxos/react-ui-table 0.8.4-main.72ec0f3 → 0.8.4-main.765dc60934
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/LICENSE +102 -5
- package/dist/lib/browser/chunk-4URYOFDL.mjs +69 -0
- package/dist/lib/browser/chunk-4URYOFDL.mjs.map +7 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GS2UNGJK.mjs → chunk-YDXPC7HA.mjs} +642 -722
- package/dist/lib/browser/chunk-YDXPC7HA.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1111 -1023
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +35 -45
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/translations.mjs +36 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +4 -3
- package/dist/lib/node-esm/{chunk-TRR3C5NX.mjs → chunk-2AN3QQ3D.mjs} +642 -721
- package/dist/lib/node-esm/chunk-2AN3QQ3D.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-B2SZYAEC.mjs +70 -0
- package/dist/lib/node-esm/chunk-B2SZYAEC.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1111 -1023
- 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 +35 -45
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/translations.mjs +37 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +4 -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 +6 -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 +84 -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 +20 -21
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +92 -26
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableContent.d.ts +17 -0
- package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts +21 -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/CellValidationMessage.d.ts.map +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/index.d.ts +0 -2
- package/dist/types/src/index.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 +18 -9
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +103 -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/playwright/playwright.config.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 +25 -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/schema.d.ts.map +1 -1
- package/dist/types/src/util/signals.d.ts.map +1 -1
- package/dist/types/src/util/sort.d.ts +12 -0
- package/dist/types/src/util/sort.d.ts.map +1 -0
- package/dist/types/src/util/table-buttons.d.ts +20 -20
- package/dist/types/src/util/table-buttons.d.ts.map +1 -1
- package/dist/types/src/util/table-controls.d.ts +4 -4
- package/dist/types/src/util/table-controls.d.ts.map +1 -1
- package/dist/types/src/util/tag.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +67 -77
- package/src/components/Table/ColumnActionsMenu.tsx +17 -12
- package/src/components/Table/ColumnSettings.tsx +8 -9
- package/src/components/Table/DynamicTable.stories.tsx +30 -30
- package/src/components/Table/DynamicTable.tsx +31 -32
- package/src/components/Table/Relations.stories.tsx +101 -63
- package/src/components/Table/RowActionsMenu.tsx +6 -4
- package/src/components/Table/Table.stories.tsx +119 -104
- package/src/components/Table/Table.tsx +43 -407
- package/src/components/Table/TableContent.tsx +421 -0
- package/src/components/{TableToolbar → Table}/TableToolbar.tsx +44 -45
- package/src/components/TableCellEditor/CellValidationMessage.tsx +5 -6
- package/src/components/TableCellEditor/FormCellEditor.tsx +120 -136
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +22 -19
- package/src/components/TableCellEditor/TableCellEditor.tsx +35 -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/index.ts +0 -4
- 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 +429 -167
- package/src/model/table-presentation.test.ts +59 -50
- package/src/model/table-presentation.ts +43 -39
- 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 +49 -42
- package/src/translations.ts +20 -22
- package/src/types/Table.ts +78 -0
- package/src/types/index.ts +1 -1
- package/src/util/dynamic-table.test.ts +70 -0
- package/src/util/dynamic-table.ts +39 -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,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
|
-
const projection = new ProjectionModel(jsonSchema, view.projection);
|
|
43
|
-
projection.normalizeView();
|
|
44
|
-
if (properties && projection.fields) {
|
|
45
|
-
setProperties(view, projection, table, properties);
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
projection,
|
|
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();
|
|
78
26
|
}
|
|
27
|
+
return String(value);
|
|
79
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;
|
|
33
|
+
}
|
|
34
|
+
return String(value);
|
|
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.update(table, (table2) => mutate(table2)),
|
|
387
|
+
row: (row, mutate) => {
|
|
388
|
+
if (Obj.isObject(row)) {
|
|
389
|
+
Obj.update(row, (row2) => mutate(row2));
|
|
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,133 +405,201 @@ 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
|
-
invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
454
|
+
invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 94, S: this, A: ["!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')", "'Single selection is not compatible with editable tables.'"] });
|
|
455
|
+
this._visibleRange = Atom2.make({
|
|
456
|
+
start: {
|
|
457
|
+
row: 0,
|
|
458
|
+
col: 0
|
|
459
|
+
},
|
|
460
|
+
end: {
|
|
461
|
+
row: 0,
|
|
462
|
+
col: 0
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
this._rows = Atom2.make([]);
|
|
466
|
+
this._draftRows = Atom2.make([]);
|
|
467
|
+
this._inMemorySort = Atom2.make(void 0);
|
|
468
|
+
this._cellUpdateCounter = Atom2.make(0);
|
|
469
|
+
this._persistedSort = Atom2.make((_get) => {
|
|
470
|
+
const viewSnapshot = Obj.getSnapshot(this.view);
|
|
471
|
+
const ast = viewSnapshot.query.ast;
|
|
472
|
+
const orders = extractOrder(ast);
|
|
473
|
+
if (orders && orders.length > 0) {
|
|
474
|
+
const firstOrder = orders[0];
|
|
475
|
+
if (firstOrder.kind === "property") {
|
|
476
|
+
const field = this._projection.getFields().find((f) => f.path === firstOrder.property);
|
|
477
|
+
if (field) {
|
|
478
|
+
return {
|
|
479
|
+
fieldId: field.id,
|
|
480
|
+
direction: firstOrder.direction
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return void 0;
|
|
486
|
+
});
|
|
487
|
+
this._sorting = Atom2.make((get) => {
|
|
488
|
+
const inMemorySort = get(this._inMemorySort);
|
|
489
|
+
return inMemorySort ?? get(this._persistedSort);
|
|
490
|
+
});
|
|
491
|
+
this._sortedRows = Atom2.make((get) => {
|
|
492
|
+
const rows = get(this._rows);
|
|
493
|
+
const sort = get(this._sorting);
|
|
494
|
+
if (!sort || rows.length === 0) {
|
|
495
|
+
return rows;
|
|
496
|
+
}
|
|
497
|
+
const field = this._projection.getFields().find((f) => f.id === sort.fieldId);
|
|
498
|
+
if (!field) {
|
|
499
|
+
return rows;
|
|
500
|
+
}
|
|
501
|
+
const fieldProjection = this._projection.getFieldProjection(field.id);
|
|
502
|
+
const sorted = [
|
|
503
|
+
...rows
|
|
504
|
+
].sort((a, b) => {
|
|
505
|
+
const aValue = getValue(a, field.path);
|
|
506
|
+
const bValue = getValue(b, field.path);
|
|
507
|
+
return compareValues(aValue, bValue, fieldProjection.props.format, sort.direction);
|
|
508
|
+
});
|
|
509
|
+
return sorted;
|
|
510
|
+
});
|
|
511
|
+
this._selection = new SelectionModel(this._registry, this._sortedRows, this._features.selection.mode ?? "multiple", initialSelection, () => this._onRowOrderChange?.());
|
|
512
|
+
this._viewDirty = Atom2.make((get) => {
|
|
513
|
+
const inMemorySort = get(this._inMemorySort);
|
|
514
|
+
if (!inMemorySort) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
const persisted = get(this._persistedSort);
|
|
518
|
+
if (!persisted) {
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
return inMemorySort.fieldId !== persisted.fieldId || inMemorySort.direction !== persisted.direction;
|
|
622
522
|
});
|
|
623
|
-
this._sorting = new TableSorting(this._rows, this._view, this._projection);
|
|
624
|
-
if (sorting.length > 0) {
|
|
625
|
-
const [sort] = sorting;
|
|
626
|
-
this._sorting.setSort(sort.fieldId, sort.direction);
|
|
627
|
-
}
|
|
628
|
-
this._selection = new SelectionModel(this._sorting.sortedRows, this._features.selection.mode ?? "multiple", initialSelection, () => this._onRowOrderChange?.());
|
|
629
523
|
this._pinnedRows = pinnedRows;
|
|
630
524
|
this._rowActions = rowActions;
|
|
631
525
|
this._onInsertRow = onInsertRow;
|
|
632
526
|
this._onDeleteRows = onDeleteRows;
|
|
633
|
-
this.
|
|
527
|
+
this._onColumnDelete = onColumnDelete;
|
|
634
528
|
this._onCellUpdate = onCellUpdate;
|
|
635
529
|
this._onRowOrderChange = onRowOrderChange;
|
|
636
530
|
this._onRowAction = onRowAction;
|
|
637
531
|
}
|
|
638
532
|
get id() {
|
|
639
|
-
return
|
|
533
|
+
return Obj.getDXN(this._object).toString();
|
|
640
534
|
}
|
|
641
535
|
get view() {
|
|
642
|
-
|
|
536
|
+
const view = this._object.view.target;
|
|
537
|
+
invariant(view, "Table model not initialized", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 186, S: this, A: ["view", "'Table model not initialized'"] });
|
|
538
|
+
return view;
|
|
643
539
|
}
|
|
644
540
|
get table() {
|
|
645
|
-
|
|
646
|
-
F: __dxlog_file,
|
|
647
|
-
L: 186,
|
|
648
|
-
S: this,
|
|
649
|
-
A: [
|
|
650
|
-
"this._table",
|
|
651
|
-
"'Model not initialized'"
|
|
652
|
-
]
|
|
653
|
-
});
|
|
654
|
-
return this._table;
|
|
541
|
+
return this._object;
|
|
655
542
|
}
|
|
656
543
|
get projection() {
|
|
657
544
|
return this._projection;
|
|
658
545
|
}
|
|
546
|
+
get db() {
|
|
547
|
+
return this._db;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Atom for reactive access to rows with in-memory sorting applied.
|
|
551
|
+
*/
|
|
659
552
|
get rows() {
|
|
660
|
-
return this.
|
|
553
|
+
return this._sortedRows;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Gets rows with in-memory sorting applied.
|
|
557
|
+
* In-memory sort is local to this instance until saved.
|
|
558
|
+
*/
|
|
559
|
+
getRows() {
|
|
560
|
+
return this._registry.get(this._sortedRows);
|
|
561
|
+
}
|
|
562
|
+
/** Atom for reactive access to cell changes. */
|
|
563
|
+
get cellUpdate() {
|
|
564
|
+
return this._cellUpdateCounter;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Change a row using the configured change callback.
|
|
568
|
+
* Use this instead of directly mutating to ensure consistent mutation handling.
|
|
569
|
+
*/
|
|
570
|
+
changeRow(row, mutate) {
|
|
571
|
+
this._change.row(row, mutate);
|
|
661
572
|
}
|
|
662
573
|
get features() {
|
|
663
574
|
return this._features;
|
|
664
575
|
}
|
|
665
576
|
/**
|
|
666
|
-
*
|
|
577
|
+
* Gets the current sort state.
|
|
578
|
+
* Priority: in-memory sort (local changes) > persisted sort (from query AST).
|
|
667
579
|
*/
|
|
668
|
-
|
|
669
|
-
return this._sorting;
|
|
580
|
+
getSorting() {
|
|
581
|
+
return this._registry.get(this._sorting);
|
|
670
582
|
}
|
|
671
583
|
/**
|
|
672
584
|
* Gets the row data at the specified display index.
|
|
673
585
|
*/
|
|
674
586
|
getRowAt(displayIndex) {
|
|
675
|
-
|
|
587
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
588
|
+
if (displayIndex < 0 || displayIndex >= sortedRows.length) {
|
|
676
589
|
return void 0;
|
|
677
590
|
}
|
|
678
|
-
return
|
|
591
|
+
return sortedRows[displayIndex];
|
|
679
592
|
}
|
|
680
593
|
get pinnedRows() {
|
|
681
594
|
return this._pinnedRows;
|
|
682
595
|
}
|
|
683
596
|
get columnMeta() {
|
|
684
|
-
invariant(this._columnMeta, void 0, {
|
|
685
|
-
F: __dxlog_file,
|
|
686
|
-
L: 225,
|
|
687
|
-
S: this,
|
|
688
|
-
A: [
|
|
689
|
-
"this._columnMeta",
|
|
690
|
-
""
|
|
691
|
-
]
|
|
692
|
-
});
|
|
597
|
+
invariant(this._columnMeta, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 240, S: this, A: ["this._columnMeta", ""] });
|
|
693
598
|
return this._columnMeta;
|
|
694
599
|
}
|
|
695
600
|
get selection() {
|
|
696
601
|
return this._selection;
|
|
697
602
|
}
|
|
698
|
-
/** @reactive */
|
|
699
|
-
get isViewDirty() {
|
|
700
|
-
return this.sorting.isDirty;
|
|
701
|
-
}
|
|
702
603
|
get rowActions() {
|
|
703
604
|
return this._rowActions;
|
|
704
605
|
}
|
|
@@ -706,24 +607,15 @@ var TableModel = class extends Resource2 {
|
|
|
706
607
|
// Initialisation
|
|
707
608
|
//
|
|
708
609
|
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;
|
|
610
|
+
await this._object.view.load();
|
|
720
611
|
this.initializeColumnMeta();
|
|
721
612
|
this.initializeEffects();
|
|
722
613
|
await this._selection.open(this._ctx);
|
|
723
614
|
}
|
|
724
615
|
initializeColumnMeta() {
|
|
725
|
-
this.
|
|
726
|
-
|
|
616
|
+
invariant(this._object.view.target, "View must be loaded before initializing column meta", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 259, S: this, A: ["this._object.view.target", "'View must be loaded before initializing column meta'"] });
|
|
617
|
+
this._columnMeta = Atom2.make((get) => {
|
|
618
|
+
const fields = get(this._projection.fields);
|
|
727
619
|
const meta = Object.fromEntries(fields.map((field, index) => [
|
|
728
620
|
index,
|
|
729
621
|
{
|
|
@@ -749,49 +641,62 @@ var TableModel = class extends Resource2 {
|
|
|
749
641
|
});
|
|
750
642
|
}
|
|
751
643
|
initializeEffects() {
|
|
752
|
-
const
|
|
753
|
-
touch(this.sorting.sortedRows.value);
|
|
644
|
+
const rowsUnsubscribe = this._registry.subscribe(this._rows, () => {
|
|
754
645
|
this._onRowOrderChange?.();
|
|
755
646
|
});
|
|
756
|
-
this._ctx.onDispose(
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
647
|
+
this._ctx.onDispose(rowsUnsubscribe);
|
|
648
|
+
const rowSubscriptions = /* @__PURE__ */ new Map();
|
|
649
|
+
const visibleRangeUnsubscribe = this._registry.subscribe(this._visibleRange, () => {
|
|
650
|
+
for (const [id, unsub] of rowSubscriptions) {
|
|
651
|
+
unsub();
|
|
652
|
+
rowSubscriptions.delete(id);
|
|
653
|
+
}
|
|
654
|
+
const { start, end } = this._registry.get(this._visibleRange);
|
|
655
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
656
|
+
for (let row = start.row; row <= end.row && row < sortedRows.length; row++) {
|
|
657
|
+
const obj = sortedRows[row];
|
|
658
|
+
if (Obj.isObject(obj) && !rowSubscriptions.has(obj.id)) {
|
|
659
|
+
const unsub = Obj.subscribe(obj, () => {
|
|
660
|
+
this._registry.set(this._cellUpdateCounter, this._registry.get(this._cellUpdateCounter) + 1);
|
|
661
|
+
this._onCellUpdate?.({
|
|
662
|
+
row,
|
|
663
|
+
col: start.col,
|
|
664
|
+
plane: "grid"
|
|
665
|
+
});
|
|
768
666
|
});
|
|
769
|
-
|
|
667
|
+
rowSubscriptions.set(obj.id, unsub);
|
|
668
|
+
}
|
|
770
669
|
}
|
|
771
|
-
return () => rowEffects.forEach((cleanup) => cleanup());
|
|
772
670
|
});
|
|
773
|
-
this._ctx.onDispose(
|
|
774
|
-
|
|
775
|
-
|
|
671
|
+
this._ctx.onDispose(() => {
|
|
672
|
+
visibleRangeUnsubscribe();
|
|
673
|
+
for (const unsub of rowSubscriptions.values()) {
|
|
674
|
+
unsub();
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
const draftRowsUnsubscribe = this._registry.subscribe(this._draftRows, () => {
|
|
776
678
|
this._onRowOrderChange?.();
|
|
777
679
|
});
|
|
778
|
-
this._ctx.onDispose(
|
|
680
|
+
this._ctx.onDispose(draftRowsUnsubscribe);
|
|
779
681
|
}
|
|
780
682
|
//
|
|
781
683
|
// Data
|
|
782
684
|
//
|
|
783
685
|
setRows = (obj) => {
|
|
784
|
-
this._rows
|
|
686
|
+
this._registry.set(this._rows, obj);
|
|
785
687
|
};
|
|
786
|
-
getRowCount = () => this.
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
// TODO(ZaymonFC): Return .value instead of exposing the signal.
|
|
688
|
+
getRowCount = () => this._registry.get(this._sortedRows).length;
|
|
689
|
+
getDraftRowCount() {
|
|
690
|
+
return this._registry.get(this._draftRows).length;
|
|
691
|
+
}
|
|
692
|
+
/** Atom for reactive access to draft rows. */
|
|
792
693
|
get draftRows() {
|
|
793
694
|
return this._draftRows;
|
|
794
695
|
}
|
|
696
|
+
/** Gets the current draft rows. */
|
|
697
|
+
getDraftRows() {
|
|
698
|
+
return this._registry.get(this._draftRows);
|
|
699
|
+
}
|
|
795
700
|
/**
|
|
796
701
|
* Checks if a specific field path has validation errors for a given draft row.
|
|
797
702
|
* @param draftRowIndex - The index of the draft row to check
|
|
@@ -799,17 +704,17 @@ var TableModel = class extends Resource2 {
|
|
|
799
704
|
* @returns true if the field has validation errors, false otherwise
|
|
800
705
|
*/
|
|
801
706
|
hasDraftRowValidationError(draftRowIndex, fieldPath) {
|
|
802
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
707
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
803
708
|
return false;
|
|
804
709
|
}
|
|
805
|
-
const draftRow = this._draftRows
|
|
710
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
806
711
|
const validationErrors = draftRow.validationErrors || [];
|
|
807
712
|
return validationErrors.some((error) => error.path === fieldPath);
|
|
808
713
|
}
|
|
809
|
-
getColumnCount = () => this._projection?.
|
|
714
|
+
getColumnCount = () => this._projection?.getFields().length ?? 0;
|
|
810
715
|
insertRow = () => {
|
|
811
716
|
const result = this._onInsertRow?.();
|
|
812
|
-
if (result === "draft" && this._draftRows.
|
|
717
|
+
if (result === "draft" && this._registry.get(this._draftRows).length === 0) {
|
|
813
718
|
this.createDraftRow();
|
|
814
719
|
}
|
|
815
720
|
return result ?? "final";
|
|
@@ -827,16 +732,16 @@ var TableModel = class extends Resource2 {
|
|
|
827
732
|
valid: validationErrors.length === 0,
|
|
828
733
|
validationErrors
|
|
829
734
|
};
|
|
830
|
-
this._draftRows
|
|
831
|
-
...this._draftRows
|
|
735
|
+
this._registry.set(this._draftRows, [
|
|
736
|
+
...this._registry.get(this._draftRows),
|
|
832
737
|
draftRow
|
|
833
|
-
];
|
|
738
|
+
]);
|
|
834
739
|
}
|
|
835
740
|
validateDraftRow(draftRowIndex) {
|
|
836
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
741
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
837
742
|
return;
|
|
838
743
|
}
|
|
839
|
-
const draftRow = this._draftRows
|
|
744
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
840
745
|
const validationErrors = this.validateDraftRowData(draftRow.data);
|
|
841
746
|
const updatedDraftRow = {
|
|
842
747
|
...draftRow,
|
|
@@ -844,80 +749,82 @@ var TableModel = class extends Resource2 {
|
|
|
844
749
|
validationErrors
|
|
845
750
|
};
|
|
846
751
|
const newDraftRows = [
|
|
847
|
-
...this._draftRows
|
|
752
|
+
...this._registry.get(this._draftRows)
|
|
848
753
|
];
|
|
849
754
|
newDraftRows[draftRowIndex] = updatedDraftRow;
|
|
850
|
-
this._draftRows
|
|
755
|
+
this._registry.set(this._draftRows, newDraftRows);
|
|
851
756
|
}
|
|
852
757
|
validateDraftRowData(data) {
|
|
853
758
|
const schema = toEffectSchema(this._projection.baseSchema);
|
|
854
759
|
return validateSchema(schema, data) || [];
|
|
855
760
|
}
|
|
856
761
|
commitDraftRow = (draftRowIndex) => {
|
|
857
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
762
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
858
763
|
return false;
|
|
859
764
|
}
|
|
860
|
-
const draftRow = this._draftRows
|
|
765
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
861
766
|
if (!draftRow.valid) {
|
|
862
767
|
return false;
|
|
863
768
|
}
|
|
864
769
|
const insertRowResult = this._onInsertRow?.(draftRow.data);
|
|
865
770
|
if (insertRowResult === "final") {
|
|
866
|
-
const newDraftRows = this._draftRows.
|
|
867
|
-
this._draftRows
|
|
771
|
+
const newDraftRows = this._registry.get(this._draftRows).filter((_, index) => index !== draftRowIndex);
|
|
772
|
+
this._registry.set(this._draftRows, newDraftRows);
|
|
868
773
|
}
|
|
869
774
|
return insertRowResult === "final";
|
|
870
775
|
};
|
|
871
776
|
deleteRow = (rowIndex) => {
|
|
872
|
-
const
|
|
873
|
-
const obj =
|
|
777
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
778
|
+
const obj = sortedRows[rowIndex];
|
|
874
779
|
const objectsToDelete = [];
|
|
875
|
-
if (this.features.selection.enabled && this._selection.hasSelection
|
|
780
|
+
if (this.features.selection.enabled && this._selection.hasSelection) {
|
|
876
781
|
const selectedRows = this._selection.getSelectedRows();
|
|
877
782
|
objectsToDelete.push(...selectedRows);
|
|
878
|
-
} else {
|
|
783
|
+
} else if (obj) {
|
|
879
784
|
objectsToDelete.push(obj);
|
|
880
785
|
}
|
|
881
|
-
|
|
786
|
+
if (objectsToDelete.length > 0) {
|
|
787
|
+
this._onDeleteRows?.(rowIndex, objectsToDelete);
|
|
788
|
+
}
|
|
882
789
|
};
|
|
883
790
|
handleRowAction = (actionId, rowIndex) => {
|
|
884
791
|
if (!this._onRowAction) {
|
|
885
792
|
return;
|
|
886
793
|
}
|
|
887
|
-
const
|
|
888
|
-
const data =
|
|
794
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
795
|
+
const data = sortedRows[rowIndex];
|
|
889
796
|
if (data) {
|
|
890
797
|
this._onRowAction(actionId, data);
|
|
891
798
|
}
|
|
892
799
|
};
|
|
893
800
|
getCellData = (cell) => {
|
|
894
801
|
const { col, row, plane } = cell;
|
|
895
|
-
const fields = this._projection?.
|
|
802
|
+
const fields = this._projection?.getFields() ?? [];
|
|
896
803
|
if (col < 0 || col >= fields.length) {
|
|
897
804
|
return void 0;
|
|
898
805
|
}
|
|
899
806
|
const field = fields[col];
|
|
900
807
|
let value;
|
|
901
808
|
if (plane === "frozenRowsEnd") {
|
|
902
|
-
if (row >= 0 && row < this._draftRows.
|
|
903
|
-
value =
|
|
809
|
+
if (row >= 0 && row < this._registry.get(this._draftRows).length) {
|
|
810
|
+
value = getValue(this._registry.get(this._draftRows)[row].data, field.path);
|
|
904
811
|
} else {
|
|
905
812
|
return void 0;
|
|
906
813
|
}
|
|
907
814
|
} else {
|
|
908
|
-
const
|
|
909
|
-
value =
|
|
815
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
816
|
+
value = getValue(sortedRows[row], field.path);
|
|
910
817
|
}
|
|
911
818
|
if (value == null) {
|
|
912
819
|
return "";
|
|
913
820
|
}
|
|
914
821
|
const { props } = this._projection.getFieldProjection(field.id);
|
|
915
822
|
switch (props.format) {
|
|
916
|
-
case
|
|
823
|
+
case Format2.TypeFormat.Ref: {
|
|
917
824
|
if (!field.referencePath) {
|
|
918
825
|
return "";
|
|
919
826
|
}
|
|
920
|
-
return
|
|
827
|
+
return getValue(value.target, field.referencePath);
|
|
921
828
|
}
|
|
922
829
|
default: {
|
|
923
830
|
return formatForEditing({
|
|
@@ -929,7 +836,7 @@ var TableModel = class extends Resource2 {
|
|
|
929
836
|
}
|
|
930
837
|
};
|
|
931
838
|
validateCellData = async ({ col, row, plane }, value) => {
|
|
932
|
-
const fields = this._projection?.
|
|
839
|
+
const fields = this._projection?.getFields() ?? [];
|
|
933
840
|
if (col < 0 || col >= fields.length) {
|
|
934
841
|
return {
|
|
935
842
|
valid: false,
|
|
@@ -941,14 +848,14 @@ var TableModel = class extends Resource2 {
|
|
|
941
848
|
const transformedValue = editorTextToCellValue(props, value);
|
|
942
849
|
const isDraftRow = plane === "frozenRowsEnd";
|
|
943
850
|
if (isDraftRow) {
|
|
944
|
-
const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.
|
|
851
|
+
const isInvalidDraftRowIndex = row < 0 || row >= this._registry.get(this._draftRows).length;
|
|
945
852
|
if (isInvalidDraftRowIndex) {
|
|
946
853
|
return {
|
|
947
854
|
valid: false,
|
|
948
855
|
error: "Invalid draft row index"
|
|
949
856
|
};
|
|
950
857
|
}
|
|
951
|
-
const draftRow = this._draftRows
|
|
858
|
+
const draftRow = this._registry.get(this._draftRows)[row];
|
|
952
859
|
const snapshot = {
|
|
953
860
|
...draftRow.data
|
|
954
861
|
};
|
|
@@ -967,41 +874,18 @@ var TableModel = class extends Resource2 {
|
|
|
967
874
|
valid: true
|
|
968
875
|
};
|
|
969
876
|
} else {
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
S: this,
|
|
976
|
-
A: [
|
|
977
|
-
"currentRow",
|
|
978
|
-
"'Invalid row index'"
|
|
979
|
-
]
|
|
980
|
-
});
|
|
981
|
-
const snapshot = getSnapshot(currentRow);
|
|
877
|
+
const currentRow = this._registry.get(this._rows)[row];
|
|
878
|
+
invariant(currentRow, "Invalid row index", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 533, S: this, A: ["currentRow", "'Invalid row index'"] });
|
|
879
|
+
const snapshot = {
|
|
880
|
+
...getSnapshot(currentRow)
|
|
881
|
+
};
|
|
982
882
|
setValue(snapshot, field.path, transformedValue);
|
|
983
|
-
const schema = getSchema(currentRow);
|
|
984
|
-
invariant(schema, void 0, {
|
|
985
|
-
F: __dxlog_file,
|
|
986
|
-
L: 531,
|
|
987
|
-
S: this,
|
|
988
|
-
A: [
|
|
989
|
-
"schema",
|
|
990
|
-
""
|
|
991
|
-
]
|
|
992
|
-
});
|
|
883
|
+
const schema = Obj.getSchema(currentRow);
|
|
884
|
+
invariant(schema, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 539, S: this, A: ["schema", ""] });
|
|
993
885
|
const validationResult = validateSchema(schema, snapshot);
|
|
994
886
|
if (validationResult && validationResult.length > 0) {
|
|
995
887
|
const error = validationResult[0];
|
|
996
|
-
invariant(error.path === field.path, void 0, {
|
|
997
|
-
F: __dxlog_file,
|
|
998
|
-
L: 536,
|
|
999
|
-
S: this,
|
|
1000
|
-
A: [
|
|
1001
|
-
"error.path === field.path",
|
|
1002
|
-
""
|
|
1003
|
-
]
|
|
1004
|
-
});
|
|
888
|
+
invariant(error.path === field.path, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 543, S: this, A: ["error.path === field.path", ""] });
|
|
1005
889
|
return {
|
|
1006
890
|
valid: false,
|
|
1007
891
|
error: error.message
|
|
@@ -1014,24 +898,27 @@ var TableModel = class extends Resource2 {
|
|
|
1014
898
|
};
|
|
1015
899
|
setCellData = (cell, value) => {
|
|
1016
900
|
const { col, row, plane } = cell;
|
|
1017
|
-
const fields = this._projection?.
|
|
901
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1018
902
|
if (col < 0 || col >= fields.length) {
|
|
1019
903
|
return;
|
|
1020
904
|
}
|
|
1021
905
|
const field = fields[col];
|
|
1022
906
|
const { props } = this._projection.getFieldProjection(field.id);
|
|
1023
907
|
const transformedValue = editorTextToCellValue(props, value);
|
|
1024
|
-
if (props.format ===
|
|
908
|
+
if (props.format === Format2.TypeFormat.Ref && !Obj.isObject(value)) {
|
|
1025
909
|
return;
|
|
1026
910
|
}
|
|
1027
911
|
if (plane === "frozenRowsEnd") {
|
|
1028
|
-
if (row >= 0 && row < this._draftRows.
|
|
1029
|
-
setValue(this._draftRows
|
|
912
|
+
if (row >= 0 && row < this._registry.get(this._draftRows).length) {
|
|
913
|
+
setValue(this._registry.get(this._draftRows)[row].data, field.path, transformedValue);
|
|
1030
914
|
this.validateDraftRow(row);
|
|
1031
915
|
}
|
|
1032
916
|
} else {
|
|
1033
|
-
const
|
|
1034
|
-
|
|
917
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
918
|
+
const rowData = sortedRows[row];
|
|
919
|
+
this._change.row(rowData, (mutableRow) => {
|
|
920
|
+
setValue(mutableRow, field.path, transformedValue);
|
|
921
|
+
});
|
|
1035
922
|
}
|
|
1036
923
|
};
|
|
1037
924
|
/**
|
|
@@ -1040,12 +927,15 @@ var TableModel = class extends Resource2 {
|
|
|
1040
927
|
* @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
|
|
1041
928
|
*/
|
|
1042
929
|
updateCellData({ col, row }, update) {
|
|
1043
|
-
const
|
|
1044
|
-
const fields = this._projection?.fields ?? [];
|
|
930
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1045
931
|
const field = fields[col];
|
|
1046
|
-
const
|
|
932
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
933
|
+
const rowData = sortedRows[row];
|
|
934
|
+
const value = getValue(rowData, field.path);
|
|
1047
935
|
const updatedValue = update(value);
|
|
1048
|
-
|
|
936
|
+
this._change.row(rowData, (mutableRow) => {
|
|
937
|
+
setValue(mutableRow, field.path, updatedValue);
|
|
938
|
+
});
|
|
1049
939
|
}
|
|
1050
940
|
/**
|
|
1051
941
|
* Gets the domain-appropriate cell type for a given cell position.
|
|
@@ -1079,21 +969,23 @@ var TableModel = class extends Resource2 {
|
|
|
1079
969
|
if (!this._projection) {
|
|
1080
970
|
return;
|
|
1081
971
|
}
|
|
1082
|
-
const field = this._projection?.
|
|
1083
|
-
if (field && this.
|
|
1084
|
-
this.
|
|
972
|
+
const field = this._projection?.getFields().find((field2) => field2.id === fieldId);
|
|
973
|
+
if (field && this._onColumnDelete) {
|
|
974
|
+
this._onColumnDelete(field.id);
|
|
1085
975
|
}
|
|
1086
976
|
}
|
|
1087
977
|
//
|
|
1088
978
|
// Resize
|
|
1089
979
|
//
|
|
1090
980
|
setColumnWidth(columnIndex, width) {
|
|
1091
|
-
const fields = this._projection?.
|
|
981
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1092
982
|
if (columnIndex < fields.length) {
|
|
1093
983
|
const newWidth = Math.max(0, width);
|
|
1094
984
|
const field = fields[columnIndex];
|
|
1095
985
|
if (field) {
|
|
1096
|
-
this.table
|
|
986
|
+
this._change.table((mutableTable) => {
|
|
987
|
+
mutableTable.sizes[field.path] = newWidth;
|
|
988
|
+
});
|
|
1097
989
|
}
|
|
1098
990
|
}
|
|
1099
991
|
}
|
|
@@ -1109,22 +1001,92 @@ var TableModel = class extends Resource2 {
|
|
|
1109
1001
|
this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
|
|
1110
1002
|
}
|
|
1111
1003
|
//
|
|
1112
|
-
//
|
|
1004
|
+
// Sort operations
|
|
1113
1005
|
//
|
|
1006
|
+
/**
|
|
1007
|
+
* Sets the sort order for a field in-memory (local to this instance).
|
|
1008
|
+
* Use saveView() to persist the sort to the view query.
|
|
1009
|
+
*/
|
|
1010
|
+
setSort(fieldId, direction) {
|
|
1011
|
+
const field = this._projection.getFields().find((f) => f.id === fieldId);
|
|
1012
|
+
if (!field) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
this._registry.set(this._inMemorySort, {
|
|
1016
|
+
fieldId,
|
|
1017
|
+
direction
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Toggles the sort direction for a field in-memory.
|
|
1022
|
+
*/
|
|
1023
|
+
toggleSort(fieldId) {
|
|
1024
|
+
const currentSort = this.getSorting();
|
|
1025
|
+
if (!currentSort || currentSort.fieldId !== fieldId) {
|
|
1026
|
+
this.setSort(fieldId, "asc");
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
const newDirection = currentSort.direction === "asc" ? "desc" : "asc";
|
|
1030
|
+
this.setSort(fieldId, newDirection);
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Clears the in-memory sort order.
|
|
1034
|
+
*/
|
|
1035
|
+
clearSort() {
|
|
1036
|
+
this._registry.set(this._inMemorySort, void 0);
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Saves the current in-memory sort to the view query AST.
|
|
1040
|
+
* This persists the sort so it becomes the default for all viewers.
|
|
1041
|
+
*/
|
|
1114
1042
|
saveView() {
|
|
1115
|
-
this.
|
|
1043
|
+
const view = this.view;
|
|
1044
|
+
const inMemorySort = this._registry.get(this._inMemorySort);
|
|
1045
|
+
const viewSnapshot = Obj.getSnapshot(view);
|
|
1046
|
+
const currentQuery = Query.fromAst(viewSnapshot.query.ast);
|
|
1047
|
+
const baseQuery = this._getBaseQuery(currentQuery);
|
|
1048
|
+
if (inMemorySort) {
|
|
1049
|
+
const field = this._projection.getFields().find((f) => f.id === inMemorySort.fieldId);
|
|
1050
|
+
if (field) {
|
|
1051
|
+
const newQuery = baseQuery.orderBy(Order.property(field.path, inMemorySort.direction));
|
|
1052
|
+
Obj.update(view, (view2) => {
|
|
1053
|
+
view2.query.ast = newQuery.ast;
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
} else {
|
|
1057
|
+
Obj.update(view, (view2) => {
|
|
1058
|
+
view2.query.ast = baseQuery.ast;
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
this._registry.set(this._inMemorySort, void 0);
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Extracts the base query without order clauses.
|
|
1065
|
+
*/
|
|
1066
|
+
_getBaseQuery(query) {
|
|
1067
|
+
const ast = query.ast;
|
|
1068
|
+
if (ast.type === "order") {
|
|
1069
|
+
return Query.fromAst(ast.query);
|
|
1070
|
+
}
|
|
1071
|
+
return query;
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Checks if the view has unsaved changes (in-memory sort differs from persisted sort).
|
|
1075
|
+
*/
|
|
1076
|
+
getViewDirty() {
|
|
1077
|
+
return this._registry.get(this._viewDirty);
|
|
1116
1078
|
}
|
|
1117
1079
|
};
|
|
1118
1080
|
var editorTextToCellValue = (props, value) => {
|
|
1119
1081
|
switch (props.format) {
|
|
1120
|
-
case
|
|
1121
|
-
if (
|
|
1082
|
+
case Format2.TypeFormat.Ref: {
|
|
1083
|
+
if (Obj.isObject(value)) {
|
|
1122
1084
|
return Ref.make(value);
|
|
1123
1085
|
} else {
|
|
1124
1086
|
return value;
|
|
1125
1087
|
}
|
|
1126
1088
|
}
|
|
1127
|
-
case
|
|
1089
|
+
case Format2.TypeFormat.SingleSelect: {
|
|
1128
1090
|
const ids = extractTagIds(value);
|
|
1129
1091
|
if (ids && ids.length > 0) {
|
|
1130
1092
|
return ids[0];
|
|
@@ -1132,7 +1094,7 @@ var editorTextToCellValue = (props, value) => {
|
|
|
1132
1094
|
return value;
|
|
1133
1095
|
}
|
|
1134
1096
|
}
|
|
1135
|
-
case
|
|
1097
|
+
case Format2.TypeFormat.MultiSelect: {
|
|
1136
1098
|
const ids = extractTagIds(value);
|
|
1137
1099
|
return ids || value;
|
|
1138
1100
|
}
|
|
@@ -1146,104 +1108,40 @@ var editorTextToCellValue = (props, value) => {
|
|
|
1146
1108
|
}
|
|
1147
1109
|
};
|
|
1148
1110
|
|
|
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
1111
|
// src/model/table-presentation.ts
|
|
1216
|
-
import {
|
|
1112
|
+
import { Atom as Atom3 } from "@effect-atom/atom-react";
|
|
1217
1113
|
import * as Predicate from "effect/Predicate";
|
|
1218
|
-
import { Obj as
|
|
1219
|
-
import {
|
|
1220
|
-
import { cellClassesForFieldType, formatForDisplay
|
|
1114
|
+
import { Obj as Obj2 } from "@dxos/echo";
|
|
1115
|
+
import { Format as Format3, TypeEnum, getValue as getValue2 } from "@dxos/echo/internal";
|
|
1116
|
+
import { cellClassesForFieldType, formatForDisplay } from "@dxos/react-ui-form";
|
|
1221
1117
|
import { toPlaneCellIndex } from "@dxos/react-ui-grid";
|
|
1222
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
1223
1118
|
import { VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
1119
|
+
import { mx } from "@dxos/ui-theme";
|
|
1224
1120
|
var TablePresentation = class {
|
|
1225
1121
|
model;
|
|
1122
|
+
_registry;
|
|
1226
1123
|
_visibleRange;
|
|
1227
1124
|
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
|
-
})) {
|
|
1125
|
+
constructor(registry, model) {
|
|
1238
1126
|
this.model = model;
|
|
1239
|
-
this.
|
|
1127
|
+
this._registry = registry;
|
|
1128
|
+
this._visibleRange = Atom3.make({
|
|
1129
|
+
start: {
|
|
1130
|
+
row: 0,
|
|
1131
|
+
col: 0
|
|
1132
|
+
},
|
|
1133
|
+
end: {
|
|
1134
|
+
row: 0,
|
|
1135
|
+
col: 0
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1240
1138
|
}
|
|
1241
1139
|
getCells(range, plane) {
|
|
1242
1140
|
this.fieldProjectionCache.clear();
|
|
1243
1141
|
let cells;
|
|
1244
1142
|
switch (plane) {
|
|
1245
1143
|
case "grid":
|
|
1246
|
-
this._visibleRange
|
|
1144
|
+
this._registry.set(this._visibleRange, range);
|
|
1247
1145
|
cells = this.getMainGridCells(range);
|
|
1248
1146
|
break;
|
|
1249
1147
|
case "frozenRowsStart":
|
|
@@ -1295,7 +1193,7 @@ var TablePresentation = class {
|
|
|
1295
1193
|
const { props } = this.getFieldProjection(field.id);
|
|
1296
1194
|
const cell = {
|
|
1297
1195
|
get value() {
|
|
1298
|
-
const value =
|
|
1196
|
+
const value = getValue2(obj, field.path);
|
|
1299
1197
|
if (value == null) {
|
|
1300
1198
|
return "";
|
|
1301
1199
|
}
|
|
@@ -1303,19 +1201,19 @@ var TablePresentation = class {
|
|
|
1303
1201
|
return "";
|
|
1304
1202
|
}
|
|
1305
1203
|
switch (props.format) {
|
|
1306
|
-
case
|
|
1307
|
-
case
|
|
1308
|
-
case
|
|
1204
|
+
case Format3.TypeFormat.Boolean:
|
|
1205
|
+
case Format3.TypeFormat.SingleSelect:
|
|
1206
|
+
case Format3.TypeFormat.MultiSelect: {
|
|
1309
1207
|
return "";
|
|
1310
1208
|
}
|
|
1311
|
-
case
|
|
1209
|
+
case Format3.TypeFormat.Ref: {
|
|
1312
1210
|
if (!field.referencePath) {
|
|
1313
1211
|
return "";
|
|
1314
1212
|
}
|
|
1315
|
-
return
|
|
1213
|
+
return getValue2(value.target, field.referencePath);
|
|
1316
1214
|
}
|
|
1317
1215
|
default: {
|
|
1318
|
-
return
|
|
1216
|
+
return formatForDisplay({
|
|
1319
1217
|
type: props.type,
|
|
1320
1218
|
format: props.format,
|
|
1321
1219
|
value
|
|
@@ -1334,8 +1232,8 @@ var TablePresentation = class {
|
|
|
1334
1232
|
classes.push(rowSelectionClasses);
|
|
1335
1233
|
}
|
|
1336
1234
|
cell.className = mx(classes);
|
|
1337
|
-
if (props.type ===
|
|
1338
|
-
const targetArray =
|
|
1235
|
+
if (props.type === TypeEnum.Array) {
|
|
1236
|
+
const targetArray = getValue2(obj, field.path);
|
|
1339
1237
|
if (targetArray && Array.isArray(targetArray)) {
|
|
1340
1238
|
const getLabel = (value) => {
|
|
1341
1239
|
if (!value) {
|
|
@@ -1361,15 +1259,15 @@ var TablePresentation = class {
|
|
|
1361
1259
|
cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
|
|
1362
1260
|
}
|
|
1363
1261
|
}
|
|
1364
|
-
if (props.format ===
|
|
1365
|
-
const targetObj =
|
|
1262
|
+
if (props.format === Format3.TypeFormat.Ref && props.referenceSchema) {
|
|
1263
|
+
const targetObj = getValue2(obj, field.path)?.target;
|
|
1366
1264
|
if (targetObj) {
|
|
1367
|
-
const dxn =
|
|
1368
|
-
cell.accessoryHtml = `<div role="none" class="absolute
|
|
1265
|
+
const dxn = Obj2.getDXN(targetObj)?.toString();
|
|
1266
|
+
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
1267
|
}
|
|
1370
1268
|
}
|
|
1371
|
-
if (props.format ===
|
|
1372
|
-
const value =
|
|
1269
|
+
if (props.format === Format3.TypeFormat.Boolean) {
|
|
1270
|
+
const value = getValue2(obj, field.path);
|
|
1373
1271
|
cell.accessoryHtml = tableControls.switch.render({
|
|
1374
1272
|
colIndex,
|
|
1375
1273
|
rowIndex: displayIndex,
|
|
@@ -1377,8 +1275,8 @@ var TablePresentation = class {
|
|
|
1377
1275
|
});
|
|
1378
1276
|
cell.readonly = "no-text-select";
|
|
1379
1277
|
}
|
|
1380
|
-
if (props.format ===
|
|
1381
|
-
const value =
|
|
1278
|
+
if (props.format === Format3.TypeFormat.SingleSelect) {
|
|
1279
|
+
const value = getValue2(obj, field.path);
|
|
1382
1280
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1383
1281
|
if (options) {
|
|
1384
1282
|
const option = options.find((o) => o.id === value);
|
|
@@ -1387,8 +1285,8 @@ var TablePresentation = class {
|
|
|
1387
1285
|
}
|
|
1388
1286
|
}
|
|
1389
1287
|
}
|
|
1390
|
-
if (props.format ===
|
|
1391
|
-
const values =
|
|
1288
|
+
if (props.format === Format3.TypeFormat.MultiSelect) {
|
|
1289
|
+
const values = getValue2(obj, field.path);
|
|
1392
1290
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1393
1291
|
if (options && values && values.length > 0) {
|
|
1394
1292
|
const tags = values.map((value) => {
|
|
@@ -1411,22 +1309,22 @@ var TablePresentation = class {
|
|
|
1411
1309
|
}
|
|
1412
1310
|
getMainGridCells(range) {
|
|
1413
1311
|
const cells = {};
|
|
1414
|
-
const fields = this.model.projection?.
|
|
1312
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1415
1313
|
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1416
1314
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1417
1315
|
const field = fields[col];
|
|
1418
1316
|
if (!field) {
|
|
1419
1317
|
continue;
|
|
1420
1318
|
}
|
|
1421
|
-
this.createDataCell(cells, this.model.
|
|
1319
|
+
this.createDataCell(cells, this.model.getRows()[row], field, col, row);
|
|
1422
1320
|
}
|
|
1423
1321
|
}
|
|
1424
1322
|
return cells;
|
|
1425
1323
|
}
|
|
1426
1324
|
getDraftRowCells(range) {
|
|
1427
1325
|
const cells = {};
|
|
1428
|
-
const fields = this.model.projection?.
|
|
1429
|
-
const draftRows = this.model.
|
|
1326
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1327
|
+
const draftRows = this.model.getDraftRows();
|
|
1430
1328
|
if (draftRows.length === 0) {
|
|
1431
1329
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1432
1330
|
cells[toPlaneCellIndex({
|
|
@@ -1466,11 +1364,11 @@ var TablePresentation = class {
|
|
|
1466
1364
|
}
|
|
1467
1365
|
getHeaderCells(range) {
|
|
1468
1366
|
const cells = {};
|
|
1469
|
-
const fields = this.model.projection?.
|
|
1367
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1368
|
+
const currentSort = this.model.getSorting();
|
|
1470
1369
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1471
1370
|
const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
|
|
1472
|
-
const
|
|
1473
|
-
const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
|
|
1371
|
+
const direction = currentSort?.fieldId === field.id ? currentSort.direction : void 0;
|
|
1474
1372
|
cells[toPlaneCellIndex({
|
|
1475
1373
|
col,
|
|
1476
1374
|
row: 0
|
|
@@ -1479,7 +1377,7 @@ var TablePresentation = class {
|
|
|
1479
1377
|
value: "",
|
|
1480
1378
|
resizeHandle: "col",
|
|
1481
1379
|
accessoryHtml: `
|
|
1482
|
-
<span class="grow min-
|
|
1380
|
+
<span class="grow min-w-0 truncate">${props.title ?? field.path}</span>
|
|
1483
1381
|
${direction !== void 0 ? tableButtons.sort.render({
|
|
1484
1382
|
fieldId: field.id,
|
|
1485
1383
|
direction
|
|
@@ -1488,7 +1386,7 @@ var TablePresentation = class {
|
|
|
1488
1386
|
fieldId: field.id
|
|
1489
1387
|
})}
|
|
1490
1388
|
`,
|
|
1491
|
-
className: "!bg-
|
|
1389
|
+
className: "!bg-toolbar-surface text-description! [&>div]:flex [&>div]:items-stretch"
|
|
1492
1390
|
};
|
|
1493
1391
|
}
|
|
1494
1392
|
return cells;
|
|
@@ -1539,7 +1437,7 @@ var TablePresentation = class {
|
|
|
1539
1437
|
col: 0,
|
|
1540
1438
|
row: 0
|
|
1541
1439
|
})]: {
|
|
1542
|
-
className: "!bg-
|
|
1440
|
+
className: "!bg-toolbar-surface",
|
|
1543
1441
|
readonly: true,
|
|
1544
1442
|
value: ""
|
|
1545
1443
|
}
|
|
@@ -1553,9 +1451,9 @@ var TablePresentation = class {
|
|
|
1553
1451
|
accessoryHtml: tableControls.checkbox.render({
|
|
1554
1452
|
rowIndex: 0,
|
|
1555
1453
|
header: true,
|
|
1556
|
-
checked: this.model.selection.
|
|
1454
|
+
checked: this.model.selection.allRowsSelected
|
|
1557
1455
|
}),
|
|
1558
|
-
className: "!bg-
|
|
1456
|
+
className: "!bg-toolbar-surface",
|
|
1559
1457
|
readonly: true,
|
|
1560
1458
|
value: ""
|
|
1561
1459
|
}
|
|
@@ -1568,9 +1466,9 @@ var TablePresentation = class {
|
|
|
1568
1466
|
row: 0
|
|
1569
1467
|
})]: {
|
|
1570
1468
|
accessoryHtml: this.model.features.schemaEditable ? tableButtons.addColumn.render({
|
|
1571
|
-
disabled: (this.model.projection?.
|
|
1469
|
+
disabled: (this.model.projection?.getFields()?.length ?? 0) >= VIEW_FIELD_LIMIT
|
|
1572
1470
|
}) : void 0,
|
|
1573
|
-
className: "!bg-
|
|
1471
|
+
className: "!bg-toolbar-surface",
|
|
1574
1472
|
readonly: true,
|
|
1575
1473
|
value: ""
|
|
1576
1474
|
}
|
|
@@ -1578,7 +1476,7 @@ var TablePresentation = class {
|
|
|
1578
1476
|
}
|
|
1579
1477
|
getDraftActionCells(range) {
|
|
1580
1478
|
const cells = {};
|
|
1581
|
-
const draftRows = this.model.
|
|
1479
|
+
const draftRows = this.model.getDraftRows();
|
|
1582
1480
|
if (draftRows.length === 0) {
|
|
1583
1481
|
cells[toPlaneCellIndex({
|
|
1584
1482
|
col: 0,
|
|
@@ -1609,7 +1507,7 @@ var TablePresentation = class {
|
|
|
1609
1507
|
}
|
|
1610
1508
|
getDraftIconCells(range) {
|
|
1611
1509
|
const cells = {};
|
|
1612
|
-
const draftRows = this.model.
|
|
1510
|
+
const draftRows = this.model.getDraftRows();
|
|
1613
1511
|
for (let row = range.start.row; row <= range.end.row; row++) {
|
|
1614
1512
|
cells[toPlaneCellIndex({
|
|
1615
1513
|
col: 0,
|
|
@@ -1628,7 +1526,7 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
|
|
|
1628
1526
|
if (!selected) {
|
|
1629
1527
|
if (selectionMode === "single") {
|
|
1630
1528
|
return [
|
|
1631
|
-
"
|
|
1529
|
+
"cursor-pointer!"
|
|
1632
1530
|
];
|
|
1633
1531
|
} else {
|
|
1634
1532
|
return void 0;
|
|
@@ -1637,111 +1535,23 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
|
|
|
1637
1535
|
switch (selectionMode) {
|
|
1638
1536
|
case "single":
|
|
1639
1537
|
return [
|
|
1640
|
-
"
|
|
1538
|
+
"dx-grid__cell--no-focus-unfurl bg-current-surface! hover:bg-hover-surface cursor-pointer!"
|
|
1641
1539
|
];
|
|
1642
1540
|
case "multiple":
|
|
1643
1541
|
return [
|
|
1644
|
-
"
|
|
1542
|
+
"bg-grid-cell-selected!"
|
|
1645
1543
|
];
|
|
1646
1544
|
}
|
|
1647
1545
|
};
|
|
1648
1546
|
|
|
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
1547
|
// src/hooks/useAddRow.ts
|
|
1738
1548
|
import { useCallback } from "react";
|
|
1739
|
-
import { Obj as
|
|
1740
|
-
var useAddRow = ({
|
|
1549
|
+
import { Obj as Obj3 } from "@dxos/echo";
|
|
1550
|
+
var useAddRow = ({ db, schema }) => {
|
|
1741
1551
|
return useCallback((data) => {
|
|
1742
|
-
if (
|
|
1552
|
+
if (db && schema) {
|
|
1743
1553
|
try {
|
|
1744
|
-
|
|
1554
|
+
db.add(Obj3.make(schema, data ?? {}));
|
|
1745
1555
|
return "final";
|
|
1746
1556
|
} catch (error) {
|
|
1747
1557
|
return "draft";
|
|
@@ -1749,27 +1559,137 @@ var useAddRow = ({ space, schema }) => {
|
|
|
1749
1559
|
}
|
|
1750
1560
|
return "final";
|
|
1751
1561
|
}, [
|
|
1752
|
-
|
|
1562
|
+
db,
|
|
1753
1563
|
schema
|
|
1754
1564
|
]);
|
|
1755
1565
|
};
|
|
1756
1566
|
|
|
1567
|
+
// src/hooks/useProjectionModel.ts
|
|
1568
|
+
import { useState } from "react";
|
|
1569
|
+
import { JsonSchema, Type } from "@dxos/echo";
|
|
1570
|
+
import { useAsyncEffect } from "@dxos/react-ui";
|
|
1571
|
+
import { ProjectionModel, createEchoChangeCallback as createEchoChangeCallback2 } from "@dxos/schema";
|
|
1572
|
+
var useProjectionModel = (schema, table, registry) => {
|
|
1573
|
+
const [projection, setProjection] = useState();
|
|
1574
|
+
useAsyncEffect(async () => {
|
|
1575
|
+
if (schema && table) {
|
|
1576
|
+
const view = await table.view.load();
|
|
1577
|
+
const jsonSchema = Type.isMutable(schema) ? schema.jsonSchema : JsonSchema.toJsonSchema(schema);
|
|
1578
|
+
const change = createEchoChangeCallback2(view, Type.isMutable(schema) ? schema : void 0);
|
|
1579
|
+
const projection2 = new ProjectionModel({
|
|
1580
|
+
registry,
|
|
1581
|
+
view,
|
|
1582
|
+
baseSchema: jsonSchema,
|
|
1583
|
+
change
|
|
1584
|
+
});
|
|
1585
|
+
projection2.normalizeView();
|
|
1586
|
+
setProjection(projection2);
|
|
1587
|
+
}
|
|
1588
|
+
}, [
|
|
1589
|
+
schema,
|
|
1590
|
+
table,
|
|
1591
|
+
registry
|
|
1592
|
+
]);
|
|
1593
|
+
return projection;
|
|
1594
|
+
};
|
|
1595
|
+
|
|
1596
|
+
// src/hooks/useTableModel.ts
|
|
1597
|
+
import { RegistryContext } from "@effect-atom/atom-react";
|
|
1598
|
+
import { useContext, useEffect, useMemo, useState as useState2 } from "react";
|
|
1599
|
+
import { Obj as Obj4 } from "@dxos/echo";
|
|
1600
|
+
import { useSelected, useSelectionActions } from "@dxos/react-ui-attention";
|
|
1601
|
+
import { isNonNullable } from "@dxos/util";
|
|
1602
|
+
var useTableModel = ({ object, projection, db, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
|
|
1603
|
+
const registry = useContext(RegistryContext);
|
|
1604
|
+
const selected = useSelected(object && Obj4.getDXN(object).toString(), "multi");
|
|
1605
|
+
const initialSelection = useMemo(() => selected, [
|
|
1606
|
+
object
|
|
1607
|
+
]);
|
|
1608
|
+
const [model, setModel] = useState2();
|
|
1609
|
+
useEffect(() => {
|
|
1610
|
+
if (!object || !projection) {
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
let model2;
|
|
1614
|
+
const t = setTimeout(async () => {
|
|
1615
|
+
model2 = new TableModel({
|
|
1616
|
+
registry,
|
|
1617
|
+
object,
|
|
1618
|
+
projection,
|
|
1619
|
+
db,
|
|
1620
|
+
change: createEchoChangeCallback(object),
|
|
1621
|
+
features,
|
|
1622
|
+
rowActions,
|
|
1623
|
+
initialSelection,
|
|
1624
|
+
onRowAction,
|
|
1625
|
+
...props
|
|
1626
|
+
});
|
|
1627
|
+
await model2.open();
|
|
1628
|
+
setModel(model2);
|
|
1629
|
+
});
|
|
1630
|
+
return () => {
|
|
1631
|
+
clearTimeout(t);
|
|
1632
|
+
void model2?.close();
|
|
1633
|
+
};
|
|
1634
|
+
}, [
|
|
1635
|
+
registry,
|
|
1636
|
+
object,
|
|
1637
|
+
projection,
|
|
1638
|
+
features,
|
|
1639
|
+
rowActions,
|
|
1640
|
+
initialSelection
|
|
1641
|
+
]);
|
|
1642
|
+
useEffect(() => {
|
|
1643
|
+
if (rows && model) {
|
|
1644
|
+
model.setRows(rows);
|
|
1645
|
+
}
|
|
1646
|
+
}, [
|
|
1647
|
+
model,
|
|
1648
|
+
rows
|
|
1649
|
+
]);
|
|
1650
|
+
const { multiSelect, clear } = useSelectionActions([
|
|
1651
|
+
model?.id
|
|
1652
|
+
].filter(isNonNullable));
|
|
1653
|
+
useEffect(() => {
|
|
1654
|
+
if (!model) {
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
const unsubscribe = registry.subscribe(model.selection.selectionAtom, () => {
|
|
1658
|
+
const selectedItems = [
|
|
1659
|
+
...model.selection.selection
|
|
1660
|
+
];
|
|
1661
|
+
multiSelect(selectedItems);
|
|
1662
|
+
onSelectionChanged?.(selectedItems);
|
|
1663
|
+
});
|
|
1664
|
+
return () => {
|
|
1665
|
+
clear();
|
|
1666
|
+
unsubscribe();
|
|
1667
|
+
};
|
|
1668
|
+
}, [
|
|
1669
|
+
registry,
|
|
1670
|
+
model,
|
|
1671
|
+
onSelectionChanged
|
|
1672
|
+
]);
|
|
1673
|
+
return model;
|
|
1674
|
+
};
|
|
1675
|
+
|
|
1757
1676
|
export {
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1677
|
+
extractOrder,
|
|
1678
|
+
getSortValue,
|
|
1679
|
+
compareValues,
|
|
1761
1680
|
BUTTON_IDENTIFIERS,
|
|
1762
1681
|
tableButtons,
|
|
1763
1682
|
CONTROL_IDENTIFIERS,
|
|
1764
1683
|
CheckboxStory,
|
|
1765
1684
|
SwitchStory,
|
|
1766
1685
|
tableControls,
|
|
1767
|
-
|
|
1686
|
+
createEchoChangeCallback,
|
|
1687
|
+
createDirectChangeCallback,
|
|
1768
1688
|
TableModel,
|
|
1769
|
-
ModalController,
|
|
1770
1689
|
TablePresentation,
|
|
1771
1690
|
cellClassesForRowSelection,
|
|
1772
|
-
|
|
1773
|
-
|
|
1691
|
+
useAddRow,
|
|
1692
|
+
useProjectionModel,
|
|
1693
|
+
useTableModel
|
|
1774
1694
|
};
|
|
1775
|
-
//# sourceMappingURL=chunk-
|
|
1695
|
+
//# sourceMappingURL=chunk-YDXPC7HA.mjs.map
|