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