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