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