@dxos/react-ui-table 0.8.4-main.2e9d522 → 0.8.4-main.5ea62a8
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-63UUF4IG.mjs +66 -0
- package/dist/lib/browser/chunk-63UUF4IG.mjs.map +7 -0
- package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-RQYXNWWN.mjs} +531 -460
- package/dist/lib/browser/chunk-RQYXNWWN.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +691 -625
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +6 -4
- 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-K734DJB7.mjs +67 -0
- package/dist/lib/node-esm/chunk-K734DJB7.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-Y66YLSTC.mjs → chunk-QNDUGIS7.mjs} +531 -460
- package/dist/lib/node-esm/chunk-QNDUGIS7.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +691 -625
- 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 +6 -4
- 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 -1
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/CreateRefPanel.d.ts +1 -1
- package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +50 -2
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +44 -0
- package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
- package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
- package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +3 -2
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +42 -3
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +7 -3
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +8 -15
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +39 -3
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts +2 -1
- package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
- package/dist/types/src/hooks/useTableModel.d.ts +1 -1
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/modal-controller.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +7 -5
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +2 -1
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/model/table-sorting.d.ts +2 -2
- package/dist/types/src/model/table-sorting.d.ts.map +1 -1
- package/dist/types/src/testing/useTestTableModel.d.ts +4 -9
- package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -2
- 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/types/schema.d.ts +24 -4
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +0 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/table-buttons.d.ts.map +1 -1
- package/dist/types/src/util/table-controls.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +44 -39
- package/src/components/Table/ColumnActionsMenu.tsx +1 -1
- package/src/components/Table/ColumnSettings.tsx +1 -1
- package/src/components/Table/CreateRefPanel.tsx +25 -8
- package/src/components/Table/DynamicTable.stories.tsx +7 -4
- package/src/components/Table/DynamicTable.tsx +4 -3
- package/src/components/Table/{relations.stories.tsx → Relations.stories.tsx} +40 -23
- package/src/components/Table/RowActionsMenu.tsx +3 -3
- package/src/components/Table/Table.stories.tsx +34 -23
- package/src/components/Table/Table.tsx +138 -112
- package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
- package/src/components/TableCellEditor/FormCellEditor.tsx +143 -42
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +11 -23
- package/src/components/TableCellEditor/TableCellEditor.tsx +64 -119
- package/src/components/TableToolbar/TableToolbar.tsx +2 -2
- package/src/components/testing.ts +1 -1
- package/src/hooks/useAddRow.ts +6 -4
- package/src/hooks/useTableModel.ts +1 -1
- package/src/model/modal-controller.ts +1 -1
- package/src/model/selection-model.ts +3 -2
- package/src/model/table-model.test.ts +3 -4
- package/src/model/table-model.ts +28 -23
- package/src/model/table-presentation.test.ts +4 -4
- package/src/model/table-presentation.ts +72 -30
- package/src/model/table-sorting.ts +3 -3
- package/src/playwright/smoke.spec.ts +129 -37
- package/src/testing/useTestTableModel.ts +4 -3
- package/src/translations.ts +2 -2
- package/src/types/index.ts +1 -1
- package/src/types/schema.ts +62 -5
- package/src/util/dynamic-table.ts +5 -5
- package/src/util/index.ts +0 -1
- package/src/util/schema.ts +1 -1
- package/src/util/table-buttons.ts +4 -3
- package/src/util/table-controls.ts +4 -1
- package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
- package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
- package/dist/lib/browser/chunk-L2LSB6KV.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-Y66YLSTC.mjs.map +0 -7
- package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
- package/dist/types/src/components/Table/relations.stories.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/util/table.d.ts +0 -11
- package/dist/types/src/util/table.d.ts.map +0 -1
- package/src/components/TableCellEditor/extension.ts +0 -61
- package/src/util/table.ts +0 -49
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
TableModel,
|
|
9
9
|
TablePresentation,
|
|
10
10
|
cellClassesForRowSelection,
|
|
11
|
-
createTable,
|
|
12
11
|
getBaseSchema,
|
|
13
12
|
makeDynamicTable,
|
|
14
13
|
narrowSchema,
|
|
@@ -17,8 +16,8 @@ import {
|
|
|
17
16
|
touch,
|
|
18
17
|
useAddRow,
|
|
19
18
|
useTableModel
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import "./chunk-
|
|
19
|
+
} from "./chunk-QNDUGIS7.mjs";
|
|
20
|
+
import "./chunk-K734DJB7.mjs";
|
|
22
21
|
|
|
23
22
|
// src/translations.ts
|
|
24
23
|
var translationKey = "react-ui-table";
|
|
@@ -30,8 +29,8 @@ var translations = [
|
|
|
30
29
|
"create object label": "Create table",
|
|
31
30
|
"table name placeholder": "Table name",
|
|
32
31
|
"settings title": "Table settings",
|
|
33
|
-
"table schema label": "
|
|
34
|
-
"new schema": "New
|
|
32
|
+
"table schema label": "Record type",
|
|
33
|
+
"new schema": "New record type",
|
|
35
34
|
"continue label": "Continue",
|
|
36
35
|
"create stack section label": "Create table",
|
|
37
36
|
"add row label": "Add row",
|
|
@@ -54,270 +53,38 @@ var translations = [
|
|
|
54
53
|
|
|
55
54
|
// src/components/Table/Table.tsx
|
|
56
55
|
import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
|
|
57
|
-
import React8, { forwardRef, useCallback as useCallback5,
|
|
58
|
-
import { Filter } from "@dxos/echo";
|
|
59
|
-
import { getValue } from "@dxos/echo-schema";
|
|
60
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
61
|
-
import { getSpace as getSpace2 } from "@dxos/react-client/echo";
|
|
62
|
-
import { useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
56
|
+
import React8, { forwardRef, useCallback as useCallback5, useEffect as useEffect3, useImperativeHandle, useMemo as useMemo5, useState as useState4 } from "react";
|
|
63
57
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
64
|
-
import { closestCell,
|
|
58
|
+
import { Grid, closestCell, gridSeparatorBlockEnd, gridSeparatorInlineEnd } from "@dxos/react-ui-grid";
|
|
59
|
+
import { DxEditRequest } from "@dxos/react-ui-grid";
|
|
65
60
|
import { mx } from "@dxos/react-ui-theme";
|
|
66
|
-
import { isNotFalsy, safeParseInt } from "@dxos/util";
|
|
67
|
-
|
|
68
|
-
// src/components/Table/ColumnActionsMenu.tsx
|
|
69
|
-
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
70
|
-
import React from "react";
|
|
71
|
-
import { DropdownMenu, useTranslation } from "@dxos/react-ui";
|
|
72
|
-
var ColumnActionsMenu = ({ model, modals }) => {
|
|
73
|
-
var _effect = _useSignals();
|
|
74
|
-
try {
|
|
75
|
-
const { t } = useTranslation(translationKey);
|
|
76
|
-
const state = modals.state.value;
|
|
77
|
-
if (state?.type !== "column") {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
const currentSort = model.sorting?.sorting;
|
|
81
|
-
const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
|
|
82
|
-
return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
|
|
83
|
-
modal: false,
|
|
84
|
-
open: true,
|
|
85
|
-
onOpenChange: modals.close
|
|
86
|
-
}, /* @__PURE__ */ React.createElement(DropdownMenu.VirtualTrigger, {
|
|
87
|
-
virtualRef: modals.trigger
|
|
88
|
-
}), /* @__PURE__ */ React.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
89
|
-
"data-testid": "column-sort-descending",
|
|
90
|
-
onClick: () => model.sorting?.setSort(state.fieldId, "desc")
|
|
91
|
-
}, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
92
|
-
"data-testid": "column-sort-ascending",
|
|
93
|
-
onClick: () => model.sorting?.setSort(state.fieldId, "asc")
|
|
94
|
-
}, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
95
|
-
"data-testid": "column-clear-sort",
|
|
96
|
-
onClick: () => model.sorting?.clearSort()
|
|
97
|
-
}, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
98
|
-
"data-testid": "column-delete",
|
|
99
|
-
onClick: () => model.deleteColumn(state.fieldId)
|
|
100
|
-
}, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
101
|
-
"data-testid": "column-settings",
|
|
102
|
-
onClick: () => modals.openColumnSettings()
|
|
103
|
-
}, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
|
|
104
|
-
} finally {
|
|
105
|
-
_effect.f();
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// src/components/Table/ColumnSettings.tsx
|
|
110
|
-
import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
|
|
111
|
-
import React2, { useCallback, useEffect, useMemo, useState } from "react";
|
|
112
|
-
import { Popover } from "@dxos/react-ui";
|
|
113
|
-
import { FieldEditor } from "@dxos/react-ui-form";
|
|
114
|
-
var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
|
|
115
|
-
var _effect = _useSignals2();
|
|
116
|
-
try {
|
|
117
|
-
const [newField, setNewField] = useState();
|
|
118
|
-
const state = modals.state.value;
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
|
|
121
|
-
setNewField(model.projection.createFieldProjection());
|
|
122
|
-
requestAnimationFrame(() => {
|
|
123
|
-
onNewColumn();
|
|
124
|
-
});
|
|
125
|
-
} else {
|
|
126
|
-
setNewField(void 0);
|
|
127
|
-
}
|
|
128
|
-
}, [
|
|
129
|
-
model?.projection,
|
|
130
|
-
state
|
|
131
|
-
]);
|
|
132
|
-
const existingField = useMemo(() => {
|
|
133
|
-
if (state?.type === "columnSettings") {
|
|
134
|
-
const { mode } = state;
|
|
135
|
-
if (mode.type === "edit") {
|
|
136
|
-
return model?.projection?.fields.find((f) => f.id === mode.fieldId);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return void 0;
|
|
140
|
-
}, [
|
|
141
|
-
model?.projection?.fields,
|
|
142
|
-
state
|
|
143
|
-
]);
|
|
144
|
-
const field = existingField ?? newField;
|
|
145
|
-
const handleSave = useCallback(() => {
|
|
146
|
-
modals.close();
|
|
147
|
-
}, [
|
|
148
|
-
modals
|
|
149
|
-
]);
|
|
150
|
-
const handleCancel = useCallback(() => {
|
|
151
|
-
if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
|
|
152
|
-
model?.projection.deleteFieldProjection(newField.id);
|
|
153
|
-
}
|
|
154
|
-
}, [
|
|
155
|
-
model?.projection,
|
|
156
|
-
state,
|
|
157
|
-
newField
|
|
158
|
-
]);
|
|
159
|
-
if (!model?.projection || !field) {
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
return /* @__PURE__ */ React2.createElement(Popover.Root, {
|
|
163
|
-
modal: false,
|
|
164
|
-
open: state?.type === "columnSettings"
|
|
165
|
-
}, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
|
|
166
|
-
virtualRef: modals.trigger
|
|
167
|
-
}), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
|
|
168
|
-
classNames: "md:is-64"
|
|
169
|
-
}, /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
|
|
170
|
-
projection: model.projection,
|
|
171
|
-
field,
|
|
172
|
-
registry,
|
|
173
|
-
onSave: handleSave,
|
|
174
|
-
onCancel: handleCancel
|
|
175
|
-
})), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))));
|
|
176
|
-
} finally {
|
|
177
|
-
_effect.f();
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
// src/components/Table/CreateRefPanel.tsx
|
|
182
|
-
import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
|
|
183
|
-
import { Schema } from "effect";
|
|
184
|
-
import React3, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
185
|
-
import { live } from "@dxos/live-object";
|
|
186
|
-
import { getSpace } from "@dxos/react-client/echo";
|
|
187
|
-
import { Popover as Popover2 } from "@dxos/react-ui";
|
|
188
|
-
import { Form } from "@dxos/react-ui-form";
|
|
189
|
-
import { useGridContext } from "@dxos/react-ui-grid";
|
|
190
|
-
var CreateRefPanel = ({ model, modals, __gridScope }) => {
|
|
191
|
-
var _effect = _useSignals3();
|
|
192
|
-
try {
|
|
193
|
-
const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
|
|
194
|
-
const space = model && getSpace(model?.view);
|
|
195
|
-
const state = modals.state.value;
|
|
196
|
-
const schema = useMemo2(() => {
|
|
197
|
-
if (!space || state?.type !== "createRefPanel") {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
const [schema2] = space.db.schemaRegistry.query({
|
|
201
|
-
typename: state.typename
|
|
202
|
-
}).runSync();
|
|
203
|
-
if (schema2) {
|
|
204
|
-
const omit = Schema.omit("id");
|
|
205
|
-
return omit(schema2);
|
|
206
|
-
}
|
|
207
|
-
}, [
|
|
208
|
-
space,
|
|
209
|
-
state
|
|
210
|
-
]);
|
|
211
|
-
const handleSave = useCallback2((values) => {
|
|
212
|
-
if (!model || !space || state?.type !== "createRefPanel") {
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
const [schema2] = space.db.schemaRegistry.query({
|
|
216
|
-
typename: state.typename
|
|
217
|
-
}).runSync();
|
|
218
|
-
if (schema2) {
|
|
219
|
-
const obj = space.db.add(live(schema2, values));
|
|
220
|
-
state.onCreate?.(obj);
|
|
221
|
-
}
|
|
222
|
-
void modals.close();
|
|
223
|
-
}, [
|
|
224
|
-
modals,
|
|
225
|
-
space,
|
|
226
|
-
state
|
|
227
|
-
]);
|
|
228
|
-
const handleCancel = useCallback2(() => {
|
|
229
|
-
if (model) {
|
|
230
|
-
modals.close();
|
|
231
|
-
}
|
|
232
|
-
}, [
|
|
233
|
-
modals
|
|
234
|
-
]);
|
|
235
|
-
if (!model?.projection) {
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
return /* @__PURE__ */ React3.createElement(Popover2.Root, {
|
|
239
|
-
modal: false,
|
|
240
|
-
open: state?.type === "createRefPanel" && !!schema,
|
|
241
|
-
onOpenChange: (nextOpen) => {
|
|
242
|
-
if (model && !nextOpen) {
|
|
243
|
-
return modals.close();
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}, /* @__PURE__ */ React3.createElement(Popover2.VirtualTrigger, {
|
|
247
|
-
virtualRef: modals.trigger
|
|
248
|
-
}), /* @__PURE__ */ React3.createElement(Popover2.Portal, null, /* @__PURE__ */ React3.createElement(Popover2.Content, {
|
|
249
|
-
classNames: "md:is-64",
|
|
250
|
-
"data-grid": gridId
|
|
251
|
-
}, /* @__PURE__ */ React3.createElement(Popover2.Viewport, null, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React3.createElement(Form, {
|
|
252
|
-
schema,
|
|
253
|
-
values: state.initialValues ?? {},
|
|
254
|
-
onSave: handleSave,
|
|
255
|
-
onCancel: handleCancel
|
|
256
|
-
})), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null))));
|
|
257
|
-
} finally {
|
|
258
|
-
_effect.f();
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
// src/components/Table/RowActionsMenu.tsx
|
|
263
|
-
import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
|
|
264
|
-
import React4 from "react";
|
|
265
|
-
import { DropdownMenu as DropdownMenu2, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
266
|
-
var RowActionsMenu = ({ model, modals }) => {
|
|
267
|
-
var _effect = _useSignals4();
|
|
268
|
-
try {
|
|
269
|
-
const { t } = useTranslation2(translationKey);
|
|
270
|
-
const hasSelection = model.selection.hasSelection.value;
|
|
271
|
-
const state = modals.state.value;
|
|
272
|
-
if (state?.type !== "row") {
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
return /* @__PURE__ */ React4.createElement(DropdownMenu2.Root, {
|
|
276
|
-
modal: false,
|
|
277
|
-
open: true,
|
|
278
|
-
onOpenChange: modals.close
|
|
279
|
-
}, /* @__PURE__ */ React4.createElement(DropdownMenu2.VirtualTrigger, {
|
|
280
|
-
virtualRef: modals.trigger
|
|
281
|
-
}), /* @__PURE__ */ React4.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu2.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
|
|
282
|
-
"data-testid": "row-menu-delete",
|
|
283
|
-
onClick: () => model.deleteRow(state.rowIndex)
|
|
284
|
-
}, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
|
|
285
|
-
key: action.id,
|
|
286
|
-
"data-testid": `row-action-${action.id}`,
|
|
287
|
-
onClick: () => {
|
|
288
|
-
modals.close();
|
|
289
|
-
model.handleRowAction(action.id, state.rowIndex);
|
|
290
|
-
}
|
|
291
|
-
}, t(action.translationKey)))), /* @__PURE__ */ React4.createElement(DropdownMenu2.Arrow, null)));
|
|
292
|
-
} finally {
|
|
293
|
-
_effect.f();
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
61
|
|
|
297
62
|
// src/components/TableCellEditor/TableCellEditor.tsx
|
|
298
|
-
import { useSignals as
|
|
299
|
-
import
|
|
63
|
+
import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
|
|
64
|
+
import { EditorView } from "@codemirror/view";
|
|
65
|
+
import React3, { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
66
|
+
import { debounce } from "@dxos/async";
|
|
300
67
|
import { FormatEnum, TypeEnum } from "@dxos/echo-schema";
|
|
301
68
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
302
69
|
import { useThemeContext } from "@dxos/react-ui";
|
|
303
70
|
import { createMarkdownExtensions } from "@dxos/react-ui-editor";
|
|
304
|
-
import {
|
|
305
|
-
import {
|
|
71
|
+
import { GridCellEditor, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
|
|
72
|
+
import { createLinks, tagPicker } from "@dxos/react-ui-tag-picker";
|
|
306
73
|
|
|
307
74
|
// src/components/TableCellEditor/CellValidationMessage.tsx
|
|
308
|
-
import { useSignals as
|
|
309
|
-
import
|
|
310
|
-
import { useGridContext
|
|
75
|
+
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
76
|
+
import React from "react";
|
|
77
|
+
import { useGridContext } from "@dxos/react-ui-grid";
|
|
311
78
|
var CellValidationMessage = ({ validationError, variant = "error", __gridScope }) => {
|
|
312
|
-
var _effect =
|
|
79
|
+
var _effect = _useSignals();
|
|
313
80
|
try {
|
|
314
|
-
const { editing, editBox: box } =
|
|
81
|
+
const { editing, editBox: box } = useGridContext("GridSheetCellEditor", __gridScope);
|
|
315
82
|
if (!editing || !validationError) {
|
|
316
83
|
return null;
|
|
317
84
|
}
|
|
318
85
|
const bgClass = variant === "error" ? "bg-errorSurface" : "bg-warningSurface";
|
|
319
86
|
const textClass = variant === "error" ? "text-errorSurfaceText" : "text-warningSurfaceText";
|
|
320
|
-
return /* @__PURE__ */
|
|
87
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
321
88
|
role: "none",
|
|
322
89
|
className: `absolute ${bgClass} ${textClass} rounded-bs-sm text-xs p-1`,
|
|
323
90
|
style: {
|
|
@@ -336,22 +103,157 @@ var CellValidationMessage = ({ validationError, variant = "error", __gridScope }
|
|
|
336
103
|
};
|
|
337
104
|
|
|
338
105
|
// src/components/TableCellEditor/FormCellEditor.tsx
|
|
339
|
-
import { useSignals as
|
|
340
|
-
import
|
|
341
|
-
import {
|
|
106
|
+
import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
|
|
107
|
+
import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
108
|
+
import { Filter, Obj } from "@dxos/echo";
|
|
109
|
+
import { Ref, getValue } from "@dxos/echo-schema";
|
|
342
110
|
import { invariant } from "@dxos/invariant";
|
|
343
|
-
import {
|
|
344
|
-
import {
|
|
345
|
-
import {
|
|
346
|
-
import {
|
|
111
|
+
import { getSnapshot } from "@dxos/live-object";
|
|
112
|
+
import { getSpace } from "@dxos/react-client/echo";
|
|
113
|
+
import { Popover } from "@dxos/react-ui";
|
|
114
|
+
import { Form } from "@dxos/react-ui-form";
|
|
115
|
+
import { cellQuery, parseCellIndex, useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
|
|
116
|
+
import { getDeep, isNotFalsy, setDeep } from "@dxos/util";
|
|
347
117
|
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
|
|
348
|
-
var
|
|
349
|
-
|
|
118
|
+
var createOptionLabel = [
|
|
119
|
+
"create new object label",
|
|
120
|
+
{
|
|
121
|
+
ns: translationKey
|
|
122
|
+
}
|
|
123
|
+
];
|
|
124
|
+
var FormCellEditor = ({ fieldProjection, model, schema, onSave, client, modals, __gridScope, ...formProps }) => {
|
|
125
|
+
var _effect = _useSignals2();
|
|
350
126
|
try {
|
|
351
|
-
const { editing: contextEditing, setEditing } =
|
|
352
|
-
const [editing, setLocalEditing] =
|
|
127
|
+
const { editing: contextEditing, setEditing, id: gridId } = useGridContext2("ArrayEditor", __gridScope);
|
|
128
|
+
const [editing, setLocalEditing] = useState(false);
|
|
353
129
|
const anchorRef = useRef(null);
|
|
354
|
-
|
|
130
|
+
const getSchema = useCallback((typeAnnotation) => {
|
|
131
|
+
const space = getSpace(model.view);
|
|
132
|
+
invariant(space, void 0, {
|
|
133
|
+
F: __dxlog_file,
|
|
134
|
+
L: 53,
|
|
135
|
+
S: void 0,
|
|
136
|
+
A: [
|
|
137
|
+
"space",
|
|
138
|
+
""
|
|
139
|
+
]
|
|
140
|
+
});
|
|
141
|
+
let schema2;
|
|
142
|
+
if (client) {
|
|
143
|
+
schema2 = client.graph.schemaRegistry.getSchema(typeAnnotation.typename);
|
|
144
|
+
}
|
|
145
|
+
if (!schema2) {
|
|
146
|
+
schema2 = space.db.schemaRegistry.getSchema(typeAnnotation.typename);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
space,
|
|
150
|
+
schema: schema2
|
|
151
|
+
};
|
|
152
|
+
}, [
|
|
153
|
+
client,
|
|
154
|
+
model
|
|
155
|
+
]);
|
|
156
|
+
const handleQueryRefOptions = useCallback(async (typeAnnotation) => {
|
|
157
|
+
const { schema: schema2, space } = getSchema(typeAnnotation);
|
|
158
|
+
if (model && schema2 && space) {
|
|
159
|
+
const { objects } = await space.db.query(Filter.type(schema2)).run();
|
|
160
|
+
return objects.map((obj) => {
|
|
161
|
+
return {
|
|
162
|
+
dxn: Obj.getDXN(obj),
|
|
163
|
+
label: getValue(obj, fieldProjection.field.referencePath) || obj.id.toString()
|
|
164
|
+
};
|
|
165
|
+
}).filter(isNotFalsy);
|
|
166
|
+
}
|
|
167
|
+
return [];
|
|
168
|
+
}, [
|
|
169
|
+
client,
|
|
170
|
+
model
|
|
171
|
+
]);
|
|
172
|
+
const originalRow = useMemo(() => {
|
|
173
|
+
if (model && contextEditing) {
|
|
174
|
+
const cell = parseCellIndex(contextEditing.index);
|
|
175
|
+
if (model.isDraftCell(cell)) {
|
|
176
|
+
const draftRow = model.draftRows.value[cell.row];
|
|
177
|
+
invariant(draftRow, void 0, {
|
|
178
|
+
F: __dxlog_file,
|
|
179
|
+
L: 94,
|
|
180
|
+
S: void 0,
|
|
181
|
+
A: [
|
|
182
|
+
"draftRow",
|
|
183
|
+
""
|
|
184
|
+
]
|
|
185
|
+
});
|
|
186
|
+
return draftRow.data;
|
|
187
|
+
} else {
|
|
188
|
+
const row = model.getRowAt(cell.row);
|
|
189
|
+
invariant(row, void 0, {
|
|
190
|
+
F: __dxlog_file,
|
|
191
|
+
L: 98,
|
|
192
|
+
S: void 0,
|
|
193
|
+
A: [
|
|
194
|
+
"row",
|
|
195
|
+
""
|
|
196
|
+
]
|
|
197
|
+
});
|
|
198
|
+
return row;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return void 0;
|
|
202
|
+
}, [
|
|
203
|
+
model,
|
|
204
|
+
contextEditing
|
|
205
|
+
]);
|
|
206
|
+
const handleSave = useCallback((values) => {
|
|
207
|
+
const path = fieldProjection.field.path;
|
|
208
|
+
const value = getDeep(values, [
|
|
209
|
+
path
|
|
210
|
+
]);
|
|
211
|
+
setDeep(originalRow, [
|
|
212
|
+
path
|
|
213
|
+
], value);
|
|
214
|
+
contextEditing?.cellElement?.focus();
|
|
215
|
+
setEditing(null);
|
|
216
|
+
setLocalEditing(false);
|
|
217
|
+
onSave?.();
|
|
218
|
+
}, [
|
|
219
|
+
fieldProjection.field.path,
|
|
220
|
+
onSave,
|
|
221
|
+
contextEditing,
|
|
222
|
+
originalRow
|
|
223
|
+
]);
|
|
224
|
+
const handleCreate = useCallback((object) => {
|
|
225
|
+
const ref = Ref.make(object);
|
|
226
|
+
const path = fieldProjection.field.path;
|
|
227
|
+
setDeep(originalRow, [
|
|
228
|
+
path
|
|
229
|
+
], ref);
|
|
230
|
+
contextEditing?.cellElement?.focus();
|
|
231
|
+
setEditing(null);
|
|
232
|
+
setLocalEditing(false);
|
|
233
|
+
onSave?.();
|
|
234
|
+
}, [
|
|
235
|
+
fieldProjection.field.path,
|
|
236
|
+
onSave,
|
|
237
|
+
contextEditing,
|
|
238
|
+
originalRow
|
|
239
|
+
]);
|
|
240
|
+
const handleCreateFromQuery = useCallback(async (typeAnnotation, query) => {
|
|
241
|
+
if (model && modals && contextEditing?.index) {
|
|
242
|
+
setLocalEditing(false);
|
|
243
|
+
modals.openCreateRef(typeAnnotation.typename, document.querySelector(cellQuery(contextEditing.index, gridId)), {
|
|
244
|
+
[fieldProjection.field.referencePath]: query
|
|
245
|
+
}, handleCreate);
|
|
246
|
+
}
|
|
247
|
+
}, [
|
|
248
|
+
model,
|
|
249
|
+
modals,
|
|
250
|
+
client,
|
|
251
|
+
contextEditing?.index,
|
|
252
|
+
gridId,
|
|
253
|
+
fieldProjection,
|
|
254
|
+
handleSave
|
|
255
|
+
]);
|
|
256
|
+
useEffect(() => {
|
|
355
257
|
if (contextEditing && contextEditing.cellElement) {
|
|
356
258
|
anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
|
|
357
259
|
setLocalEditing(true);
|
|
@@ -362,7 +264,7 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
|
|
|
362
264
|
}, [
|
|
363
265
|
contextEditing
|
|
364
266
|
]);
|
|
365
|
-
const narrowedSchema =
|
|
267
|
+
const narrowedSchema = useMemo(() => {
|
|
366
268
|
if (!schema) {
|
|
367
269
|
return void 0;
|
|
368
270
|
}
|
|
@@ -373,49 +275,10 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
|
|
|
373
275
|
JSON.stringify(schema),
|
|
374
276
|
fieldProjection.field.path
|
|
375
277
|
]);
|
|
376
|
-
const
|
|
377
|
-
if (model && contextEditing) {
|
|
378
|
-
const cell = parseCellIndex(contextEditing.index);
|
|
379
|
-
const row = model.getRowAt(cell.row);
|
|
380
|
-
invariant(row, void 0, {
|
|
381
|
-
F: __dxlog_file,
|
|
382
|
-
L: 55,
|
|
383
|
-
S: void 0,
|
|
384
|
-
A: [
|
|
385
|
-
"row",
|
|
386
|
-
""
|
|
387
|
-
]
|
|
388
|
-
});
|
|
389
|
-
return row;
|
|
390
|
-
}
|
|
391
|
-
return void 0;
|
|
392
|
-
}, [
|
|
393
|
-
model,
|
|
394
|
-
contextEditing
|
|
395
|
-
]);
|
|
396
|
-
const formValues = useMemo3(() => {
|
|
397
|
-
if (originalRow) {
|
|
398
|
-
return getSnapshot(originalRow);
|
|
399
|
-
}
|
|
400
|
-
}, [
|
|
401
|
-
originalRow
|
|
402
|
-
]);
|
|
403
|
-
const handleSave = useCallback3((values) => {
|
|
404
|
-
const path = fieldProjection.field.path;
|
|
405
|
-
const value = getDeep(values, [
|
|
406
|
-
path
|
|
407
|
-
]);
|
|
408
|
-
setDeep(originalRow, [
|
|
409
|
-
path
|
|
410
|
-
], value);
|
|
411
|
-
setEditing(null);
|
|
412
|
-
setLocalEditing(false);
|
|
413
|
-
onSave?.();
|
|
414
|
-
}, [
|
|
415
|
-
fieldProjection.field.path,
|
|
278
|
+
const formValues = useMemo(() => originalRow ? getSnapshot(originalRow) : {}, [
|
|
416
279
|
originalRow
|
|
417
280
|
]);
|
|
418
|
-
const handleOpenChange =
|
|
281
|
+
const handleOpenChange = useCallback((nextOpen) => {
|
|
419
282
|
if (nextOpen === false) {
|
|
420
283
|
setEditing(null);
|
|
421
284
|
onSave?.();
|
|
@@ -425,76 +288,38 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
|
|
|
425
288
|
if (!editing) {
|
|
426
289
|
return null;
|
|
427
290
|
}
|
|
428
|
-
return /* @__PURE__ */
|
|
291
|
+
return /* @__PURE__ */ React2.createElement(Popover.Root, {
|
|
429
292
|
open: editing,
|
|
430
293
|
onOpenChange: handleOpenChange
|
|
431
|
-
}, /* @__PURE__ */
|
|
294
|
+
}, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
|
|
432
295
|
virtualRef: anchorRef
|
|
433
|
-
}), /* @__PURE__ */
|
|
296
|
+
}), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
|
|
434
297
|
tabIndex: -1,
|
|
435
298
|
classNames: "popover-card-width density-fine"
|
|
436
|
-
}, /* @__PURE__ */
|
|
299
|
+
}, /* @__PURE__ */ React2.createElement(Popover.Arrow, null), /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(Form, {
|
|
300
|
+
autoFocus: true,
|
|
437
301
|
values: formValues,
|
|
438
302
|
schema: narrowedSchema,
|
|
439
|
-
onSave: handleSave
|
|
440
|
-
|
|
303
|
+
onSave: handleSave,
|
|
304
|
+
...formProps,
|
|
305
|
+
onQueryRefOptions: handleQueryRefOptions,
|
|
306
|
+
onCreateFromQuery: handleCreateFromQuery,
|
|
307
|
+
createOptionIcon: "ph--plus--regular",
|
|
308
|
+
createOptionLabel
|
|
309
|
+
})))));
|
|
441
310
|
} finally {
|
|
442
311
|
_effect.f();
|
|
443
312
|
}
|
|
444
313
|
};
|
|
445
314
|
|
|
446
|
-
// src/components/TableCellEditor/extension.ts
|
|
447
|
-
import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
|
|
448
|
-
import { EditorView } from "@codemirror/view";
|
|
449
|
-
var completion = ({ debug, onQuery, onMatch }) => {
|
|
450
|
-
return [
|
|
451
|
-
EditorView.theme({
|
|
452
|
-
".cm-completionDialog": {
|
|
453
|
-
width: "var(--dx-gridCellWidth)"
|
|
454
|
-
}
|
|
455
|
-
}),
|
|
456
|
-
autocompletion({
|
|
457
|
-
icons: false,
|
|
458
|
-
activateOnTyping: true,
|
|
459
|
-
closeOnBlur: !debug,
|
|
460
|
-
override: [
|
|
461
|
-
async (context) => {
|
|
462
|
-
const text = context.state.doc.toString();
|
|
463
|
-
return {
|
|
464
|
-
from: 0,
|
|
465
|
-
options: await onQuery(text)
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
],
|
|
469
|
-
// TODO(burdon): Consts from grid (to line-up with grid).
|
|
470
|
-
tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
|
|
471
|
-
optionClass: () => "flex h-[33px] items-center"
|
|
472
|
-
}),
|
|
473
|
-
// Check for accepted completion metadata in the transaction.
|
|
474
|
-
EditorView.updateListener.of((update) => {
|
|
475
|
-
update.transactions.forEach((tr) => {
|
|
476
|
-
const completion2 = tr.annotation(pickedCompletion);
|
|
477
|
-
if (completion2) {
|
|
478
|
-
onMatch(completion2.data);
|
|
479
|
-
}
|
|
480
|
-
});
|
|
481
|
-
})
|
|
482
|
-
];
|
|
483
|
-
};
|
|
484
|
-
|
|
485
315
|
// src/components/TableCellEditor/TableCellEditor.tsx
|
|
486
316
|
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
|
|
487
|
-
var
|
|
488
|
-
var
|
|
489
|
-
|
|
490
|
-
text
|
|
491
|
-
});
|
|
492
|
-
var isCreateOption = (data) => typeof data === "object" && data[newValue];
|
|
493
|
-
var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQuery, __gridScope }) => {
|
|
494
|
-
var _effect = _useSignals7();
|
|
317
|
+
var adaptValidationMessage = (message) => message ? message.endsWith("is missing") ? "Can\u2019t be blank" : message : null;
|
|
318
|
+
var TableValueEditor = ({ model, modals, schema, onFocus, onSave, client, __gridScope }) => {
|
|
319
|
+
var _effect = _useSignals3();
|
|
495
320
|
try {
|
|
496
|
-
const { editing } =
|
|
497
|
-
const fieldProjection =
|
|
321
|
+
const { editing } = useGridContext3("TableValueEditor", __gridScope);
|
|
322
|
+
const fieldProjection = useMemo2(() => {
|
|
498
323
|
if (!model || !editing) {
|
|
499
324
|
return;
|
|
500
325
|
}
|
|
@@ -503,7 +328,7 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQue
|
|
|
503
328
|
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
504
329
|
invariant2(fieldProjection2, void 0, {
|
|
505
330
|
F: __dxlog_file2,
|
|
506
|
-
L:
|
|
331
|
+
L: 72,
|
|
507
332
|
S: void 0,
|
|
508
333
|
A: [
|
|
509
334
|
"fieldProjection",
|
|
@@ -515,21 +340,21 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQue
|
|
|
515
340
|
model,
|
|
516
341
|
editing
|
|
517
342
|
]);
|
|
518
|
-
if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum.SingleSelect) {
|
|
519
|
-
return /* @__PURE__ */
|
|
343
|
+
if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum.SingleSelect || fieldProjection?.props.format === FormatEnum.Ref) {
|
|
344
|
+
return /* @__PURE__ */ React3.createElement(FormCellEditor, {
|
|
520
345
|
fieldProjection,
|
|
521
346
|
model,
|
|
522
347
|
schema,
|
|
523
348
|
__gridScope,
|
|
524
|
-
onSave
|
|
349
|
+
onSave,
|
|
350
|
+
client,
|
|
351
|
+
modals
|
|
525
352
|
});
|
|
526
353
|
}
|
|
527
|
-
return /* @__PURE__ */
|
|
354
|
+
return /* @__PURE__ */ React3.createElement(TableCellEditor, {
|
|
528
355
|
model,
|
|
529
356
|
modals,
|
|
530
|
-
onEnter,
|
|
531
357
|
onFocus,
|
|
532
|
-
onQuery,
|
|
533
358
|
onSave,
|
|
534
359
|
__gridScope
|
|
535
360
|
});
|
|
@@ -542,15 +367,15 @@ var editorSlots = {
|
|
|
542
367
|
className: "!plb-[--dx-grid-cell-editor-padding-block]"
|
|
543
368
|
}
|
|
544
369
|
};
|
|
545
|
-
var TableCellEditor = ({ model, modals,
|
|
546
|
-
var _effect =
|
|
370
|
+
var TableCellEditor = ({ model, modals, onFocus, onSave, __gridScope }) => {
|
|
371
|
+
var _effect = _useSignals3();
|
|
547
372
|
try {
|
|
548
|
-
const { id: gridId, editing, setEditing } =
|
|
373
|
+
const { id: gridId, editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
|
|
549
374
|
const suppressNextBlur = useRef2(false);
|
|
550
375
|
const { themeMode } = useThemeContext();
|
|
551
|
-
const [
|
|
552
|
-
const [
|
|
553
|
-
const fieldProjection =
|
|
376
|
+
const [validationError, setValidationError] = useState2(null);
|
|
377
|
+
const [validationVariant, setValidationVariant] = useState2("error");
|
|
378
|
+
const fieldProjection = useMemo2(() => {
|
|
554
379
|
if (!model || !editing) {
|
|
555
380
|
return;
|
|
556
381
|
}
|
|
@@ -559,7 +384,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
|
|
|
559
384
|
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
560
385
|
invariant2(fieldProjection2, void 0, {
|
|
561
386
|
F: __dxlog_file2,
|
|
562
|
-
L:
|
|
387
|
+
L: 122,
|
|
563
388
|
S: void 0,
|
|
564
389
|
A: [
|
|
565
390
|
"fieldProjection",
|
|
@@ -571,38 +396,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
|
|
|
571
396
|
model,
|
|
572
397
|
editing
|
|
573
398
|
]);
|
|
574
|
-
|
|
575
|
-
if (!model || !editing || !fieldProjection) {
|
|
576
|
-
setValidationError(null);
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const cell = parseCellIndex2(editing.index);
|
|
580
|
-
const { row, col } = cell;
|
|
581
|
-
if (model.isDraftCell(cell)) {
|
|
582
|
-
const field = model.projection.fields[col];
|
|
583
|
-
const hasValidationError = model.hasDraftRowValidationError(row, field.path);
|
|
584
|
-
if (hasValidationError) {
|
|
585
|
-
const draftRows = model.draftRows.value;
|
|
586
|
-
if (row >= 0 && row < draftRows.length) {
|
|
587
|
-
const draftRow = draftRows[row];
|
|
588
|
-
const validationError = draftRow.validationErrors?.find((error) => error.path === field.path);
|
|
589
|
-
if (validationError) {
|
|
590
|
-
setValidationError(validationError.message);
|
|
591
|
-
setValidationVariant("warning");
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
} else {
|
|
595
|
-
setValidationError(null);
|
|
596
|
-
}
|
|
597
|
-
} else {
|
|
598
|
-
setValidationError(null);
|
|
599
|
-
}
|
|
600
|
-
}, [
|
|
601
|
-
model,
|
|
602
|
-
editing,
|
|
603
|
-
fieldProjection
|
|
604
|
-
]);
|
|
605
|
-
const handleEnter = useCallback4(async (value) => {
|
|
399
|
+
const handleEnter = useCallback2(async (value) => {
|
|
606
400
|
if (!model || !editing) {
|
|
607
401
|
return;
|
|
608
402
|
}
|
|
@@ -611,33 +405,39 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
|
|
|
611
405
|
if (validationResult.valid) {
|
|
612
406
|
setValidationError(null);
|
|
613
407
|
model.setCellData(cell, value);
|
|
614
|
-
onEnter?.(cell);
|
|
615
408
|
onFocus?.();
|
|
616
409
|
setEditing(null);
|
|
617
410
|
onSave?.();
|
|
618
411
|
} else {
|
|
619
|
-
setValidationError(validationResult.error);
|
|
412
|
+
setValidationError(adaptValidationMessage(validationResult.error));
|
|
620
413
|
setValidationVariant("error");
|
|
621
414
|
}
|
|
622
415
|
}, [
|
|
623
416
|
model,
|
|
624
417
|
editing,
|
|
625
|
-
onEnter,
|
|
626
418
|
onFocus,
|
|
627
419
|
setEditing
|
|
628
420
|
]);
|
|
629
|
-
const handleBlur =
|
|
630
|
-
if (!model || !editing) {
|
|
631
|
-
return;
|
|
632
|
-
}
|
|
421
|
+
const handleBlur = useCallback2(async (value) => {
|
|
633
422
|
if (suppressNextBlur.current) {
|
|
634
423
|
suppressNextBlur.current = false;
|
|
424
|
+
} else if (model && editing) {
|
|
425
|
+
const cell = parseCellIndex2(editing.index);
|
|
426
|
+
if (value !== void 0) {
|
|
427
|
+
const result = await model.validateCellData(cell, value);
|
|
428
|
+
if (result.valid) {
|
|
429
|
+
setValidationError(null);
|
|
430
|
+
model.setCellData(cell, value);
|
|
431
|
+
setEditing(null);
|
|
432
|
+
onSave?.();
|
|
433
|
+
}
|
|
434
|
+
}
|
|
635
435
|
}
|
|
636
436
|
}, [
|
|
637
437
|
model,
|
|
638
438
|
editing
|
|
639
439
|
]);
|
|
640
|
-
const handleClose =
|
|
440
|
+
const handleClose = useCallback2(async (value, event) => {
|
|
641
441
|
if (!model || !editing || !fieldProjection) {
|
|
642
442
|
return;
|
|
643
443
|
}
|
|
@@ -645,19 +445,20 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
|
|
|
645
445
|
if (value !== void 0) {
|
|
646
446
|
const result = await model.validateCellData(cell, value);
|
|
647
447
|
if (result.valid) {
|
|
448
|
+
suppressNextBlur.current = true;
|
|
648
449
|
setValidationError(null);
|
|
649
450
|
model.setCellData(cell, value);
|
|
650
451
|
setEditing(null);
|
|
651
452
|
onSave?.();
|
|
652
|
-
onEnter?.(cell);
|
|
653
453
|
if (event && onFocus) {
|
|
654
|
-
onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
|
|
454
|
+
onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
|
|
655
455
|
}
|
|
656
456
|
} else {
|
|
657
457
|
setValidationError(result.error);
|
|
658
458
|
setValidationVariant("error");
|
|
659
459
|
}
|
|
660
460
|
} else {
|
|
461
|
+
suppressNextBlur.current = true;
|
|
661
462
|
setValidationError(null);
|
|
662
463
|
setEditing(null);
|
|
663
464
|
onSave?.();
|
|
@@ -669,12 +470,11 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
|
|
|
669
470
|
model,
|
|
670
471
|
editing,
|
|
671
472
|
onFocus,
|
|
672
|
-
onEnter,
|
|
673
473
|
fieldProjection,
|
|
674
474
|
setEditing,
|
|
675
475
|
onSave
|
|
676
476
|
]);
|
|
677
|
-
const extension =
|
|
477
|
+
const extension = useMemo2(() => {
|
|
678
478
|
if (!fieldProjection) {
|
|
679
479
|
return [];
|
|
680
480
|
}
|
|
@@ -717,131 +517,369 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
|
|
|
717
517
|
}
|
|
718
518
|
}));
|
|
719
519
|
}
|
|
720
|
-
if (
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
520
|
+
if (model && editing) {
|
|
521
|
+
extension2.push(EditorView.updateListener.of(debounce((update) => {
|
|
522
|
+
const content = update.state.doc.toString();
|
|
523
|
+
const cell = parseCellIndex2(editing.index);
|
|
524
|
+
void model.validateCellData(cell, content).then((result) => {
|
|
525
|
+
if (result.valid) {
|
|
526
|
+
setValidationError(null);
|
|
527
|
+
} else {
|
|
528
|
+
setValidationError(result.error);
|
|
529
|
+
setValidationVariant("error");
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
}, 10)));
|
|
533
|
+
}
|
|
534
|
+
return extension2;
|
|
535
|
+
}, [
|
|
536
|
+
model,
|
|
537
|
+
modals,
|
|
538
|
+
editing,
|
|
539
|
+
fieldProjection,
|
|
540
|
+
handleClose,
|
|
541
|
+
themeMode
|
|
542
|
+
]);
|
|
543
|
+
const getCellContent = useCallback2(() => {
|
|
544
|
+
if (model && editing) {
|
|
545
|
+
const cell = parseCellIndex2(editing.index);
|
|
546
|
+
const { col } = cell;
|
|
547
|
+
const field = model.projection.fields[col];
|
|
548
|
+
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
549
|
+
if (fieldProjection2?.props.format === FormatEnum.SingleSelect || fieldProjection2?.props.format === FormatEnum.MultiSelect) {
|
|
550
|
+
const value2 = model.getCellData(cell);
|
|
551
|
+
if (value2 !== void 0) {
|
|
552
|
+
const options = fieldProjection2.props.options || [];
|
|
553
|
+
if (fieldProjection2.props.format === FormatEnum.MultiSelect) {
|
|
554
|
+
const tagItems = value2.split(",").map((id) => {
|
|
555
|
+
const option = options.find((o) => o.id === id);
|
|
556
|
+
if (option) {
|
|
557
|
+
return {
|
|
558
|
+
id,
|
|
559
|
+
label: option.title,
|
|
560
|
+
hue: option.color
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
return void 0;
|
|
564
|
+
}).filter((item) => item !== void 0);
|
|
565
|
+
return createLinks(tagItems);
|
|
566
|
+
} else {
|
|
567
|
+
const option = options.find((o) => o.id === value2);
|
|
568
|
+
if (option) {
|
|
569
|
+
const tagItem = {
|
|
570
|
+
id: value2,
|
|
571
|
+
label: option.title,
|
|
572
|
+
hue: option.color
|
|
573
|
+
};
|
|
574
|
+
return createLinks([
|
|
575
|
+
tagItem
|
|
576
|
+
]);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return "";
|
|
581
|
+
}
|
|
582
|
+
const value = model.getCellData(cell);
|
|
583
|
+
return value !== void 0 ? String(value) : "";
|
|
584
|
+
}
|
|
585
|
+
}, [
|
|
586
|
+
model,
|
|
587
|
+
editing
|
|
588
|
+
]);
|
|
589
|
+
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(CellValidationMessage, {
|
|
590
|
+
validationError,
|
|
591
|
+
variant: validationVariant,
|
|
592
|
+
__gridScope
|
|
593
|
+
}), /* @__PURE__ */ React3.createElement(GridCellEditor, {
|
|
594
|
+
extension,
|
|
595
|
+
getCellContent,
|
|
596
|
+
onBlur: handleBlur,
|
|
597
|
+
slots: editorSlots
|
|
598
|
+
}));
|
|
599
|
+
} finally {
|
|
600
|
+
_effect.f();
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
var determineNavigationAxis = ({ key }) => {
|
|
604
|
+
switch (key) {
|
|
605
|
+
case "ArrowUp":
|
|
606
|
+
case "ArrowDown":
|
|
607
|
+
case "Enter": {
|
|
608
|
+
return "row";
|
|
609
|
+
}
|
|
610
|
+
case "ArrowLeft":
|
|
611
|
+
case "ArrowRight":
|
|
612
|
+
case "Tab":
|
|
613
|
+
return "col";
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
var determineNavigationDelta = ({ key, shift }) => {
|
|
617
|
+
switch (key) {
|
|
618
|
+
case "ArrowUp":
|
|
619
|
+
case "ArrowLeft":
|
|
620
|
+
return -1;
|
|
621
|
+
case "ArrowDown":
|
|
622
|
+
case "ArrowRight":
|
|
623
|
+
return 1;
|
|
624
|
+
}
|
|
625
|
+
return shift ? -1 : 1;
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
// src/components/Table/ColumnActionsMenu.tsx
|
|
629
|
+
import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
|
|
630
|
+
import React4 from "react";
|
|
631
|
+
import { DropdownMenu, useTranslation } from "@dxos/react-ui";
|
|
632
|
+
var ColumnActionsMenu = ({ model, modals }) => {
|
|
633
|
+
var _effect = _useSignals4();
|
|
634
|
+
try {
|
|
635
|
+
const { t } = useTranslation(translationKey);
|
|
636
|
+
const state = modals.state.value;
|
|
637
|
+
if (state?.type !== "column") {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
const currentSort = model.sorting?.sorting;
|
|
641
|
+
const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
|
|
642
|
+
return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
|
|
643
|
+
modal: false,
|
|
644
|
+
open: true,
|
|
645
|
+
onOpenChange: modals.close
|
|
646
|
+
}, /* @__PURE__ */ React4.createElement(DropdownMenu.VirtualTrigger, {
|
|
647
|
+
virtualRef: modals.trigger
|
|
648
|
+
}), /* @__PURE__ */ React4.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
649
|
+
"data-testid": "column-sort-descending",
|
|
650
|
+
onClick: () => model.sorting?.setSort(state.fieldId, "desc")
|
|
651
|
+
}, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
652
|
+
"data-testid": "column-sort-ascending",
|
|
653
|
+
onClick: () => model.sorting?.setSort(state.fieldId, "asc")
|
|
654
|
+
}, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
655
|
+
"data-testid": "column-clear-sort",
|
|
656
|
+
onClick: () => model.sorting?.clearSort()
|
|
657
|
+
}, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
658
|
+
"data-testid": "column-delete",
|
|
659
|
+
onClick: () => model.deleteColumn(state.fieldId)
|
|
660
|
+
}, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
661
|
+
"data-testid": "column-settings",
|
|
662
|
+
onClick: () => modals.openColumnSettings()
|
|
663
|
+
}, t("column action settings"))), /* @__PURE__ */ React4.createElement(DropdownMenu.Arrow, null))));
|
|
664
|
+
} finally {
|
|
665
|
+
_effect.f();
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// src/components/Table/ColumnSettings.tsx
|
|
670
|
+
import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
|
|
671
|
+
import React5, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useState as useState3 } from "react";
|
|
672
|
+
import { Popover as Popover2 } from "@dxos/react-ui";
|
|
673
|
+
import { FieldEditor } from "@dxos/react-ui-form";
|
|
674
|
+
var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
|
|
675
|
+
var _effect = _useSignals5();
|
|
676
|
+
try {
|
|
677
|
+
const [newField, setNewField] = useState3();
|
|
678
|
+
const state = modals.state.value;
|
|
679
|
+
useEffect2(() => {
|
|
680
|
+
if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
|
|
681
|
+
setNewField(model.projection.createFieldProjection());
|
|
682
|
+
requestAnimationFrame(() => {
|
|
683
|
+
onNewColumn();
|
|
684
|
+
});
|
|
685
|
+
} else {
|
|
686
|
+
setNewField(void 0);
|
|
687
|
+
}
|
|
688
|
+
}, [
|
|
689
|
+
model?.projection,
|
|
690
|
+
state
|
|
691
|
+
]);
|
|
692
|
+
const existingField = useMemo3(() => {
|
|
693
|
+
if (state?.type === "columnSettings") {
|
|
694
|
+
const { mode } = state;
|
|
695
|
+
if (mode.type === "edit") {
|
|
696
|
+
return model?.projection?.fields.find((f) => f.id === mode.fieldId);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return void 0;
|
|
700
|
+
}, [
|
|
701
|
+
model?.projection?.fields,
|
|
702
|
+
state
|
|
703
|
+
]);
|
|
704
|
+
const field = existingField ?? newField;
|
|
705
|
+
const handleSave = useCallback3(() => {
|
|
706
|
+
modals.close();
|
|
707
|
+
}, [
|
|
708
|
+
modals
|
|
709
|
+
]);
|
|
710
|
+
const handleCancel = useCallback3(() => {
|
|
711
|
+
if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
|
|
712
|
+
model?.projection.deleteFieldProjection(newField.id);
|
|
713
|
+
}
|
|
714
|
+
}, [
|
|
715
|
+
model?.projection,
|
|
716
|
+
state,
|
|
717
|
+
newField
|
|
718
|
+
]);
|
|
719
|
+
if (!model?.projection || !field) {
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
return /* @__PURE__ */ React5.createElement(Popover2.Root, {
|
|
723
|
+
modal: false,
|
|
724
|
+
open: state?.type === "columnSettings"
|
|
725
|
+
}, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
|
|
726
|
+
virtualRef: modals.trigger
|
|
727
|
+
}), /* @__PURE__ */ React5.createElement(Popover2.Portal, null, /* @__PURE__ */ React5.createElement(Popover2.Content, {
|
|
728
|
+
classNames: "md:is-64"
|
|
729
|
+
}, /* @__PURE__ */ React5.createElement(Popover2.Viewport, null, /* @__PURE__ */ React5.createElement(FieldEditor, {
|
|
730
|
+
projection: model.projection,
|
|
731
|
+
field,
|
|
732
|
+
registry,
|
|
733
|
+
onSave: handleSave,
|
|
734
|
+
onCancel: handleCancel
|
|
735
|
+
})), /* @__PURE__ */ React5.createElement(Popover2.Arrow, null))));
|
|
736
|
+
} finally {
|
|
737
|
+
_effect.f();
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
// src/components/Table/CreateRefPanel.tsx
|
|
742
|
+
import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
|
|
743
|
+
import { Schema } from "effect";
|
|
744
|
+
import React6, { useCallback as useCallback4, useMemo as useMemo4 } from "react";
|
|
745
|
+
import { Type } from "@dxos/echo";
|
|
746
|
+
import { live } from "@dxos/live-object";
|
|
747
|
+
import { useClient } from "@dxos/react-client";
|
|
748
|
+
import { getSpace as getSpace2 } from "@dxos/react-client/echo";
|
|
749
|
+
import { Popover as Popover3 } from "@dxos/react-ui";
|
|
750
|
+
import { Form as Form2 } from "@dxos/react-ui-form";
|
|
751
|
+
import { useGridContext as useGridContext4 } from "@dxos/react-ui-grid";
|
|
752
|
+
var CreateRefPanel = ({ model, modals, __gridScope }) => {
|
|
753
|
+
var _effect = _useSignals6();
|
|
754
|
+
try {
|
|
755
|
+
const { id: gridId } = useGridContext4("TableCellEditor", __gridScope);
|
|
756
|
+
const client = useClient();
|
|
757
|
+
const space = model && getSpace2(model?.view);
|
|
758
|
+
const state = modals.state.value;
|
|
759
|
+
const getSchema = useCallback4(() => {
|
|
760
|
+
if (!space || state?.type !== "createRefPanel") {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
const staticSchema = client.graph.schemaRegistry.schemas.find((schema3) => Type.getTypename(schema3) === state.typename);
|
|
764
|
+
if (staticSchema) {
|
|
765
|
+
return staticSchema;
|
|
748
766
|
}
|
|
749
|
-
|
|
767
|
+
const [schema2] = space.db.schemaRegistry.query({
|
|
768
|
+
typename: state.typename
|
|
769
|
+
}).runSync();
|
|
770
|
+
return schema2;
|
|
771
|
+
}, [
|
|
772
|
+
space,
|
|
773
|
+
state
|
|
774
|
+
]);
|
|
775
|
+
const schema = useMemo4(() => {
|
|
776
|
+
const schema2 = getSchema();
|
|
777
|
+
if (!schema2) {
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
const omit = Schema.omit("id");
|
|
781
|
+
return omit(schema2);
|
|
782
|
+
}, [
|
|
783
|
+
getSchema
|
|
784
|
+
]);
|
|
785
|
+
const handleSave = useCallback4((values) => {
|
|
786
|
+
if (!model || !space || state?.type !== "createRefPanel") {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const schema2 = getSchema();
|
|
790
|
+
if (schema2) {
|
|
791
|
+
const obj = space.db.add(live(schema2, values));
|
|
792
|
+
state.onCreate?.(obj);
|
|
793
|
+
}
|
|
794
|
+
void modals.close();
|
|
750
795
|
}, [
|
|
751
796
|
model,
|
|
752
797
|
modals,
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
handleClose,
|
|
756
|
-
themeMode
|
|
798
|
+
space,
|
|
799
|
+
state
|
|
757
800
|
]);
|
|
758
|
-
const
|
|
759
|
-
if (model
|
|
760
|
-
|
|
761
|
-
const { col } = cell;
|
|
762
|
-
const field = model.projection.fields[col];
|
|
763
|
-
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
764
|
-
if (fieldProjection2?.props.format === FormatEnum.SingleSelect || fieldProjection2?.props.format === FormatEnum.MultiSelect) {
|
|
765
|
-
const value2 = model.getCellData(cell);
|
|
766
|
-
if (value2 !== void 0) {
|
|
767
|
-
const options = fieldProjection2.props.options || [];
|
|
768
|
-
if (fieldProjection2.props.format === FormatEnum.MultiSelect) {
|
|
769
|
-
const tagItems = value2.split(",").map((id) => {
|
|
770
|
-
const option = options.find((o) => o.id === id);
|
|
771
|
-
if (option) {
|
|
772
|
-
return {
|
|
773
|
-
id,
|
|
774
|
-
label: option.title,
|
|
775
|
-
hue: option.color
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
return void 0;
|
|
779
|
-
}).filter((item) => item !== void 0);
|
|
780
|
-
return createLinks(tagItems);
|
|
781
|
-
} else {
|
|
782
|
-
const option = options.find((o) => o.id === value2);
|
|
783
|
-
if (option) {
|
|
784
|
-
const tagItem = {
|
|
785
|
-
id: value2,
|
|
786
|
-
label: option.title,
|
|
787
|
-
hue: option.color
|
|
788
|
-
};
|
|
789
|
-
return createLinks([
|
|
790
|
-
tagItem
|
|
791
|
-
]);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
return "";
|
|
796
|
-
}
|
|
797
|
-
const value = model.getCellData(cell);
|
|
798
|
-
return value !== void 0 ? String(value) : "";
|
|
801
|
+
const handleCancel = useCallback4(() => {
|
|
802
|
+
if (model) {
|
|
803
|
+
modals.close();
|
|
799
804
|
}
|
|
800
805
|
}, [
|
|
801
|
-
|
|
802
|
-
editing
|
|
806
|
+
modals
|
|
803
807
|
]);
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
808
|
+
if (!model?.projection) {
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
return /* @__PURE__ */ React6.createElement(Popover3.Root, {
|
|
812
|
+
modal: false,
|
|
813
|
+
open: state?.type === "createRefPanel" && !!schema,
|
|
814
|
+
onOpenChange: (nextOpen) => {
|
|
815
|
+
if (model && !nextOpen) {
|
|
816
|
+
return modals.close();
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
|
|
820
|
+
virtualRef: modals.trigger
|
|
821
|
+
}), /* @__PURE__ */ React6.createElement(Popover3.Portal, null, /* @__PURE__ */ React6.createElement(Popover3.Content, {
|
|
822
|
+
classNames: "md:is-64",
|
|
823
|
+
"data-grid": gridId
|
|
824
|
+
}, /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React6.createElement(Form2, {
|
|
825
|
+
schema,
|
|
826
|
+
values: state.initialValues ?? {},
|
|
827
|
+
onSave: handleSave,
|
|
828
|
+
onCancel: handleCancel
|
|
829
|
+
})), /* @__PURE__ */ React6.createElement(Popover3.Arrow, null))));
|
|
814
830
|
} finally {
|
|
815
831
|
_effect.f();
|
|
816
832
|
}
|
|
817
833
|
};
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
834
|
+
|
|
835
|
+
// src/components/Table/RowActionsMenu.tsx
|
|
836
|
+
import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
|
|
837
|
+
import React7 from "react";
|
|
838
|
+
import { DropdownMenu as DropdownMenu2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
839
|
+
var RowActionsMenu = ({ model, modals }) => {
|
|
840
|
+
var _effect = _useSignals7();
|
|
841
|
+
try {
|
|
842
|
+
const { t } = useTranslation2(translationKey);
|
|
843
|
+
const hasSelection = model.selection.hasSelection.value;
|
|
844
|
+
const state = modals.state.value;
|
|
845
|
+
if (state?.type !== "row") {
|
|
846
|
+
return null;
|
|
824
847
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
848
|
+
return /* @__PURE__ */ React7.createElement(DropdownMenu2.Root, {
|
|
849
|
+
modal: false,
|
|
850
|
+
open: true,
|
|
851
|
+
onOpenChange: modals.close
|
|
852
|
+
}, /* @__PURE__ */ React7.createElement(DropdownMenu2.VirtualTrigger, {
|
|
853
|
+
virtualRef: modals.trigger
|
|
854
|
+
}), /* @__PURE__ */ React7.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React7.createElement(DropdownMenu2.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
|
|
855
|
+
"data-testid": "row-menu-delete",
|
|
856
|
+
onClick: () => model.deleteRow(state.rowIndex)
|
|
857
|
+
}, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
|
|
858
|
+
key: action.id,
|
|
859
|
+
"data-testid": `row-action-${action.id}`,
|
|
860
|
+
onClick: () => {
|
|
861
|
+
modals.close();
|
|
862
|
+
model.handleRowAction(action.id, state.rowIndex);
|
|
863
|
+
}
|
|
864
|
+
}, toLocalizedString(action.label, t)))), /* @__PURE__ */ React7.createElement(DropdownMenu2.Arrow, null)));
|
|
865
|
+
} finally {
|
|
866
|
+
_effect.f();
|
|
839
867
|
}
|
|
840
|
-
return shift ? -1 : 1;
|
|
841
868
|
};
|
|
842
869
|
|
|
843
870
|
// src/components/Table/Table.tsx
|
|
844
|
-
var
|
|
871
|
+
var columnDefault = {
|
|
872
|
+
grid: {
|
|
873
|
+
minSize: 80,
|
|
874
|
+
maxSize: 640
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
var rowDefault = {
|
|
878
|
+
frozenRowsStart: {
|
|
879
|
+
readonly: true,
|
|
880
|
+
focusUnfurl: false
|
|
881
|
+
}
|
|
882
|
+
};
|
|
845
883
|
var TableRoot = ({ children, role = "article" }) => {
|
|
846
884
|
var _effect = _useSignals8();
|
|
847
885
|
try {
|
|
@@ -865,14 +903,19 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
865
903
|
try {
|
|
866
904
|
const [dxGrid, setDxGrid] = useState4(null);
|
|
867
905
|
const { hasAttention } = useAttention(model?.id ?? "table");
|
|
868
|
-
const { t } = useTranslation3(translationKey);
|
|
869
906
|
const modals = useMemo5(() => new ModalController(), []);
|
|
870
907
|
const draftRowCount = model?.getDraftRowCount() ?? 0;
|
|
908
|
+
const handleSave = useCallback5(() => {
|
|
909
|
+
dxGrid?.updateCells(true);
|
|
910
|
+
dxGrid?.requestUpdate();
|
|
911
|
+
}, [
|
|
912
|
+
dxGrid
|
|
913
|
+
]);
|
|
871
914
|
const frozen = useMemo5(() => {
|
|
872
915
|
const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
|
|
873
916
|
return {
|
|
874
917
|
frozenRowsStart: 1,
|
|
875
|
-
frozenRowsEnd: draftRowCount,
|
|
918
|
+
frozenRowsEnd: Math.max(1, draftRowCount),
|
|
876
919
|
frozenColsStart: model?.features.selection.enabled ? 1 : 0,
|
|
877
920
|
frozenColsEnd: noActionColumn ? 0 : 1
|
|
878
921
|
};
|
|
@@ -883,7 +926,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
883
926
|
const getCells = useCallback5((range, plane) => presentation?.getCells(range, plane) ?? {}, [
|
|
884
927
|
presentation
|
|
885
928
|
]);
|
|
886
|
-
|
|
929
|
+
useEffect3(() => {
|
|
887
930
|
if (!presentation || !dxGrid) {
|
|
888
931
|
return;
|
|
889
932
|
}
|
|
@@ -893,6 +936,30 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
893
936
|
dxGrid,
|
|
894
937
|
getCells
|
|
895
938
|
]);
|
|
939
|
+
const handleInsertRowResult = useCallback5((insertResult) => {
|
|
940
|
+
if (insertResult === "draft") {
|
|
941
|
+
requestAnimationFrame(() => {
|
|
942
|
+
dxGrid?.setFocus({
|
|
943
|
+
plane: "frozenRowsEnd",
|
|
944
|
+
col: 0,
|
|
945
|
+
row: 0
|
|
946
|
+
});
|
|
947
|
+
dxGrid?.refocus();
|
|
948
|
+
});
|
|
949
|
+
} else {
|
|
950
|
+
requestAnimationFrame(() => {
|
|
951
|
+
dxGrid?.setFocus({
|
|
952
|
+
plane: "grid",
|
|
953
|
+
col: 0,
|
|
954
|
+
row: model ? model.getRowCount() - 1 : 0
|
|
955
|
+
});
|
|
956
|
+
dxGrid?.refocus();
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
}, [
|
|
960
|
+
model,
|
|
961
|
+
dxGrid
|
|
962
|
+
]);
|
|
896
963
|
useImperativeHandle(forwardedRef, () => {
|
|
897
964
|
if (!presentation || !dxGrid) {
|
|
898
965
|
return {};
|
|
@@ -905,18 +972,38 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
905
972
|
dxGrid.updateCells(true);
|
|
906
973
|
dxGrid.requestUpdate();
|
|
907
974
|
}
|
|
908
|
-
}
|
|
975
|
+
},
|
|
976
|
+
handleInsertRowResult
|
|
909
977
|
};
|
|
910
978
|
}, [
|
|
911
979
|
presentation,
|
|
980
|
+
dxGrid,
|
|
981
|
+
model
|
|
982
|
+
]);
|
|
983
|
+
const handleSaveDraftRow = useCallback5((rowIndex = 0) => {
|
|
984
|
+
if (model && dxGrid) {
|
|
985
|
+
const didCommitSuccessfully = model.commitDraftRow(rowIndex);
|
|
986
|
+
if (didCommitSuccessfully) {
|
|
987
|
+
requestAnimationFrame(() => {
|
|
988
|
+
dxGrid.scrollToEndRow();
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}, [
|
|
993
|
+
model,
|
|
912
994
|
dxGrid
|
|
913
995
|
]);
|
|
914
996
|
const handleGridClick = useCallback5((event) => {
|
|
915
|
-
const
|
|
916
|
-
if (
|
|
997
|
+
const cell = closestCell(event.target);
|
|
998
|
+
if (cell) {
|
|
999
|
+
const { row: rowIndex, plane } = cell;
|
|
917
1000
|
if (onRowClick) {
|
|
918
|
-
|
|
919
|
-
|
|
1001
|
+
if (plane === "grid") {
|
|
1002
|
+
const row = model?.getRowAt(rowIndex);
|
|
1003
|
+
row && onRowClick(row);
|
|
1004
|
+
} else {
|
|
1005
|
+
onRowClick(cell);
|
|
1006
|
+
}
|
|
920
1007
|
}
|
|
921
1008
|
if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
|
|
922
1009
|
model.selection.toggleSelectionForRowIndex(rowIndex);
|
|
@@ -952,14 +1039,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
952
1039
|
break;
|
|
953
1040
|
}
|
|
954
1041
|
case "saveDraftRow": {
|
|
955
|
-
|
|
956
|
-
const didCommitSuccessfully = model.commitDraftRow(data.rowIndex);
|
|
957
|
-
if (dxGrid && didCommitSuccessfully) {
|
|
958
|
-
requestAnimationFrame(() => {
|
|
959
|
-
dxGrid.scrollToEndRow();
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
}
|
|
1042
|
+
handleSaveDraftRow();
|
|
963
1043
|
break;
|
|
964
1044
|
}
|
|
965
1045
|
}
|
|
@@ -998,29 +1078,20 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
998
1078
|
modals,
|
|
999
1079
|
dxGrid
|
|
1000
1080
|
]);
|
|
1001
|
-
const handleFocus = useCallback5((increment, delta) => {
|
|
1002
|
-
if (dxGrid) {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
return;
|
|
1011
|
-
}
|
|
1012
|
-
if (model && cell.row === model.getRowCount() - 1) {
|
|
1013
|
-
model.insertRow();
|
|
1014
|
-
if (dxGrid) {
|
|
1015
|
-
requestAnimationFrame(() => {
|
|
1016
|
-
dxGrid?.scrollToRow(cell.row + 1);
|
|
1017
|
-
dxGrid?.refocus("row", 1);
|
|
1018
|
-
});
|
|
1081
|
+
const handleFocus = useCallback5((increment, delta, cell) => {
|
|
1082
|
+
if (dxGrid && model) {
|
|
1083
|
+
if (cell?.plane === "grid" && cell?.row >= model.getRowCount() - 1) {
|
|
1084
|
+
handleInsertRowResult(draftRowCount < 1 ? model.insertRow() : "final");
|
|
1085
|
+
} else if (cell?.plane === "frozenRowsEnd" && increment === "row") {
|
|
1086
|
+
handleSaveDraftRow(cell.row);
|
|
1087
|
+
handleInsertRowResult(model.insertRow());
|
|
1088
|
+
} else {
|
|
1089
|
+
dxGrid.refocus(increment, delta);
|
|
1019
1090
|
}
|
|
1020
1091
|
}
|
|
1021
1092
|
}, [
|
|
1022
|
-
|
|
1023
|
-
|
|
1093
|
+
dxGrid,
|
|
1094
|
+
model
|
|
1024
1095
|
]);
|
|
1025
1096
|
const handleKeyDown = useCallback5((event) => {
|
|
1026
1097
|
if (!model?.features.dataEditable) {
|
|
@@ -1030,15 +1101,63 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
1030
1101
|
if (!model || !cell) {
|
|
1031
1102
|
return;
|
|
1032
1103
|
}
|
|
1104
|
+
if (event.metaKey || event.ctrlKey) {
|
|
1105
|
+
switch (event.key) {
|
|
1106
|
+
case "c": {
|
|
1107
|
+
try {
|
|
1108
|
+
const cellData = model.getCellData(cell);
|
|
1109
|
+
const textContent = cellData?.toString() ?? "";
|
|
1110
|
+
void navigator.clipboard.writeText(textContent);
|
|
1111
|
+
event.preventDefault();
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
console.warn("Failed to copy cell content:", error);
|
|
1114
|
+
}
|
|
1115
|
+
break;
|
|
1116
|
+
}
|
|
1117
|
+
case "v": {
|
|
1118
|
+
event.preventDefault();
|
|
1119
|
+
void navigator.clipboard.readText().then((clipboardText) => {
|
|
1120
|
+
try {
|
|
1121
|
+
model.setCellData(cell, clipboardText);
|
|
1122
|
+
handleSave();
|
|
1123
|
+
} catch {
|
|
1124
|
+
const cellElement = event.target.closest('[data-dx-grid-action="cell"]');
|
|
1125
|
+
if (cellElement) {
|
|
1126
|
+
const rect = cellElement.getBoundingClientRect();
|
|
1127
|
+
const editRequest = new DxEditRequest({
|
|
1128
|
+
cellIndex: `${cell.plane},${cell.col},${cell.row}`,
|
|
1129
|
+
cellBox: {
|
|
1130
|
+
insetInlineStart: rect.left,
|
|
1131
|
+
insetBlockStart: rect.top,
|
|
1132
|
+
inlineSize: rect.width,
|
|
1133
|
+
blockSize: rect.height
|
|
1134
|
+
},
|
|
1135
|
+
cellElement,
|
|
1136
|
+
initialContent: clipboardText
|
|
1137
|
+
});
|
|
1138
|
+
cellElement.dispatchEvent(editRequest);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
break;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1033
1146
|
switch (event.key) {
|
|
1034
1147
|
case "Backspace":
|
|
1035
1148
|
case "Delete": {
|
|
1036
|
-
|
|
1149
|
+
try {
|
|
1150
|
+
model.setCellData(cell, void 0);
|
|
1151
|
+
event.preventDefault();
|
|
1152
|
+
} catch {
|
|
1153
|
+
}
|
|
1037
1154
|
break;
|
|
1038
1155
|
}
|
|
1039
1156
|
}
|
|
1040
1157
|
}, [
|
|
1041
|
-
model
|
|
1158
|
+
model,
|
|
1159
|
+
dxGrid,
|
|
1160
|
+
handleSave
|
|
1042
1161
|
]);
|
|
1043
1162
|
const handleAxisResize = useCallback5((event) => {
|
|
1044
1163
|
if (event.axis === "col") {
|
|
@@ -1065,59 +1184,6 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
1065
1184
|
model,
|
|
1066
1185
|
dxGrid
|
|
1067
1186
|
]);
|
|
1068
|
-
const handleQuery = useCallback5(async ({ field, props }, text) => {
|
|
1069
|
-
if (model && props.referenceSchema && field.referencePath) {
|
|
1070
|
-
const space = getSpace2(model.view);
|
|
1071
|
-
invariant3(space, void 0, {
|
|
1072
|
-
F: __dxlog_file3,
|
|
1073
|
-
L: 325,
|
|
1074
|
-
S: void 0,
|
|
1075
|
-
A: [
|
|
1076
|
-
"space",
|
|
1077
|
-
""
|
|
1078
|
-
]
|
|
1079
|
-
});
|
|
1080
|
-
let schema2;
|
|
1081
|
-
if (client) {
|
|
1082
|
-
schema2 = client.graph.schemaRegistry.getSchema(props.referenceSchema);
|
|
1083
|
-
}
|
|
1084
|
-
if (!schema2) {
|
|
1085
|
-
schema2 = space.db.schemaRegistry.getSchema(props.referenceSchema);
|
|
1086
|
-
}
|
|
1087
|
-
if (schema2) {
|
|
1088
|
-
const { objects } = await space.db.query(Filter.type(schema2)).run();
|
|
1089
|
-
const options = objects.map((obj) => {
|
|
1090
|
-
const value = getValue(obj, field.referencePath);
|
|
1091
|
-
if (!value || typeof value !== "string") {
|
|
1092
|
-
return void 0;
|
|
1093
|
-
}
|
|
1094
|
-
return {
|
|
1095
|
-
label: value,
|
|
1096
|
-
data: obj
|
|
1097
|
-
};
|
|
1098
|
-
}).filter(isNotFalsy);
|
|
1099
|
-
return [
|
|
1100
|
-
...options,
|
|
1101
|
-
{
|
|
1102
|
-
label: t("create new object label", {
|
|
1103
|
-
text
|
|
1104
|
-
}),
|
|
1105
|
-
data: createOption(text)
|
|
1106
|
-
}
|
|
1107
|
-
];
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
return [];
|
|
1111
|
-
}, [
|
|
1112
|
-
model,
|
|
1113
|
-
client,
|
|
1114
|
-
t
|
|
1115
|
-
]);
|
|
1116
|
-
const handleSave = useCallback5(() => {
|
|
1117
|
-
dxGrid?.updateCells(true);
|
|
1118
|
-
}, [
|
|
1119
|
-
dxGrid
|
|
1120
|
-
]);
|
|
1121
1187
|
if (!model || !modals) {
|
|
1122
1188
|
return /* @__PURE__ */ React8.createElement("span", {
|
|
1123
1189
|
role: "none",
|
|
@@ -1130,20 +1196,21 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
|
|
|
1130
1196
|
model,
|
|
1131
1197
|
modals,
|
|
1132
1198
|
schema,
|
|
1133
|
-
onEnter: handleEnter,
|
|
1134
1199
|
onFocus: handleFocus,
|
|
1135
|
-
|
|
1136
|
-
|
|
1200
|
+
onSave: handleSave,
|
|
1201
|
+
client
|
|
1137
1202
|
}), /* @__PURE__ */ React8.createElement(Grid.Content, {
|
|
1138
1203
|
className: mx("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
|
|
1139
1204
|
frozen,
|
|
1140
1205
|
columns: model.columnMeta.value,
|
|
1206
|
+
columnDefault,
|
|
1207
|
+
rowDefault,
|
|
1141
1208
|
limitRows: model.getRowCount() ?? 0,
|
|
1142
1209
|
limitColumns: model.projection.fields.length,
|
|
1143
1210
|
overscroll: "trap",
|
|
1144
1211
|
onAxisResize: handleAxisResize,
|
|
1145
1212
|
onClick: handleGridClick,
|
|
1146
|
-
|
|
1213
|
+
onKeyDownCapture: handleKeyDown,
|
|
1147
1214
|
onWheelCapture: handleWheel,
|
|
1148
1215
|
ref: setDxGrid
|
|
1149
1216
|
}), /* @__PURE__ */ React8.createElement(RowActionsMenu, {
|
|
@@ -1171,7 +1238,7 @@ var Table = {
|
|
|
1171
1238
|
|
|
1172
1239
|
// src/components/Table/DynamicTable.tsx
|
|
1173
1240
|
import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
|
|
1174
|
-
import React9, {
|
|
1241
|
+
import React9, { useCallback as useCallback6, useMemo as useMemo6, useRef as useRef3 } from "react";
|
|
1175
1242
|
import { useDefaultValue } from "@dxos/react-ui";
|
|
1176
1243
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1177
1244
|
var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema: _jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
|
|
@@ -1251,7 +1318,7 @@ import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking
|
|
|
1251
1318
|
import { Rx } from "@effect-rx/rx-react";
|
|
1252
1319
|
import React10, { useMemo as useMemo7 } from "react";
|
|
1253
1320
|
import { live as live2 } from "@dxos/live-object";
|
|
1254
|
-
import {
|
|
1321
|
+
import { MenuProvider, ToolbarMenu, createGapSeparator, createMenuAction, useMenuActions } from "@dxos/react-ui-menu";
|
|
1255
1322
|
import { rxFromSignal } from "@dxos/react-ui-menu";
|
|
1256
1323
|
var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.make((get) => {
|
|
1257
1324
|
const add = createMenuAction("add-row", onAdd, {
|
|
@@ -1338,7 +1405,6 @@ export {
|
|
|
1338
1405
|
TablePresentation,
|
|
1339
1406
|
TableToolbar,
|
|
1340
1407
|
cellClassesForRowSelection,
|
|
1341
|
-
createTable,
|
|
1342
1408
|
getBaseSchema,
|
|
1343
1409
|
makeDynamicTable,
|
|
1344
1410
|
narrowSchema,
|