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