@dxos/react-ui-table 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5
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-ZAOSIG3L.mjs → chunk-F7Y374KL.mjs} +739 -802
- package/dist/lib/browser/chunk-F7Y374KL.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1208 -1158
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +34 -43
- 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-ZOFFI3JJ.mjs → chunk-CCJ4LOVM.mjs} +739 -801
- package/dist/lib/node-esm/chunk-CCJ4LOVM.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 +1208 -1158
- 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 +34 -43
- 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 +35 -3
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +106 -5
- 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 +21 -19
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +108 -5
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableContent.d.ts +17 -0
- package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts +21 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
- package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +13 -9
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +7 -14
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +38 -5
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
- package/dist/types/src/components/TableCellEditor/index.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 +23 -16
- 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 +6 -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 -8
- 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 +110 -29
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +4 -2
- 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 -34
- 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 -12
- 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 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/query-ast.d.ts +7 -0
- package/dist/types/src/util/query-ast.d.ts.map +1 -0
- package/dist/types/src/util/schema.d.ts +1 -1
- package/dist/types/src/util/schema.d.ts.map +1 -1
- package/dist/types/src/util/sort.d.ts +12 -0
- package/dist/types/src/util/sort.d.ts.map +1 -0
- package/dist/types/src/util/table-buttons.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +58 -57
- package/src/components/Table/ColumnActionsMenu.tsx +15 -11
- package/src/components/Table/ColumnSettings.tsx +8 -9
- package/src/components/Table/DynamicTable.stories.tsx +36 -34
- package/src/components/Table/DynamicTable.tsx +33 -36
- package/src/components/Table/Relations.stories.tsx +180 -59
- package/src/components/Table/RowActionsMenu.tsx +24 -15
- package/src/components/Table/Table.stories.tsx +152 -129
- package/src/components/Table/Table.tsx +46 -391
- package/src/components/Table/TableContent.tsx +421 -0
- package/src/components/Table/TableToolbar.tsx +111 -0
- package/src/components/TableCellEditor/CellValidationMessage.tsx +5 -5
- package/src/components/TableCellEditor/FormCellEditor.tsx +134 -40
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +35 -72
- package/src/components/TableCellEditor/TableCellEditor.tsx +80 -224
- package/src/components/TableCellEditor/index.ts +1 -0
- package/src/components/index.ts +0 -1
- package/src/components/testing.ts +44 -18
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useAddRow.ts +14 -14
- package/src/hooks/useProjectionModel.ts +39 -0
- package/src/hooks/useTableModel.ts +36 -34
- package/src/model/modal-controller.ts +23 -40
- package/src/model/selection-model.ts +75 -44
- package/src/model/table-model.test.ts +91 -56
- package/src/model/table-model.ts +447 -172
- package/src/model/table-presentation.test.ts +68 -58
- package/src/model/table-presentation.ts +97 -73
- package/src/playwright/TableManager.ts +13 -6
- package/src/playwright/playwright.config.ts +1 -1
- package/src/playwright/smoke.spec.ts +92 -46
- package/src/testing/useTestTableModel.ts +50 -40
- 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 +45 -32
- package/src/util/index.ts +2 -1
- package/src/util/query-ast.ts +22 -0
- package/src/util/schema.ts +4 -4
- package/src/util/sort.ts +90 -0
- package/src/util/table-buttons.ts +3 -3
- package/src/util/table-controls.ts +2 -2
- package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
- package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZAOSIG3L.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +0 -20
- package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ZOFFI3JJ.mjs.map +0 -7
- package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
- package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
- package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
- package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
- 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 -53
- package/dist/types/src/model/table-sorting.d.ts.map +0 -1
- package/dist/types/src/types/schema.d.ts +0 -8
- package/dist/types/src/types/schema.d.ts.map +0 -1
- package/dist/types/src/util/table.d.ts +0 -12
- package/dist/types/src/util/table.d.ts.map +0 -1
- package/src/components/Table/CreateRefPanel.tsx +0 -86
- package/src/components/TableCellEditor/extension.ts +0 -61
- package/src/components/TableToolbar/TableToolbar.tsx +0 -102
- package/src/components/TableToolbar/index.ts +0 -5
- package/src/model/table-sorting.ts +0 -216
- package/src/types/schema.ts +0 -16
- package/src/util/table.ts +0 -53
|
@@ -1,120 +1,66 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
TableView
|
|
4
|
-
} from "./chunk-NXZ4CJYX.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
|
-
if (properties && projection.fields) {
|
|
45
|
-
setProperties(view, projection, table, properties);
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
projection,
|
|
49
|
-
view
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
var setProperties = (view, projection, table, properties) => {
|
|
53
|
-
for (const property of properties) {
|
|
54
|
-
const field = projection.fields.find((field2) => field2.path === property.name);
|
|
55
|
-
if (field) {
|
|
56
|
-
if (property.size !== void 0) {
|
|
57
|
-
table.sizes[field.path] = property.size;
|
|
58
|
-
}
|
|
59
|
-
if (property.title !== void 0) {
|
|
60
|
-
const fieldProjection = projection.getFieldProjection(field.id);
|
|
61
|
-
projection.setFieldProjection({
|
|
62
|
-
...fieldProjection,
|
|
63
|
-
props: {
|
|
64
|
-
...fieldProjection.props,
|
|
65
|
-
title: property.title
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
if (property.sort) {
|
|
70
|
-
const fieldId = field.id;
|
|
71
|
-
view.query.sort = [
|
|
72
|
-
{
|
|
73
|
-
fieldId,
|
|
74
|
-
direction: property.sort
|
|
75
|
-
}
|
|
76
|
-
];
|
|
77
|
-
}
|
|
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();
|
|
78
28
|
}
|
|
29
|
+
return String(value);
|
|
79
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;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value === "number") {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
return String(value);
|
|
80
45
|
};
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const shouldIncludeId = props.fields?.find((field) => field === "id") !== void 0;
|
|
100
|
-
const properties = getSchemaProperties(schema.ast, {}, shouldIncludeId);
|
|
101
|
-
for (const property of properties) {
|
|
102
|
-
if (sizes?.[property.name]) {
|
|
103
|
-
table.sizes[property.name] = sizes[property.name];
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
Match.type().pipe(Match.when("boolean", () => {
|
|
107
|
-
table.sizes[property.name] = 100;
|
|
108
|
-
}), Match.when("number", () => {
|
|
109
|
-
table.sizes[property.name] = 100;
|
|
110
|
-
}), Match.orElse(() => {
|
|
111
|
-
}))(property.type);
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
jsonSchema,
|
|
115
|
-
schema,
|
|
116
|
-
view
|
|
117
|
-
};
|
|
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;
|
|
118
64
|
};
|
|
119
65
|
|
|
120
66
|
// src/util/table-buttons.ts
|
|
@@ -126,10 +72,9 @@ var BUTTON_IDENTIFIERS = {
|
|
|
126
72
|
saveDraftRow: "data-table-save-draft-row-button",
|
|
127
73
|
sort: "data-table-sort-button"
|
|
128
74
|
};
|
|
129
|
-
var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
|
|
75
|
+
var createButton = ({ attr, data, disabled = false, icon, testId, type: _type = "primary" }) => {
|
|
130
76
|
const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
131
|
-
|
|
132
|
-
return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? "disabled" : ""} data-dx-grid-action="accessory"><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></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>`;
|
|
133
78
|
};
|
|
134
79
|
var addColumnButton = {
|
|
135
80
|
attr: BUTTON_IDENTIFIERS.newColumn,
|
|
@@ -155,7 +100,8 @@ var columnSettingsButton = {
|
|
|
155
100
|
attr: BUTTON_IDENTIFIERS.columnSettings,
|
|
156
101
|
icon: columnSettingsButton.icon,
|
|
157
102
|
data: {
|
|
158
|
-
"data-field-id": fieldId
|
|
103
|
+
"data-field-id": fieldId,
|
|
104
|
+
"data-variant": "ghost"
|
|
159
105
|
},
|
|
160
106
|
testId: "table-column-settings-button"
|
|
161
107
|
});
|
|
@@ -241,8 +187,8 @@ var CONTROL_IDENTIFIERS = {
|
|
|
241
187
|
switch: "data-table-switch"
|
|
242
188
|
};
|
|
243
189
|
var BASE_CLASSES = {
|
|
244
|
-
checkbox: "absolute inset-
|
|
245
|
-
switch: "absolute inset-
|
|
190
|
+
checkbox: "absolute inset-y-[.375rem] end-[.375rem] dx-checkbox",
|
|
191
|
+
switch: "absolute inset-y-[.25rem] end-[.25rem] dx-checkbox--switch"
|
|
246
192
|
};
|
|
247
193
|
var renderAttributes = (data) => {
|
|
248
194
|
return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
@@ -290,32 +236,17 @@ var tableControls = {
|
|
|
290
236
|
}
|
|
291
237
|
};
|
|
292
238
|
|
|
293
|
-
// src/util/schema.ts
|
|
294
|
-
import { Schema } from "effect";
|
|
295
|
-
import { TypeLiteral, isTypeLiteral } from "effect/SchemaAST";
|
|
296
|
-
var narrowSchema = (schema, paths) => {
|
|
297
|
-
const ast = schema?.ast;
|
|
298
|
-
if (isTypeLiteral(ast)) {
|
|
299
|
-
const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
|
|
300
|
-
if (propertySignatures.length > 0) {
|
|
301
|
-
const narrowType = new TypeLiteral(propertySignatures, []);
|
|
302
|
-
return Schema.make(narrowType);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return void 0;
|
|
306
|
-
};
|
|
307
|
-
|
|
308
239
|
// src/model/table-model.ts
|
|
309
|
-
import {
|
|
240
|
+
import { Atom as Atom2 } from "@effect-atom/atom-react";
|
|
310
241
|
import { Resource as Resource2 } from "@dxos/context";
|
|
311
|
-
import {
|
|
312
|
-
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";
|
|
313
246
|
import { invariant } from "@dxos/invariant";
|
|
314
247
|
import { ObjectId } from "@dxos/keys";
|
|
315
|
-
import { isLiveObject } from "@dxos/live-object";
|
|
316
|
-
import { fullyQualifiedId } from "@dxos/react-client/echo";
|
|
317
248
|
import { formatForEditing, parseValue } from "@dxos/react-ui-form";
|
|
318
|
-
import {
|
|
249
|
+
import { validateSchema } from "@dxos/schema";
|
|
319
250
|
|
|
320
251
|
// src/util/tag.ts
|
|
321
252
|
var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
@@ -334,273 +265,139 @@ var extractTagIds = (value) => {
|
|
|
334
265
|
};
|
|
335
266
|
|
|
336
267
|
// src/model/selection-model.ts
|
|
337
|
-
import {
|
|
268
|
+
import { Atom } from "@effect-atom/atom-react";
|
|
338
269
|
import { Resource } from "@dxos/context";
|
|
339
270
|
var SelectionModel = class extends Resource {
|
|
271
|
+
_registry;
|
|
340
272
|
_rows;
|
|
341
|
-
_selectionMode;
|
|
342
|
-
_initialSelection;
|
|
343
|
-
_onSelectionChanged;
|
|
344
273
|
_selection;
|
|
345
274
|
_validSelectedIds;
|
|
346
275
|
_hasSelection;
|
|
347
276
|
_allSelected;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
277
|
+
_selectionMode;
|
|
278
|
+
_onSelectionChanged;
|
|
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) {
|
|
352
289
|
return /* @__PURE__ */ new Set();
|
|
353
290
|
}
|
|
354
|
-
const validIds = new Set(
|
|
291
|
+
const validIds = new Set(rows2.map((row) => row.id));
|
|
292
|
+
const selection = get(this._selection);
|
|
355
293
|
return new Set([
|
|
356
|
-
...
|
|
294
|
+
...selection
|
|
357
295
|
].filter((id) => validIds.has(id)));
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
|
|
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) {
|
|
361
301
|
return false;
|
|
362
302
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
return this._rows.value.filter((row) => selectedIds.has(row.id));
|
|
367
|
-
}, this.isRowIndexSelected = (rowIndex) => {
|
|
368
|
-
const row = this._rows.value[rowIndex];
|
|
369
|
-
return this._selection.value.has(row.id);
|
|
370
|
-
}, this.isObjectSelected = (object) => {
|
|
371
|
-
return this._selection.value.has(object.id);
|
|
372
|
-
}, this.toggleSelectionForRowIndex = (rowIndex) => {
|
|
373
|
-
const row = this._rows.value[rowIndex];
|
|
374
|
-
const newSelection = new Set(this._selection.value);
|
|
375
|
-
if (newSelection.has(row.id)) {
|
|
376
|
-
newSelection.delete(row.id);
|
|
377
|
-
} else {
|
|
378
|
-
if (this._selectionMode === "single") {
|
|
379
|
-
newSelection.clear();
|
|
380
|
-
}
|
|
381
|
-
newSelection.add(row.id);
|
|
382
|
-
}
|
|
383
|
-
this._selection.value = newSelection;
|
|
384
|
-
}, this.setSelection = (mode) => {
|
|
385
|
-
switch (mode) {
|
|
386
|
-
case "all": {
|
|
387
|
-
this._selection.value = new Set(this._rows.value.map((row) => row.id));
|
|
388
|
-
break;
|
|
389
|
-
}
|
|
390
|
-
case "none": {
|
|
391
|
-
this._selection.value = /* @__PURE__ */ new Set();
|
|
392
|
-
break;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
this._selection = signal(new Set(this._initialSelection));
|
|
303
|
+
const selection = get(this._selection);
|
|
304
|
+
return rows2.every((row) => selection.has(row.id));
|
|
305
|
+
});
|
|
397
306
|
}
|
|
398
307
|
async _open() {
|
|
399
|
-
const
|
|
400
|
-
touch(this._selection.value);
|
|
308
|
+
const selectionUnsubscribe = this._registry.subscribe(this._selection, () => {
|
|
401
309
|
this._onSelectionChanged?.();
|
|
402
310
|
});
|
|
403
|
-
this._ctx.onDispose(
|
|
311
|
+
this._ctx.onDispose(selectionUnsubscribe);
|
|
404
312
|
}
|
|
405
313
|
//
|
|
406
314
|
// Getters
|
|
407
315
|
//
|
|
408
|
-
|
|
316
|
+
/** Get the selection atom for reactive access. */
|
|
317
|
+
get selectionAtom() {
|
|
409
318
|
return this._selection;
|
|
410
319
|
}
|
|
411
|
-
|
|
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() {
|
|
412
326
|
return this._hasSelection;
|
|
413
327
|
}
|
|
414
|
-
|
|
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() {
|
|
415
334
|
return this._allSelected;
|
|
416
335
|
}
|
|
336
|
+
/** Check if all rows are selected. */
|
|
337
|
+
get allRowsSelected() {
|
|
338
|
+
return this._registry.get(this._allSelected);
|
|
339
|
+
}
|
|
417
340
|
get selectionMode() {
|
|
418
341
|
return this._selectionMode;
|
|
419
342
|
}
|
|
420
|
-
getSelectedRows
|
|
421
|
-
|
|
422
|
-
|
|
343
|
+
getSelectedRows = () => {
|
|
344
|
+
const selectedIds = this._registry.get(this._validSelectedIds);
|
|
345
|
+
return this._registry.get(this._rows).filter((row) => selectedIds.has(row.id));
|
|
346
|
+
};
|
|
347
|
+
isRowIndexSelected = (rowIndex) => {
|
|
348
|
+
const row = this._registry.get(this._rows)[rowIndex];
|
|
349
|
+
return this._registry.get(this._selection).has(row.id);
|
|
350
|
+
};
|
|
351
|
+
isObjectSelected = (object) => {
|
|
352
|
+
return this._registry.get(this._selection).has(object.id);
|
|
353
|
+
};
|
|
423
354
|
//
|
|
424
355
|
// Manipulation
|
|
425
356
|
//
|
|
426
|
-
toggleSelectionForRowIndex
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
var TableSorting = class {
|
|
436
|
-
_view;
|
|
437
|
-
_projection;
|
|
438
|
-
_displayToDataIndex;
|
|
439
|
-
_rows;
|
|
440
|
-
_localSort;
|
|
441
|
-
_isDirty;
|
|
442
|
-
sortedRows;
|
|
443
|
-
constructor(rows, _view, _projection) {
|
|
444
|
-
this._view = _view;
|
|
445
|
-
this._projection = _projection;
|
|
446
|
-
this._displayToDataIndex = /* @__PURE__ */ new Map();
|
|
447
|
-
this._localSort = signal2(void 0);
|
|
448
|
-
this._rows = rows;
|
|
449
|
-
this._isDirty = computed2(() => {
|
|
450
|
-
const local = this._localSort.value;
|
|
451
|
-
const viewSort = this._view.query.sort?.[0];
|
|
452
|
-
if (local?.type === "cleared") {
|
|
453
|
-
return viewSort !== void 0;
|
|
454
|
-
}
|
|
455
|
-
if (local?.type === "active") {
|
|
456
|
-
if (!viewSort) {
|
|
457
|
-
return true;
|
|
458
|
-
}
|
|
459
|
-
return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
|
|
460
|
-
}
|
|
461
|
-
return false;
|
|
462
|
-
});
|
|
463
|
-
this.sortedRows = this.initialiseSortedRows();
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* @reactive
|
|
467
|
-
* @returns Local sort if present, falls back to view sort.
|
|
468
|
-
*/
|
|
469
|
-
get sorting() {
|
|
470
|
-
const local = this._localSort.value;
|
|
471
|
-
if (local?.type === "cleared") {
|
|
472
|
-
return void 0;
|
|
473
|
-
}
|
|
474
|
-
if (local?.type === "active") {
|
|
475
|
-
return local.sort;
|
|
476
|
-
}
|
|
477
|
-
return this._view.query.sort?.[0];
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* @reactive
|
|
481
|
-
* @returns Whether local sort differs from view sort.
|
|
482
|
-
*/
|
|
483
|
-
get isDirty() {
|
|
484
|
-
return this._isDirty.value;
|
|
485
|
-
}
|
|
486
|
-
getDataIndex(displayIndex) {
|
|
487
|
-
return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
|
|
488
|
-
}
|
|
489
|
-
setSort(fieldId, direction) {
|
|
490
|
-
this._localSort.value = {
|
|
491
|
-
type: "active",
|
|
492
|
-
sort: {
|
|
493
|
-
fieldId,
|
|
494
|
-
direction
|
|
357
|
+
toggleSelectionForRowIndex = (rowIndex) => {
|
|
358
|
+
const row = this._registry.get(this._rows)[rowIndex];
|
|
359
|
+
const currentSelection = this._registry.get(this._selection);
|
|
360
|
+
const newSelection = new Set(currentSelection);
|
|
361
|
+
if (newSelection.has(row.id)) {
|
|
362
|
+
newSelection.delete(row.id);
|
|
363
|
+
} else {
|
|
364
|
+
if (this._selectionMode === "single") {
|
|
365
|
+
newSelection.clear();
|
|
495
366
|
}
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
toggleSort(fieldId) {
|
|
499
|
-
if (!this.sorting || this.sorting.fieldId !== fieldId) {
|
|
500
|
-
return;
|
|
367
|
+
newSelection.add(row.id);
|
|
501
368
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
369
|
+
this._registry.set(this._selection, newSelection);
|
|
370
|
+
};
|
|
371
|
+
setSelection = (mode) => {
|
|
372
|
+
switch (mode) {
|
|
373
|
+
case "all": {
|
|
374
|
+
this._registry.set(this._selection, new Set(this._registry.get(this._rows).map((row) => row.id)));
|
|
505
375
|
break;
|
|
506
376
|
}
|
|
507
|
-
case "
|
|
508
|
-
this.
|
|
377
|
+
case "none": {
|
|
378
|
+
this._registry.set(this._selection, /* @__PURE__ */ new Set());
|
|
509
379
|
break;
|
|
510
380
|
}
|
|
511
381
|
}
|
|
512
|
-
}
|
|
513
|
-
clearSort() {
|
|
514
|
-
this._localSort.value = {
|
|
515
|
-
type: "cleared"
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
save() {
|
|
519
|
-
if (this._localSort.value !== void 0) {
|
|
520
|
-
if (this._localSort.value.type === "active") {
|
|
521
|
-
this._view.query.sort = [
|
|
522
|
-
this._localSort.value.sort
|
|
523
|
-
];
|
|
524
|
-
} else {
|
|
525
|
-
this._view.query.sort = [];
|
|
526
|
-
}
|
|
527
|
-
this._localSort.value = void 0;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
//
|
|
531
|
-
// Initialisation.
|
|
532
|
-
//
|
|
533
|
-
initialiseSortedRows() {
|
|
534
|
-
return computed2(() => {
|
|
535
|
-
this._displayToDataIndex.clear();
|
|
536
|
-
const sort = this.sorting;
|
|
537
|
-
if (!sort) {
|
|
538
|
-
return this._rows.value;
|
|
539
|
-
}
|
|
540
|
-
const field = this._projection.fields.find((f) => f.id === sort.fieldId);
|
|
541
|
-
if (!field) {
|
|
542
|
-
return this._rows.value;
|
|
543
|
-
}
|
|
544
|
-
const { props } = this._projection.getFieldProjection(field.id);
|
|
545
|
-
const dataWithIndices = this._rows.value.map((item, index) => {
|
|
546
|
-
const sortValue = this.getSortValue(props, field, item);
|
|
547
|
-
const isEmpty = !(props.type === TypeEnum.Boolean) && (sortValue == null || sortValue === "");
|
|
548
|
-
return {
|
|
549
|
-
item,
|
|
550
|
-
index,
|
|
551
|
-
value: sortValue,
|
|
552
|
-
isEmpty
|
|
553
|
-
};
|
|
554
|
-
});
|
|
555
|
-
const ordered = orderBy(dataWithIndices, [
|
|
556
|
-
"isEmpty",
|
|
557
|
-
"value"
|
|
558
|
-
], [
|
|
559
|
-
"asc",
|
|
560
|
-
sort.direction
|
|
561
|
-
]);
|
|
562
|
-
ordered.forEach(({ index: dataIndex }, displayIndex) => {
|
|
563
|
-
if (displayIndex !== dataIndex) {
|
|
564
|
-
this._displayToDataIndex.set(displayIndex, dataIndex);
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
return ordered.map(({ item }) => item);
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
getSortValue(props, field, item) {
|
|
571
|
-
const { type, format } = props;
|
|
572
|
-
const value = getValue(item, field.path);
|
|
573
|
-
if (type === TypeEnum.Boolean) {
|
|
574
|
-
return !!value;
|
|
575
|
-
}
|
|
576
|
-
if (type === TypeEnum.Number) {
|
|
577
|
-
return value;
|
|
578
|
-
}
|
|
579
|
-
if (value == null) {
|
|
580
|
-
return value;
|
|
581
|
-
}
|
|
582
|
-
if (format === FormatEnum.SingleSelect) {
|
|
583
|
-
const options = props.options;
|
|
584
|
-
if (!options) {
|
|
585
|
-
return void 0;
|
|
586
|
-
}
|
|
587
|
-
const option = options.find((option2) => option2.id === value);
|
|
588
|
-
return option ? options.indexOf(option) : void 0;
|
|
589
|
-
}
|
|
590
|
-
if (format === FormatEnum.Ref && field.referencePath) {
|
|
591
|
-
const refValue = getValue(value.target, field.referencePath);
|
|
592
|
-
return refValue;
|
|
593
|
-
}
|
|
594
|
-
return formatForDisplay({
|
|
595
|
-
type,
|
|
596
|
-
format,
|
|
597
|
-
value
|
|
598
|
-
});
|
|
599
|
-
}
|
|
382
|
+
};
|
|
600
383
|
};
|
|
601
384
|
|
|
602
385
|
// src/model/table-model.ts
|
|
603
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, (table2) => mutate(table2)),
|
|
389
|
+
row: (row, mutate) => {
|
|
390
|
+
if (Obj.isObject(row)) {
|
|
391
|
+
Obj.change(row, (row2) => mutate(row2));
|
|
392
|
+
} else {
|
|
393
|
+
mutate(row);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
var createDirectChangeCallback = (table) => ({
|
|
398
|
+
table: (mutate) => mutate(table),
|
|
399
|
+
row: (row, mutate) => mutate(row)
|
|
400
|
+
});
|
|
604
401
|
var defaultFeatures = {
|
|
605
402
|
selection: {
|
|
606
403
|
enabled: true,
|
|
@@ -610,109 +407,206 @@ var defaultFeatures = {
|
|
|
610
407
|
schemaEditable: false
|
|
611
408
|
};
|
|
612
409
|
var TableModel = class extends Resource2 {
|
|
613
|
-
|
|
410
|
+
_registry;
|
|
411
|
+
_object;
|
|
614
412
|
_projection;
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
row: 0,
|
|
619
|
-
col: 0
|
|
620
|
-
},
|
|
621
|
-
end: {
|
|
622
|
-
row: 0,
|
|
623
|
-
col: 0
|
|
624
|
-
}
|
|
625
|
-
});
|
|
413
|
+
_db;
|
|
414
|
+
_change;
|
|
415
|
+
_visibleRange;
|
|
626
416
|
_onInsertRow;
|
|
627
417
|
_onDeleteRows;
|
|
628
|
-
|
|
418
|
+
_onColumnDelete;
|
|
629
419
|
_onCellUpdate;
|
|
630
420
|
_onRowOrderChange;
|
|
631
421
|
_onRowAction;
|
|
632
422
|
_rowActions;
|
|
633
423
|
_features;
|
|
634
|
-
_rows
|
|
635
|
-
_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).
|
|
636
431
|
_sorting;
|
|
432
|
+
// Derived atom for sorted rows (used by rows getter and SelectionModel).
|
|
433
|
+
_sortedRows;
|
|
434
|
+
// Derived atom for viewDirty state.
|
|
435
|
+
_viewDirty;
|
|
637
436
|
_pinnedRows;
|
|
638
437
|
_selection;
|
|
639
438
|
_columnMeta;
|
|
640
|
-
|
|
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 = {
|
|
641
442
|
top: [],
|
|
642
443
|
bottom: []
|
|
643
|
-
}, rowActions = [], onCellUpdate,
|
|
444
|
+
}, rowActions = [], onCellUpdate, onColumnDelete, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
|
|
644
445
|
super();
|
|
645
|
-
this.
|
|
646
|
-
this.
|
|
446
|
+
this._registry = registry;
|
|
447
|
+
this._object = object;
|
|
448
|
+
this._projection = projection;
|
|
449
|
+
this._projection.normalizeView();
|
|
450
|
+
this._db = db;
|
|
451
|
+
this._change = change ?? createEchoChangeCallback(object);
|
|
647
452
|
this._features = {
|
|
648
453
|
...defaultFeatures,
|
|
649
454
|
...features
|
|
650
455
|
};
|
|
651
456
|
invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
|
|
652
457
|
F: __dxlog_file,
|
|
653
|
-
L:
|
|
458
|
+
L: 197,
|
|
654
459
|
S: this,
|
|
655
460
|
A: [
|
|
656
461
|
"!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
|
|
657
462
|
"'Single selection is not compatible with editable tables.'"
|
|
658
463
|
]
|
|
659
464
|
});
|
|
660
|
-
this.
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
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
|
+
});
|
|
666
533
|
this._pinnedRows = pinnedRows;
|
|
667
534
|
this._rowActions = rowActions;
|
|
668
535
|
this._onInsertRow = onInsertRow;
|
|
669
536
|
this._onDeleteRows = onDeleteRows;
|
|
670
|
-
this.
|
|
537
|
+
this._onColumnDelete = onColumnDelete;
|
|
671
538
|
this._onCellUpdate = onCellUpdate;
|
|
672
539
|
this._onRowOrderChange = onRowOrderChange;
|
|
673
540
|
this._onRowAction = onRowAction;
|
|
674
541
|
}
|
|
675
542
|
get id() {
|
|
676
|
-
return
|
|
543
|
+
return Obj.getDXN(this._object).toString();
|
|
677
544
|
}
|
|
678
545
|
get view() {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
get table() {
|
|
682
|
-
invariant(this._table, "Model not initialized", {
|
|
546
|
+
const view = this._object.view.target;
|
|
547
|
+
invariant(view, "Table model not initialized", {
|
|
683
548
|
F: __dxlog_file,
|
|
684
|
-
L:
|
|
549
|
+
L: 308,
|
|
685
550
|
S: this,
|
|
686
551
|
A: [
|
|
687
|
-
"
|
|
688
|
-
"'
|
|
552
|
+
"view",
|
|
553
|
+
"'Table model not initialized'"
|
|
689
554
|
]
|
|
690
555
|
});
|
|
691
|
-
return
|
|
556
|
+
return view;
|
|
557
|
+
}
|
|
558
|
+
get table() {
|
|
559
|
+
return this._object;
|
|
692
560
|
}
|
|
693
561
|
get projection() {
|
|
694
562
|
return this._projection;
|
|
695
563
|
}
|
|
564
|
+
get db() {
|
|
565
|
+
return this._db;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Atom for reactive access to rows with in-memory sorting applied.
|
|
569
|
+
*/
|
|
696
570
|
get rows() {
|
|
697
|
-
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);
|
|
698
590
|
}
|
|
699
591
|
get features() {
|
|
700
592
|
return this._features;
|
|
701
593
|
}
|
|
702
594
|
/**
|
|
703
|
-
*
|
|
595
|
+
* Gets the current sort state.
|
|
596
|
+
* Priority: in-memory sort (local changes) > persisted sort (from query AST).
|
|
704
597
|
*/
|
|
705
|
-
|
|
706
|
-
return this._sorting;
|
|
598
|
+
getSorting() {
|
|
599
|
+
return this._registry.get(this._sorting);
|
|
707
600
|
}
|
|
708
601
|
/**
|
|
709
602
|
* Gets the row data at the specified display index.
|
|
710
603
|
*/
|
|
711
604
|
getRowAt(displayIndex) {
|
|
712
|
-
|
|
605
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
606
|
+
if (displayIndex < 0 || displayIndex >= sortedRows.length) {
|
|
713
607
|
return void 0;
|
|
714
608
|
}
|
|
715
|
-
return
|
|
609
|
+
return sortedRows[displayIndex];
|
|
716
610
|
}
|
|
717
611
|
get pinnedRows() {
|
|
718
612
|
return this._pinnedRows;
|
|
@@ -720,7 +614,7 @@ var TableModel = class extends Resource2 {
|
|
|
720
614
|
get columnMeta() {
|
|
721
615
|
invariant(this._columnMeta, void 0, {
|
|
722
616
|
F: __dxlog_file,
|
|
723
|
-
L:
|
|
617
|
+
L: 381,
|
|
724
618
|
S: this,
|
|
725
619
|
A: [
|
|
726
620
|
"this._columnMeta",
|
|
@@ -732,10 +626,6 @@ var TableModel = class extends Resource2 {
|
|
|
732
626
|
get selection() {
|
|
733
627
|
return this._selection;
|
|
734
628
|
}
|
|
735
|
-
/** @reactive */
|
|
736
|
-
get isViewDirty() {
|
|
737
|
-
return this.sorting.isDirty;
|
|
738
|
-
}
|
|
739
629
|
get rowActions() {
|
|
740
630
|
return this._rowActions;
|
|
741
631
|
}
|
|
@@ -743,24 +633,23 @@ var TableModel = class extends Resource2 {
|
|
|
743
633
|
// Initialisation
|
|
744
634
|
//
|
|
745
635
|
async _open() {
|
|
746
|
-
|
|
747
|
-
invariant(Obj3.instanceOf(TableView, presentation), void 0, {
|
|
748
|
-
F: __dxlog_file,
|
|
749
|
-
L: 241,
|
|
750
|
-
S: this,
|
|
751
|
-
A: [
|
|
752
|
-
"Obj.instanceOf(TableView, presentation)",
|
|
753
|
-
""
|
|
754
|
-
]
|
|
755
|
-
});
|
|
756
|
-
this._table = presentation;
|
|
636
|
+
await this._object.view.load();
|
|
757
637
|
this.initializeColumnMeta();
|
|
758
638
|
this.initializeEffects();
|
|
759
639
|
await this._selection.open(this._ctx);
|
|
760
640
|
}
|
|
761
641
|
initializeColumnMeta() {
|
|
762
|
-
this.
|
|
763
|
-
|
|
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);
|
|
764
653
|
const meta = Object.fromEntries(fields.map((field, index) => [
|
|
765
654
|
index,
|
|
766
655
|
{
|
|
@@ -778,7 +667,7 @@ var TableModel = class extends Resource2 {
|
|
|
778
667
|
},
|
|
779
668
|
frozenColsEnd: {
|
|
780
669
|
0: {
|
|
781
|
-
size:
|
|
670
|
+
size: 32,
|
|
782
671
|
resizeable: false
|
|
783
672
|
}
|
|
784
673
|
}
|
|
@@ -786,49 +675,62 @@ var TableModel = class extends Resource2 {
|
|
|
786
675
|
});
|
|
787
676
|
}
|
|
788
677
|
initializeEffects() {
|
|
789
|
-
const
|
|
790
|
-
touch(this.sorting.sortedRows.value);
|
|
678
|
+
const rowsUnsubscribe = this._registry.subscribe(this._rows, () => {
|
|
791
679
|
this._onRowOrderChange?.();
|
|
792
680
|
});
|
|
793
|
-
this._ctx.onDispose(
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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
|
+
});
|
|
805
700
|
});
|
|
806
|
-
|
|
701
|
+
rowSubscriptions.set(obj.id, unsub);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
this._ctx.onDispose(() => {
|
|
706
|
+
visibleRangeUnsubscribe();
|
|
707
|
+
for (const unsub of rowSubscriptions.values()) {
|
|
708
|
+
unsub();
|
|
807
709
|
}
|
|
808
|
-
return () => rowEffects.forEach((cleanup) => cleanup());
|
|
809
710
|
});
|
|
810
|
-
this.
|
|
811
|
-
const draftRowsWatcher = effect2(() => {
|
|
812
|
-
touch(this._draftRows.value);
|
|
711
|
+
const draftRowsUnsubscribe = this._registry.subscribe(this._draftRows, () => {
|
|
813
712
|
this._onRowOrderChange?.();
|
|
814
713
|
});
|
|
815
|
-
this._ctx.onDispose(
|
|
714
|
+
this._ctx.onDispose(draftRowsUnsubscribe);
|
|
816
715
|
}
|
|
817
716
|
//
|
|
818
717
|
// Data
|
|
819
718
|
//
|
|
820
719
|
setRows = (obj) => {
|
|
821
|
-
this._rows
|
|
720
|
+
this._registry.set(this._rows, obj);
|
|
822
721
|
};
|
|
823
|
-
getRowCount = () => this.
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
// 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. */
|
|
829
727
|
get draftRows() {
|
|
830
728
|
return this._draftRows;
|
|
831
729
|
}
|
|
730
|
+
/** Gets the current draft rows. */
|
|
731
|
+
getDraftRows() {
|
|
732
|
+
return this._registry.get(this._draftRows);
|
|
733
|
+
}
|
|
832
734
|
/**
|
|
833
735
|
* Checks if a specific field path has validation errors for a given draft row.
|
|
834
736
|
* @param draftRowIndex - The index of the draft row to check
|
|
@@ -836,19 +738,20 @@ var TableModel = class extends Resource2 {
|
|
|
836
738
|
* @returns true if the field has validation errors, false otherwise
|
|
837
739
|
*/
|
|
838
740
|
hasDraftRowValidationError(draftRowIndex, fieldPath) {
|
|
839
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
741
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
840
742
|
return false;
|
|
841
743
|
}
|
|
842
|
-
const draftRow = this._draftRows
|
|
744
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
843
745
|
const validationErrors = draftRow.validationErrors || [];
|
|
844
746
|
return validationErrors.some((error) => error.path === fieldPath);
|
|
845
747
|
}
|
|
846
|
-
getColumnCount = () => this._projection?.
|
|
748
|
+
getColumnCount = () => this._projection?.getFields().length ?? 0;
|
|
847
749
|
insertRow = () => {
|
|
848
750
|
const result = this._onInsertRow?.();
|
|
849
|
-
if (result ===
|
|
751
|
+
if (result === "draft" && this._registry.get(this._draftRows).length === 0) {
|
|
850
752
|
this.createDraftRow();
|
|
851
753
|
}
|
|
754
|
+
return result ?? "final";
|
|
852
755
|
};
|
|
853
756
|
createDraftRow() {
|
|
854
757
|
if (!this._projection) {
|
|
@@ -863,16 +766,16 @@ var TableModel = class extends Resource2 {
|
|
|
863
766
|
valid: validationErrors.length === 0,
|
|
864
767
|
validationErrors
|
|
865
768
|
};
|
|
866
|
-
this._draftRows
|
|
867
|
-
...this._draftRows
|
|
769
|
+
this._registry.set(this._draftRows, [
|
|
770
|
+
...this._registry.get(this._draftRows),
|
|
868
771
|
draftRow
|
|
869
|
-
];
|
|
772
|
+
]);
|
|
870
773
|
}
|
|
871
774
|
validateDraftRow(draftRowIndex) {
|
|
872
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
775
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
873
776
|
return;
|
|
874
777
|
}
|
|
875
|
-
const draftRow = this._draftRows
|
|
778
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
876
779
|
const validationErrors = this.validateDraftRowData(draftRow.data);
|
|
877
780
|
const updatedDraftRow = {
|
|
878
781
|
...draftRow,
|
|
@@ -880,80 +783,82 @@ var TableModel = class extends Resource2 {
|
|
|
880
783
|
validationErrors
|
|
881
784
|
};
|
|
882
785
|
const newDraftRows = [
|
|
883
|
-
...this._draftRows
|
|
786
|
+
...this._registry.get(this._draftRows)
|
|
884
787
|
];
|
|
885
788
|
newDraftRows[draftRowIndex] = updatedDraftRow;
|
|
886
|
-
this._draftRows
|
|
789
|
+
this._registry.set(this._draftRows, newDraftRows);
|
|
887
790
|
}
|
|
888
791
|
validateDraftRowData(data) {
|
|
889
|
-
const schema =
|
|
792
|
+
const schema = toEffectSchema(this._projection.baseSchema);
|
|
890
793
|
return validateSchema(schema, data) || [];
|
|
891
794
|
}
|
|
892
795
|
commitDraftRow = (draftRowIndex) => {
|
|
893
|
-
if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.
|
|
796
|
+
if (draftRowIndex < 0 || draftRowIndex >= this._registry.get(this._draftRows).length) {
|
|
894
797
|
return false;
|
|
895
798
|
}
|
|
896
|
-
const draftRow = this._draftRows
|
|
799
|
+
const draftRow = this._registry.get(this._draftRows)[draftRowIndex];
|
|
897
800
|
if (!draftRow.valid) {
|
|
898
801
|
return false;
|
|
899
802
|
}
|
|
900
|
-
const
|
|
901
|
-
if (
|
|
902
|
-
const newDraftRows = this._draftRows.
|
|
903
|
-
this._draftRows
|
|
803
|
+
const insertRowResult = this._onInsertRow?.(draftRow.data);
|
|
804
|
+
if (insertRowResult === "final") {
|
|
805
|
+
const newDraftRows = this._registry.get(this._draftRows).filter((_, index) => index !== draftRowIndex);
|
|
806
|
+
this._registry.set(this._draftRows, newDraftRows);
|
|
904
807
|
}
|
|
905
|
-
return
|
|
808
|
+
return insertRowResult === "final";
|
|
906
809
|
};
|
|
907
810
|
deleteRow = (rowIndex) => {
|
|
908
|
-
const
|
|
909
|
-
const obj =
|
|
811
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
812
|
+
const obj = sortedRows[rowIndex];
|
|
910
813
|
const objectsToDelete = [];
|
|
911
|
-
if (this.features.selection.enabled && this._selection.hasSelection
|
|
814
|
+
if (this.features.selection.enabled && this._selection.hasSelection) {
|
|
912
815
|
const selectedRows = this._selection.getSelectedRows();
|
|
913
816
|
objectsToDelete.push(...selectedRows);
|
|
914
|
-
} else {
|
|
817
|
+
} else if (obj) {
|
|
915
818
|
objectsToDelete.push(obj);
|
|
916
819
|
}
|
|
917
|
-
|
|
820
|
+
if (objectsToDelete.length > 0) {
|
|
821
|
+
this._onDeleteRows?.(rowIndex, objectsToDelete);
|
|
822
|
+
}
|
|
918
823
|
};
|
|
919
824
|
handleRowAction = (actionId, rowIndex) => {
|
|
920
825
|
if (!this._onRowAction) {
|
|
921
826
|
return;
|
|
922
827
|
}
|
|
923
|
-
const
|
|
924
|
-
const data =
|
|
828
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
829
|
+
const data = sortedRows[rowIndex];
|
|
925
830
|
if (data) {
|
|
926
831
|
this._onRowAction(actionId, data);
|
|
927
832
|
}
|
|
928
833
|
};
|
|
929
834
|
getCellData = (cell) => {
|
|
930
835
|
const { col, row, plane } = cell;
|
|
931
|
-
const fields = this._projection?.
|
|
836
|
+
const fields = this._projection?.getFields() ?? [];
|
|
932
837
|
if (col < 0 || col >= fields.length) {
|
|
933
838
|
return void 0;
|
|
934
839
|
}
|
|
935
840
|
const field = fields[col];
|
|
936
841
|
let value;
|
|
937
842
|
if (plane === "frozenRowsEnd") {
|
|
938
|
-
if (row >= 0 && row < this._draftRows.
|
|
939
|
-
value =
|
|
843
|
+
if (row >= 0 && row < this._registry.get(this._draftRows).length) {
|
|
844
|
+
value = getValue(this._registry.get(this._draftRows)[row].data, field.path);
|
|
940
845
|
} else {
|
|
941
846
|
return void 0;
|
|
942
847
|
}
|
|
943
848
|
} else {
|
|
944
|
-
const
|
|
945
|
-
value =
|
|
849
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
850
|
+
value = getValue(sortedRows[row], field.path);
|
|
946
851
|
}
|
|
947
852
|
if (value == null) {
|
|
948
853
|
return "";
|
|
949
854
|
}
|
|
950
855
|
const { props } = this._projection.getFieldProjection(field.id);
|
|
951
856
|
switch (props.format) {
|
|
952
|
-
case
|
|
857
|
+
case Format2.TypeFormat.Ref: {
|
|
953
858
|
if (!field.referencePath) {
|
|
954
859
|
return "";
|
|
955
860
|
}
|
|
956
|
-
return
|
|
861
|
+
return getValue(value.target, field.referencePath);
|
|
957
862
|
}
|
|
958
863
|
default: {
|
|
959
864
|
return formatForEditing({
|
|
@@ -965,7 +870,7 @@ var TableModel = class extends Resource2 {
|
|
|
965
870
|
}
|
|
966
871
|
};
|
|
967
872
|
validateCellData = async ({ col, row, plane }, value) => {
|
|
968
|
-
const fields = this._projection?.
|
|
873
|
+
const fields = this._projection?.getFields() ?? [];
|
|
969
874
|
if (col < 0 || col >= fields.length) {
|
|
970
875
|
return {
|
|
971
876
|
valid: false,
|
|
@@ -977,14 +882,14 @@ var TableModel = class extends Resource2 {
|
|
|
977
882
|
const transformedValue = editorTextToCellValue(props, value);
|
|
978
883
|
const isDraftRow = plane === "frozenRowsEnd";
|
|
979
884
|
if (isDraftRow) {
|
|
980
|
-
const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.
|
|
885
|
+
const isInvalidDraftRowIndex = row < 0 || row >= this._registry.get(this._draftRows).length;
|
|
981
886
|
if (isInvalidDraftRowIndex) {
|
|
982
887
|
return {
|
|
983
888
|
valid: false,
|
|
984
889
|
error: "Invalid draft row index"
|
|
985
890
|
};
|
|
986
891
|
}
|
|
987
|
-
const draftRow = this._draftRows
|
|
892
|
+
const draftRow = this._registry.get(this._draftRows)[row];
|
|
988
893
|
const snapshot = {
|
|
989
894
|
...draftRow.data
|
|
990
895
|
};
|
|
@@ -1003,23 +908,24 @@ var TableModel = class extends Resource2 {
|
|
|
1003
908
|
valid: true
|
|
1004
909
|
};
|
|
1005
910
|
} else {
|
|
1006
|
-
const
|
|
1007
|
-
const currentRow = this._rows.value[rowIdx];
|
|
911
|
+
const currentRow = this._registry.get(this._rows)[row];
|
|
1008
912
|
invariant(currentRow, "Invalid row index", {
|
|
1009
913
|
F: __dxlog_file,
|
|
1010
|
-
L:
|
|
914
|
+
L: 693,
|
|
1011
915
|
S: this,
|
|
1012
916
|
A: [
|
|
1013
917
|
"currentRow",
|
|
1014
918
|
"'Invalid row index'"
|
|
1015
919
|
]
|
|
1016
920
|
});
|
|
1017
|
-
const snapshot =
|
|
921
|
+
const snapshot = {
|
|
922
|
+
...getSnapshot(currentRow)
|
|
923
|
+
};
|
|
1018
924
|
setValue(snapshot, field.path, transformedValue);
|
|
1019
|
-
const schema = getSchema(currentRow);
|
|
925
|
+
const schema = Obj.getSchema(currentRow);
|
|
1020
926
|
invariant(schema, void 0, {
|
|
1021
927
|
F: __dxlog_file,
|
|
1022
|
-
L:
|
|
928
|
+
L: 699,
|
|
1023
929
|
S: this,
|
|
1024
930
|
A: [
|
|
1025
931
|
"schema",
|
|
@@ -1031,7 +937,7 @@ var TableModel = class extends Resource2 {
|
|
|
1031
937
|
const error = validationResult[0];
|
|
1032
938
|
invariant(error.path === field.path, void 0, {
|
|
1033
939
|
F: __dxlog_file,
|
|
1034
|
-
L:
|
|
940
|
+
L: 704,
|
|
1035
941
|
S: this,
|
|
1036
942
|
A: [
|
|
1037
943
|
"error.path === field.path",
|
|
@@ -1050,24 +956,27 @@ var TableModel = class extends Resource2 {
|
|
|
1050
956
|
};
|
|
1051
957
|
setCellData = (cell, value) => {
|
|
1052
958
|
const { col, row, plane } = cell;
|
|
1053
|
-
const fields = this._projection?.
|
|
959
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1054
960
|
if (col < 0 || col >= fields.length) {
|
|
1055
961
|
return;
|
|
1056
962
|
}
|
|
1057
963
|
const field = fields[col];
|
|
1058
964
|
const { props } = this._projection.getFieldProjection(field.id);
|
|
1059
965
|
const transformedValue = editorTextToCellValue(props, value);
|
|
1060
|
-
if (props.format ===
|
|
966
|
+
if (props.format === Format2.TypeFormat.Ref && !Obj.isObject(value)) {
|
|
1061
967
|
return;
|
|
1062
968
|
}
|
|
1063
969
|
if (plane === "frozenRowsEnd") {
|
|
1064
|
-
if (row >= 0 && row < this._draftRows.
|
|
1065
|
-
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);
|
|
1066
972
|
this.validateDraftRow(row);
|
|
1067
973
|
}
|
|
1068
974
|
} else {
|
|
1069
|
-
const
|
|
1070
|
-
|
|
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
|
+
});
|
|
1071
980
|
}
|
|
1072
981
|
};
|
|
1073
982
|
/**
|
|
@@ -1076,12 +985,15 @@ var TableModel = class extends Resource2 {
|
|
|
1076
985
|
* @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
|
|
1077
986
|
*/
|
|
1078
987
|
updateCellData({ col, row }, update) {
|
|
1079
|
-
const
|
|
1080
|
-
const fields = this._projection?.fields ?? [];
|
|
988
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1081
989
|
const field = fields[col];
|
|
1082
|
-
const
|
|
990
|
+
const sortedRows = this._registry.get(this._sortedRows);
|
|
991
|
+
const rowData = sortedRows[row];
|
|
992
|
+
const value = getValue(rowData, field.path);
|
|
1083
993
|
const updatedValue = update(value);
|
|
1084
|
-
|
|
994
|
+
this._change.row(rowData, (mutableRow) => {
|
|
995
|
+
setValue(mutableRow, field.path, updatedValue);
|
|
996
|
+
});
|
|
1085
997
|
}
|
|
1086
998
|
/**
|
|
1087
999
|
* Gets the domain-appropriate cell type for a given cell position.
|
|
@@ -1115,21 +1027,23 @@ var TableModel = class extends Resource2 {
|
|
|
1115
1027
|
if (!this._projection) {
|
|
1116
1028
|
return;
|
|
1117
1029
|
}
|
|
1118
|
-
const field = this._projection?.
|
|
1119
|
-
if (field && this.
|
|
1120
|
-
this.
|
|
1030
|
+
const field = this._projection?.getFields().find((field2) => field2.id === fieldId);
|
|
1031
|
+
if (field && this._onColumnDelete) {
|
|
1032
|
+
this._onColumnDelete(field.id);
|
|
1121
1033
|
}
|
|
1122
1034
|
}
|
|
1123
1035
|
//
|
|
1124
1036
|
// Resize
|
|
1125
1037
|
//
|
|
1126
1038
|
setColumnWidth(columnIndex, width) {
|
|
1127
|
-
const fields = this._projection?.
|
|
1039
|
+
const fields = this._projection?.getFields() ?? [];
|
|
1128
1040
|
if (columnIndex < fields.length) {
|
|
1129
1041
|
const newWidth = Math.max(0, width);
|
|
1130
1042
|
const field = fields[columnIndex];
|
|
1131
1043
|
if (field) {
|
|
1132
|
-
this.table
|
|
1044
|
+
this._change.table((mutableTable) => {
|
|
1045
|
+
mutableTable.sizes[field.path] = newWidth;
|
|
1046
|
+
});
|
|
1133
1047
|
}
|
|
1134
1048
|
}
|
|
1135
1049
|
}
|
|
@@ -1145,22 +1059,92 @@ var TableModel = class extends Resource2 {
|
|
|
1145
1059
|
this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
|
|
1146
1060
|
}
|
|
1147
1061
|
//
|
|
1148
|
-
//
|
|
1062
|
+
// Sort operations
|
|
1149
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
|
+
*/
|
|
1150
1100
|
saveView() {
|
|
1151
|
-
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, (view2) => {
|
|
1111
|
+
view2.query.ast = newQuery.ast;
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
} else {
|
|
1115
|
+
Obj.change(view, (view2) => {
|
|
1116
|
+
view2.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);
|
|
1152
1136
|
}
|
|
1153
1137
|
};
|
|
1154
1138
|
var editorTextToCellValue = (props, value) => {
|
|
1155
1139
|
switch (props.format) {
|
|
1156
|
-
case
|
|
1157
|
-
if (
|
|
1140
|
+
case Format2.TypeFormat.Ref: {
|
|
1141
|
+
if (Obj.isObject(value)) {
|
|
1158
1142
|
return Ref.make(value);
|
|
1159
1143
|
} else {
|
|
1160
1144
|
return value;
|
|
1161
1145
|
}
|
|
1162
1146
|
}
|
|
1163
|
-
case
|
|
1147
|
+
case Format2.TypeFormat.SingleSelect: {
|
|
1164
1148
|
const ids = extractTagIds(value);
|
|
1165
1149
|
if (ids && ids.length > 0) {
|
|
1166
1150
|
return ids[0];
|
|
@@ -1168,7 +1152,7 @@ var editorTextToCellValue = (props, value) => {
|
|
|
1168
1152
|
return value;
|
|
1169
1153
|
}
|
|
1170
1154
|
}
|
|
1171
|
-
case
|
|
1155
|
+
case Format2.TypeFormat.MultiSelect: {
|
|
1172
1156
|
const ids = extractTagIds(value);
|
|
1173
1157
|
return ids || value;
|
|
1174
1158
|
}
|
|
@@ -1182,125 +1166,40 @@ var editorTextToCellValue = (props, value) => {
|
|
|
1182
1166
|
}
|
|
1183
1167
|
};
|
|
1184
1168
|
|
|
1185
|
-
// src/model/modal-controller.ts
|
|
1186
|
-
import { signal as signal4 } from "@preact/signals-core";
|
|
1187
|
-
import { log } from "@dxos/log";
|
|
1188
|
-
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
|
|
1189
|
-
var ModalController = class {
|
|
1190
|
-
_state = signal4({
|
|
1191
|
-
type: "closed"
|
|
1192
|
-
});
|
|
1193
|
-
_triggerRef = {
|
|
1194
|
-
current: null
|
|
1195
|
-
};
|
|
1196
|
-
get state() {
|
|
1197
|
-
return this._state;
|
|
1198
|
-
}
|
|
1199
|
-
get trigger() {
|
|
1200
|
-
return this._triggerRef;
|
|
1201
|
-
}
|
|
1202
|
-
setTrigger = (trigger) => {
|
|
1203
|
-
this._triggerRef.current = trigger;
|
|
1204
|
-
};
|
|
1205
|
-
showRowMenu = (rowIndex) => {
|
|
1206
|
-
this._state.value = {
|
|
1207
|
-
type: "row",
|
|
1208
|
-
rowIndex
|
|
1209
|
-
};
|
|
1210
|
-
};
|
|
1211
|
-
showColumnMenu = (fieldId) => {
|
|
1212
|
-
this._state.value = {
|
|
1213
|
-
type: "column",
|
|
1214
|
-
fieldId
|
|
1215
|
-
};
|
|
1216
|
-
};
|
|
1217
|
-
showColumnCreator = () => {
|
|
1218
|
-
this._state.value = {
|
|
1219
|
-
type: "columnSettings",
|
|
1220
|
-
mode: {
|
|
1221
|
-
type: "create"
|
|
1222
|
-
}
|
|
1223
|
-
};
|
|
1224
|
-
};
|
|
1225
|
-
showReferencePanel = (targetId, schemaId) => {
|
|
1226
|
-
this._state.value = {
|
|
1227
|
-
type: "refPanel",
|
|
1228
|
-
targetId,
|
|
1229
|
-
typename: schemaId
|
|
1230
|
-
};
|
|
1231
|
-
};
|
|
1232
|
-
openColumnSettings = () => {
|
|
1233
|
-
if (this._state.value.type === "column") {
|
|
1234
|
-
const fieldId = this._state.value.fieldId;
|
|
1235
|
-
requestAnimationFrame(() => {
|
|
1236
|
-
this._state.value = {
|
|
1237
|
-
type: "columnSettings",
|
|
1238
|
-
mode: {
|
|
1239
|
-
type: "edit",
|
|
1240
|
-
fieldId
|
|
1241
|
-
}
|
|
1242
|
-
};
|
|
1243
|
-
});
|
|
1244
|
-
}
|
|
1245
|
-
};
|
|
1246
|
-
openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
|
|
1247
|
-
if (anchorCell) {
|
|
1248
|
-
this._triggerRef.current = anchorCell;
|
|
1249
|
-
this._state.value = {
|
|
1250
|
-
type: "createRefPanel",
|
|
1251
|
-
typename,
|
|
1252
|
-
initialValues,
|
|
1253
|
-
onCreate
|
|
1254
|
-
};
|
|
1255
|
-
} else {
|
|
1256
|
-
log.warn("anchor cell not found while creating new ref", void 0, {
|
|
1257
|
-
F: __dxlog_file2,
|
|
1258
|
-
L: 86,
|
|
1259
|
-
S: this,
|
|
1260
|
-
C: (f, a) => f(...a)
|
|
1261
|
-
});
|
|
1262
|
-
}
|
|
1263
|
-
};
|
|
1264
|
-
close = () => {
|
|
1265
|
-
this._state.value = {
|
|
1266
|
-
type: "closed"
|
|
1267
|
-
};
|
|
1268
|
-
};
|
|
1269
|
-
};
|
|
1270
|
-
|
|
1271
1169
|
// src/model/table-presentation.ts
|
|
1272
|
-
import {
|
|
1273
|
-
import
|
|
1274
|
-
import { Obj as
|
|
1275
|
-
import {
|
|
1276
|
-
import { cellClassesForFieldType, formatForDisplay
|
|
1170
|
+
import { Atom as Atom3 } from "@effect-atom/atom-react";
|
|
1171
|
+
import * as Predicate from "effect/Predicate";
|
|
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";
|
|
1277
1175
|
import { toPlaneCellIndex } from "@dxos/react-ui-grid";
|
|
1278
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
1279
1176
|
import { VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
1177
|
+
import { mx } from "@dxos/ui-theme";
|
|
1280
1178
|
var TablePresentation = class {
|
|
1281
1179
|
model;
|
|
1180
|
+
_registry;
|
|
1282
1181
|
_visibleRange;
|
|
1283
|
-
fieldProjectionCache;
|
|
1284
|
-
constructor(
|
|
1285
|
-
start: {
|
|
1286
|
-
row: 0,
|
|
1287
|
-
col: 0
|
|
1288
|
-
},
|
|
1289
|
-
end: {
|
|
1290
|
-
row: 0,
|
|
1291
|
-
col: 0
|
|
1292
|
-
}
|
|
1293
|
-
})) {
|
|
1182
|
+
fieldProjectionCache = /* @__PURE__ */ new Map();
|
|
1183
|
+
constructor(registry, model) {
|
|
1294
1184
|
this.model = model;
|
|
1295
|
-
this.
|
|
1296
|
-
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
|
+
});
|
|
1297
1196
|
}
|
|
1298
1197
|
getCells(range, plane) {
|
|
1299
1198
|
this.fieldProjectionCache.clear();
|
|
1300
1199
|
let cells;
|
|
1301
1200
|
switch (plane) {
|
|
1302
1201
|
case "grid":
|
|
1303
|
-
this._visibleRange
|
|
1202
|
+
this._registry.set(this._visibleRange, range);
|
|
1304
1203
|
cells = this.getMainGridCells(range);
|
|
1305
1204
|
break;
|
|
1306
1205
|
case "frozenRowsStart":
|
|
@@ -1322,7 +1221,7 @@ var TablePresentation = class {
|
|
|
1322
1221
|
cells = this.getDraftRowCells(range);
|
|
1323
1222
|
break;
|
|
1324
1223
|
case "fixedEndStart":
|
|
1325
|
-
cells = this.
|
|
1224
|
+
cells = this.getDraftIconCells(range);
|
|
1326
1225
|
break;
|
|
1327
1226
|
case "fixedEndEnd":
|
|
1328
1227
|
cells = this.getDraftActionCells(range);
|
|
@@ -1352,7 +1251,7 @@ var TablePresentation = class {
|
|
|
1352
1251
|
const { props } = this.getFieldProjection(field.id);
|
|
1353
1252
|
const cell = {
|
|
1354
1253
|
get value() {
|
|
1355
|
-
const value =
|
|
1254
|
+
const value = getValue2(obj, field.path);
|
|
1356
1255
|
if (value == null) {
|
|
1357
1256
|
return "";
|
|
1358
1257
|
}
|
|
@@ -1360,19 +1259,19 @@ var TablePresentation = class {
|
|
|
1360
1259
|
return "";
|
|
1361
1260
|
}
|
|
1362
1261
|
switch (props.format) {
|
|
1363
|
-
case
|
|
1364
|
-
case
|
|
1365
|
-
case
|
|
1262
|
+
case Format3.TypeFormat.Boolean:
|
|
1263
|
+
case Format3.TypeFormat.SingleSelect:
|
|
1264
|
+
case Format3.TypeFormat.MultiSelect: {
|
|
1366
1265
|
return "";
|
|
1367
1266
|
}
|
|
1368
|
-
case
|
|
1267
|
+
case Format3.TypeFormat.Ref: {
|
|
1369
1268
|
if (!field.referencePath) {
|
|
1370
1269
|
return "";
|
|
1371
1270
|
}
|
|
1372
|
-
return
|
|
1271
|
+
return getValue2(value.target, field.referencePath);
|
|
1373
1272
|
}
|
|
1374
1273
|
default: {
|
|
1375
|
-
return
|
|
1274
|
+
return formatForDisplay({
|
|
1376
1275
|
type: props.type,
|
|
1377
1276
|
format: props.format,
|
|
1378
1277
|
value
|
|
@@ -1382,10 +1281,7 @@ var TablePresentation = class {
|
|
|
1382
1281
|
}
|
|
1383
1282
|
};
|
|
1384
1283
|
const classes = [];
|
|
1385
|
-
const formatClasses = cellClassesForFieldType(
|
|
1386
|
-
type: props.type,
|
|
1387
|
-
format: props.format
|
|
1388
|
-
});
|
|
1284
|
+
const formatClasses = cellClassesForFieldType(props);
|
|
1389
1285
|
if (formatClasses) {
|
|
1390
1286
|
classes.push(formatClasses);
|
|
1391
1287
|
}
|
|
@@ -1393,11 +1289,9 @@ var TablePresentation = class {
|
|
|
1393
1289
|
if (rowSelectionClasses) {
|
|
1394
1290
|
classes.push(rowSelectionClasses);
|
|
1395
1291
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
if (props.type === TypeEnum2.Array) {
|
|
1400
|
-
const targetArray = getValue3(obj, field.path);
|
|
1292
|
+
cell.className = mx(classes);
|
|
1293
|
+
if (props.type === TypeEnum.Array) {
|
|
1294
|
+
const targetArray = getValue2(obj, field.path);
|
|
1401
1295
|
if (targetArray && Array.isArray(targetArray)) {
|
|
1402
1296
|
const getLabel = (value) => {
|
|
1403
1297
|
if (!value) {
|
|
@@ -1417,21 +1311,21 @@ var TablePresentation = class {
|
|
|
1417
1311
|
}
|
|
1418
1312
|
return "Object";
|
|
1419
1313
|
};
|
|
1420
|
-
const tags = targetArray.map(getLabel).filter(isNotNullable).map((title) => {
|
|
1314
|
+
const tags = targetArray.map(getLabel).filter(Predicate.isNotNullable).map((title) => {
|
|
1421
1315
|
return `<span class="dx-tag" data-hue="neutral">${title}</span>`;
|
|
1422
1316
|
}).join("");
|
|
1423
1317
|
cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
|
|
1424
1318
|
}
|
|
1425
1319
|
}
|
|
1426
|
-
if (props.format ===
|
|
1427
|
-
const targetObj =
|
|
1320
|
+
if (props.format === Format3.TypeFormat.Ref && props.referenceSchema) {
|
|
1321
|
+
const targetObj = getValue2(obj, field.path)?.target;
|
|
1428
1322
|
if (targetObj) {
|
|
1429
|
-
const dxn =
|
|
1430
|
-
cell.accessoryHtml = `<dx-
|
|
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>`;
|
|
1431
1325
|
}
|
|
1432
1326
|
}
|
|
1433
|
-
if (props.format ===
|
|
1434
|
-
const value =
|
|
1327
|
+
if (props.format === Format3.TypeFormat.Boolean) {
|
|
1328
|
+
const value = getValue2(obj, field.path);
|
|
1435
1329
|
cell.accessoryHtml = tableControls.switch.render({
|
|
1436
1330
|
colIndex,
|
|
1437
1331
|
rowIndex: displayIndex,
|
|
@@ -1439,8 +1333,8 @@ var TablePresentation = class {
|
|
|
1439
1333
|
});
|
|
1440
1334
|
cell.readonly = "no-text-select";
|
|
1441
1335
|
}
|
|
1442
|
-
if (props.format ===
|
|
1443
|
-
const value =
|
|
1336
|
+
if (props.format === Format3.TypeFormat.SingleSelect) {
|
|
1337
|
+
const value = getValue2(obj, field.path);
|
|
1444
1338
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1445
1339
|
if (options) {
|
|
1446
1340
|
const option = options.find((o) => o.id === value);
|
|
@@ -1449,8 +1343,8 @@ var TablePresentation = class {
|
|
|
1449
1343
|
}
|
|
1450
1344
|
}
|
|
1451
1345
|
}
|
|
1452
|
-
if (props.format ===
|
|
1453
|
-
const values =
|
|
1346
|
+
if (props.format === Format3.TypeFormat.MultiSelect) {
|
|
1347
|
+
const values = getValue2(obj, field.path);
|
|
1454
1348
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1455
1349
|
if (options && values && values.length > 0) {
|
|
1456
1350
|
const tags = values.map((value) => {
|
|
@@ -1473,63 +1367,75 @@ var TablePresentation = class {
|
|
|
1473
1367
|
}
|
|
1474
1368
|
getMainGridCells(range) {
|
|
1475
1369
|
const cells = {};
|
|
1476
|
-
const fields = this.model.projection?.
|
|
1370
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1477
1371
|
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1478
1372
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1479
1373
|
const field = fields[col];
|
|
1480
1374
|
if (!field) {
|
|
1481
1375
|
continue;
|
|
1482
1376
|
}
|
|
1483
|
-
this.createDataCell(cells, this.model.
|
|
1377
|
+
this.createDataCell(cells, this.model.getRows()[row], field, col, row);
|
|
1484
1378
|
}
|
|
1485
1379
|
}
|
|
1486
1380
|
return cells;
|
|
1487
1381
|
}
|
|
1488
1382
|
getDraftRowCells(range) {
|
|
1489
1383
|
const cells = {};
|
|
1490
|
-
const fields = this.model.projection?.
|
|
1491
|
-
const draftRows = this.model.
|
|
1492
|
-
|
|
1493
|
-
const draftRow = draftRows[row];
|
|
1384
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1385
|
+
const draftRows = this.model.getDraftRows();
|
|
1386
|
+
if (draftRows.length === 0) {
|
|
1494
1387
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1495
|
-
|
|
1388
|
+
cells[toPlaneCellIndex({
|
|
1496
1389
|
col,
|
|
1497
|
-
row
|
|
1498
|
-
})
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1390
|
+
row: 0
|
|
1391
|
+
})] = {
|
|
1392
|
+
value: "",
|
|
1393
|
+
readonly: true,
|
|
1394
|
+
className: "dx-grid__row--cta__cell"
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
} else {
|
|
1398
|
+
for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
|
|
1399
|
+
const draftRow = draftRows[row];
|
|
1400
|
+
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1401
|
+
const cellIndex = toPlaneCellIndex({
|
|
1402
|
+
col,
|
|
1403
|
+
row
|
|
1404
|
+
});
|
|
1405
|
+
const field = fields[col];
|
|
1406
|
+
if (!field) {
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
this.createDataCell(cells, draftRow.data, field, col, row);
|
|
1410
|
+
if (this.model.hasDraftRowValidationError(row, field.path)) {
|
|
1411
|
+
const cellValue = cells[cellIndex];
|
|
1412
|
+
if (cellValue) {
|
|
1413
|
+
const existingClasses = cellValue.className || "";
|
|
1414
|
+
const draftClasses = "dx-grid__cell--flagged";
|
|
1415
|
+
cellValue.className = existingClasses ? `${existingClasses} ${draftClasses}` : draftClasses;
|
|
1416
|
+
}
|
|
1510
1417
|
}
|
|
1511
1418
|
}
|
|
1512
|
-
cells[cellIndex].className += " !bg-toolbarSurface";
|
|
1513
1419
|
}
|
|
1514
1420
|
}
|
|
1515
1421
|
return cells;
|
|
1516
1422
|
}
|
|
1517
1423
|
getHeaderCells(range) {
|
|
1518
1424
|
const cells = {};
|
|
1519
|
-
const fields = this.model.projection?.
|
|
1425
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
1426
|
+
const currentSort = this.model.getSorting();
|
|
1520
1427
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1521
1428
|
const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
|
|
1522
|
-
const
|
|
1523
|
-
const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
|
|
1429
|
+
const direction = currentSort?.fieldId === field.id ? currentSort.direction : void 0;
|
|
1524
1430
|
cells[toPlaneCellIndex({
|
|
1525
1431
|
col,
|
|
1526
1432
|
row: 0
|
|
1527
1433
|
})] = {
|
|
1528
1434
|
// TODO(burdon): Use same logic as form for fallback title.
|
|
1529
|
-
value:
|
|
1530
|
-
readonly: true,
|
|
1435
|
+
value: "",
|
|
1531
1436
|
resizeHandle: "col",
|
|
1532
1437
|
accessoryHtml: `
|
|
1438
|
+
<span class="grow min-w-0 truncate">${props.title ?? field.path}</span>
|
|
1533
1439
|
${direction !== void 0 ? tableButtons.sort.render({
|
|
1534
1440
|
fieldId: field.id,
|
|
1535
1441
|
direction
|
|
@@ -1538,7 +1444,7 @@ var TablePresentation = class {
|
|
|
1538
1444
|
fieldId: field.id
|
|
1539
1445
|
})}
|
|
1540
1446
|
`,
|
|
1541
|
-
className: "!bg-
|
|
1447
|
+
className: "!bg-toolbar-surface text-description! [&>div]:flex [&>div]:items-stretch"
|
|
1542
1448
|
};
|
|
1543
1449
|
}
|
|
1544
1450
|
return cells;
|
|
@@ -1589,7 +1495,7 @@ var TablePresentation = class {
|
|
|
1589
1495
|
col: 0,
|
|
1590
1496
|
row: 0
|
|
1591
1497
|
})]: {
|
|
1592
|
-
className: "!bg-
|
|
1498
|
+
className: "!bg-toolbar-surface",
|
|
1593
1499
|
readonly: true,
|
|
1594
1500
|
value: ""
|
|
1595
1501
|
}
|
|
@@ -1603,9 +1509,9 @@ var TablePresentation = class {
|
|
|
1603
1509
|
accessoryHtml: tableControls.checkbox.render({
|
|
1604
1510
|
rowIndex: 0,
|
|
1605
1511
|
header: true,
|
|
1606
|
-
checked: this.model.selection.
|
|
1512
|
+
checked: this.model.selection.allRowsSelected
|
|
1607
1513
|
}),
|
|
1608
|
-
className: "!bg-
|
|
1514
|
+
className: "!bg-toolbar-surface",
|
|
1609
1515
|
readonly: true,
|
|
1610
1516
|
value: ""
|
|
1611
1517
|
}
|
|
@@ -1618,9 +1524,9 @@ var TablePresentation = class {
|
|
|
1618
1524
|
row: 0
|
|
1619
1525
|
})]: {
|
|
1620
1526
|
accessoryHtml: this.model.features.schemaEditable ? tableButtons.addColumn.render({
|
|
1621
|
-
disabled: (this.model.projection?.
|
|
1527
|
+
disabled: (this.model.projection?.getFields()?.length ?? 0) >= VIEW_FIELD_LIMIT
|
|
1622
1528
|
}) : void 0,
|
|
1623
|
-
className: "!bg-
|
|
1529
|
+
className: "!bg-toolbar-surface",
|
|
1624
1530
|
readonly: true,
|
|
1625
1531
|
value: ""
|
|
1626
1532
|
}
|
|
@@ -1628,36 +1534,47 @@ var TablePresentation = class {
|
|
|
1628
1534
|
}
|
|
1629
1535
|
getDraftActionCells(range) {
|
|
1630
1536
|
const cells = {};
|
|
1631
|
-
const draftRows = this.model.
|
|
1632
|
-
|
|
1633
|
-
const draftRow = draftRows[row];
|
|
1634
|
-
const disabled = !draftRow.valid;
|
|
1537
|
+
const draftRows = this.model.getDraftRows();
|
|
1538
|
+
if (draftRows.length === 0) {
|
|
1635
1539
|
cells[toPlaneCellIndex({
|
|
1636
1540
|
col: 0,
|
|
1637
|
-
row
|
|
1541
|
+
row: 0
|
|
1638
1542
|
})] = {
|
|
1639
1543
|
value: "",
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
rowIndex: row,
|
|
1643
|
-
disabled
|
|
1644
|
-
}),
|
|
1645
|
-
className: "!bg-toolbarSurface"
|
|
1544
|
+
className: "dx-grid__row--cta__cell",
|
|
1545
|
+
readonly: true
|
|
1646
1546
|
};
|
|
1547
|
+
} else {
|
|
1548
|
+
for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
|
|
1549
|
+
const draftRow = draftRows[row];
|
|
1550
|
+
const disabled = !draftRow.valid;
|
|
1551
|
+
cells[toPlaneCellIndex({
|
|
1552
|
+
col: 0,
|
|
1553
|
+
row
|
|
1554
|
+
})] = {
|
|
1555
|
+
value: "",
|
|
1556
|
+
readonly: true,
|
|
1557
|
+
accessoryHtml: tableButtons.saveDraftRow.render({
|
|
1558
|
+
rowIndex: row,
|
|
1559
|
+
disabled
|
|
1560
|
+
})
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1647
1563
|
}
|
|
1648
1564
|
return cells;
|
|
1649
1565
|
}
|
|
1650
|
-
|
|
1566
|
+
getDraftIconCells(range) {
|
|
1651
1567
|
const cells = {};
|
|
1652
|
-
const draftRows = this.model.
|
|
1653
|
-
for (let row = range.start.row; row <= range.end.row
|
|
1568
|
+
const draftRows = this.model.getDraftRows();
|
|
1569
|
+
for (let row = range.start.row; row <= range.end.row; row++) {
|
|
1654
1570
|
cells[toPlaneCellIndex({
|
|
1655
1571
|
col: 0,
|
|
1656
1572
|
row
|
|
1657
1573
|
})] = {
|
|
1658
1574
|
value: "",
|
|
1659
1575
|
readonly: true,
|
|
1660
|
-
|
|
1576
|
+
accessoryHtml: '<dx-icon icon="ph--plus--regular" class="contents"></dx-icon>',
|
|
1577
|
+
className: mx("[&>div]:grid [&>div]:place-content-center", draftRows.length < 1 && "dx-grid__row--cta__cell")
|
|
1661
1578
|
};
|
|
1662
1579
|
}
|
|
1663
1580
|
return cells;
|
|
@@ -1667,7 +1584,7 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
|
|
|
1667
1584
|
if (!selected) {
|
|
1668
1585
|
if (selectionMode === "single") {
|
|
1669
1586
|
return [
|
|
1670
|
-
"
|
|
1587
|
+
"cursor-pointer!"
|
|
1671
1588
|
];
|
|
1672
1589
|
} else {
|
|
1673
1590
|
return void 0;
|
|
@@ -1676,140 +1593,161 @@ var cellClassesForRowSelection = (selected, selectionMode) => {
|
|
|
1676
1593
|
switch (selectionMode) {
|
|
1677
1594
|
case "single":
|
|
1678
1595
|
return [
|
|
1679
|
-
"
|
|
1596
|
+
"dx-grid__cell--no-focus-unfurl !bg-current-surface hover:bg-hover-surface cursor-pointer!"
|
|
1680
1597
|
];
|
|
1681
1598
|
case "multiple":
|
|
1682
1599
|
return [
|
|
1683
|
-
"!bg-
|
|
1600
|
+
"!bg-grid-cell-selected"
|
|
1684
1601
|
];
|
|
1685
1602
|
}
|
|
1686
1603
|
};
|
|
1687
1604
|
|
|
1688
|
-
// src/hooks/useTableModel.ts
|
|
1689
|
-
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
1690
|
-
import { effect as effect3 } from "@preact/signals-core";
|
|
1691
|
-
import orderBy2 from "lodash.orderby";
|
|
1692
|
-
import { useEffect, useMemo, useState } from "react";
|
|
1693
|
-
import { fullyQualifiedId as fullyQualifiedId2 } from "@dxos/react-client/echo";
|
|
1694
|
-
import { useSelected, useSelectionActions } from "@dxos/react-ui-attention";
|
|
1695
|
-
import { isNonNullable } from "@dxos/util";
|
|
1696
|
-
var useTableModel = ({ view, schema, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
|
|
1697
|
-
var _effect = _useSignals();
|
|
1698
|
-
try {
|
|
1699
|
-
const selected = useSelected(view && fullyQualifiedId2(view), "multi");
|
|
1700
|
-
const initialSelection = useMemo(() => selected, [
|
|
1701
|
-
view
|
|
1702
|
-
]);
|
|
1703
|
-
const [model, setModel] = useState();
|
|
1704
|
-
useEffect(() => {
|
|
1705
|
-
if (!view || !schema) {
|
|
1706
|
-
return;
|
|
1707
|
-
}
|
|
1708
|
-
let model2;
|
|
1709
|
-
const t = setTimeout(async () => {
|
|
1710
|
-
model2 = new TableModel({
|
|
1711
|
-
view,
|
|
1712
|
-
schema,
|
|
1713
|
-
projection,
|
|
1714
|
-
features,
|
|
1715
|
-
rowActions,
|
|
1716
|
-
initialSelection,
|
|
1717
|
-
onRowAction,
|
|
1718
|
-
...props
|
|
1719
|
-
});
|
|
1720
|
-
await model2.open();
|
|
1721
|
-
setModel(model2);
|
|
1722
|
-
});
|
|
1723
|
-
return () => {
|
|
1724
|
-
clearTimeout(t);
|
|
1725
|
-
void model2?.close();
|
|
1726
|
-
};
|
|
1727
|
-
}, [
|
|
1728
|
-
view,
|
|
1729
|
-
schema,
|
|
1730
|
-
projection,
|
|
1731
|
-
features,
|
|
1732
|
-
rowActions,
|
|
1733
|
-
initialSelection
|
|
1734
|
-
]);
|
|
1735
|
-
useEffect(() => {
|
|
1736
|
-
if (rows) {
|
|
1737
|
-
const sortedRows = orderBy2(rows, [
|
|
1738
|
-
(row) => String(row.id)
|
|
1739
|
-
], [
|
|
1740
|
-
"asc"
|
|
1741
|
-
]);
|
|
1742
|
-
model?.setRows(sortedRows);
|
|
1743
|
-
}
|
|
1744
|
-
}, [
|
|
1745
|
-
model,
|
|
1746
|
-
rows
|
|
1747
|
-
]);
|
|
1748
|
-
const { multiSelect, clear } = useSelectionActions([
|
|
1749
|
-
model?.id
|
|
1750
|
-
].filter(isNonNullable));
|
|
1751
|
-
useEffect(() => {
|
|
1752
|
-
if (!model) {
|
|
1753
|
-
return;
|
|
1754
|
-
}
|
|
1755
|
-
const unsubscribe = effect3(() => {
|
|
1756
|
-
const selectedItems = [
|
|
1757
|
-
...model.selection.selection.value
|
|
1758
|
-
];
|
|
1759
|
-
multiSelect(selectedItems);
|
|
1760
|
-
onSelectionChanged?.(selectedItems);
|
|
1761
|
-
});
|
|
1762
|
-
return () => {
|
|
1763
|
-
clear();
|
|
1764
|
-
unsubscribe();
|
|
1765
|
-
};
|
|
1766
|
-
}, [
|
|
1767
|
-
model,
|
|
1768
|
-
onSelectionChanged
|
|
1769
|
-
]);
|
|
1770
|
-
return model;
|
|
1771
|
-
} finally {
|
|
1772
|
-
_effect.f();
|
|
1773
|
-
}
|
|
1774
|
-
};
|
|
1775
|
-
|
|
1776
1605
|
// src/hooks/useAddRow.ts
|
|
1777
1606
|
import { useCallback } from "react";
|
|
1778
|
-
import { Obj as
|
|
1779
|
-
var useAddRow = ({
|
|
1607
|
+
import { Obj as Obj3 } from "@dxos/echo";
|
|
1608
|
+
var useAddRow = ({ db, schema }) => {
|
|
1780
1609
|
return useCallback((data) => {
|
|
1781
|
-
if (
|
|
1610
|
+
if (db && schema) {
|
|
1782
1611
|
try {
|
|
1783
|
-
|
|
1784
|
-
return
|
|
1612
|
+
db.add(Obj3.make(schema, data ?? {}));
|
|
1613
|
+
return "final";
|
|
1785
1614
|
} catch (error) {
|
|
1786
|
-
return
|
|
1615
|
+
return "draft";
|
|
1787
1616
|
}
|
|
1788
1617
|
}
|
|
1789
|
-
return
|
|
1618
|
+
return "final";
|
|
1790
1619
|
}, [
|
|
1791
|
-
|
|
1620
|
+
db,
|
|
1792
1621
|
schema
|
|
1793
1622
|
]);
|
|
1794
1623
|
};
|
|
1795
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
|
+
|
|
1796
1734
|
export {
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
createTable,
|
|
1735
|
+
extractOrder,
|
|
1736
|
+
getSortValue,
|
|
1737
|
+
compareValues,
|
|
1801
1738
|
BUTTON_IDENTIFIERS,
|
|
1802
1739
|
tableButtons,
|
|
1803
1740
|
CONTROL_IDENTIFIERS,
|
|
1804
1741
|
CheckboxStory,
|
|
1805
1742
|
SwitchStory,
|
|
1806
1743
|
tableControls,
|
|
1807
|
-
|
|
1744
|
+
createEchoChangeCallback,
|
|
1745
|
+
createDirectChangeCallback,
|
|
1808
1746
|
TableModel,
|
|
1809
|
-
ModalController,
|
|
1810
1747
|
TablePresentation,
|
|
1811
1748
|
cellClassesForRowSelection,
|
|
1812
|
-
|
|
1813
|
-
|
|
1749
|
+
useAddRow,
|
|
1750
|
+
useProjectionModel,
|
|
1751
|
+
useTableModel
|
|
1814
1752
|
};
|
|
1815
|
-
//# sourceMappingURL=chunk-
|
|
1753
|
+
//# sourceMappingURL=chunk-CCJ4LOVM.mjs.map
|