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