@dxos/react-ui-table 0.8.4-main.c1de068 → 0.8.4-main.c4373fc
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-4K7JPALT.mjs +66 -0
- package/dist/lib/browser/chunk-4K7JPALT.mjs.map +7 -0
- package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-OZTXLZGM.mjs} +544 -491
- package/dist/lib/browser/chunk-OZTXLZGM.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +590 -675
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +13 -8
- 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-MK6OVUF6.mjs +67 -0
- package/dist/lib/node-esm/chunk-MK6OVUF6.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-Y66YLSTC.mjs → chunk-S56Z4V4X.mjs} +544 -491
- package/dist/lib/node-esm/chunk-S56Z4V4X.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +590 -675
- 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 +13 -8
- 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/DynamicTable.d.ts +2 -2
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +51 -3
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +108 -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 +8 -4
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +42 -4
- 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 +12 -6
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +12 -17
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +39 -4
- 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/TableToolbar/TableToolbar.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +3 -3
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts +3 -2
- package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
- package/dist/types/src/hooks/useTableModel.d.ts +2 -2
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/modal-controller.d.ts +0 -7
- 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 +9 -7
- 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 -3
- package/dist/types/src/model/table-sorting.d.ts.map +1 -1
- package/dist/types/src/testing/useTestTableModel.d.ts +3 -22
- 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 +25 -5
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +4 -5
- 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/schema.d.ts +1 -1
- package/dist/types/src/util/schema.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 +55 -50
- package/src/components/Table/ColumnActionsMenu.tsx +1 -1
- package/src/components/Table/ColumnSettings.tsx +1 -1
- package/src/components/Table/DynamicTable.stories.tsx +15 -11
- package/src/components/Table/DynamicTable.tsx +8 -10
- package/src/components/Table/Relations.stories.tsx +248 -0
- package/src/components/Table/RowActionsMenu.tsx +3 -3
- package/src/components/Table/Table.stories.tsx +66 -54
- package/src/components/Table/Table.tsx +147 -117
- package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
- package/src/components/TableCellEditor/FormCellEditor.tsx +153 -42
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +24 -64
- package/src/components/TableCellEditor/TableCellEditor.tsx +74 -224
- package/src/components/TableCellEditor/index.ts +1 -0
- package/src/components/TableToolbar/TableToolbar.tsx +2 -2
- package/src/components/testing.ts +2 -2
- package/src/hooks/useAddRow.ts +7 -5
- package/src/hooks/useTableModel.ts +2 -2
- package/src/model/modal-controller.ts +1 -29
- package/src/model/selection-model.ts +3 -2
- package/src/model/table-model.test.ts +19 -10
- package/src/model/table-model.ts +37 -25
- package/src/model/table-presentation.test.ts +23 -21
- package/src/model/table-presentation.ts +74 -33
- package/src/model/table-sorting.ts +16 -7
- package/src/playwright/smoke.spec.ts +129 -37
- package/src/testing/useTestTableModel.ts +11 -7
- package/src/translations.ts +2 -2
- package/src/types/index.ts +1 -1
- package/src/types/schema.ts +63 -6
- package/src/util/dynamic-table.ts +13 -13
- package/src/util/index.ts +0 -1
- package/src/util/schema.ts +4 -4
- 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/CreateRefPanel.d.ts +0 -9
- package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
- 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/Table/CreateRefPanel.tsx +0 -86
- package/src/components/Table/relations.stories.tsx +0 -116
- package/src/components/TableCellEditor/extension.ts +0 -61
- package/src/util/table.ts +0 -49
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-table",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.c4373fc",
|
|
4
4
|
"description": "A table component.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -10,21 +10,25 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"exports": {
|
|
12
12
|
"./deprecated": {
|
|
13
|
+
"source": "./src/deprecated/index.ts",
|
|
13
14
|
"types": "./dist/types/src/deprecated/index.d.ts",
|
|
14
15
|
"browser": "./dist/lib/browser/deprecated/index.mjs",
|
|
15
16
|
"node": "./dist/lib/node-esm/deprecated/index.mjs"
|
|
16
17
|
},
|
|
17
18
|
".": {
|
|
19
|
+
"source": "./src/index.ts",
|
|
18
20
|
"types": "./dist/types/src/index.d.ts",
|
|
19
21
|
"browser": "./dist/lib/browser/index.mjs",
|
|
20
22
|
"node": "./dist/lib/node-esm/index.mjs"
|
|
21
23
|
},
|
|
22
24
|
"./testing": {
|
|
25
|
+
"source": "./src/testing/index.ts",
|
|
23
26
|
"types": "./dist/types/src/testing/index.d.ts",
|
|
24
27
|
"browser": "./dist/lib/browser/testing/index.mjs",
|
|
25
28
|
"node": "./dist/lib/node-esm/testing/index.mjs"
|
|
26
29
|
},
|
|
27
30
|
"./types": {
|
|
31
|
+
"source": "./src/types/index.ts",
|
|
28
32
|
"types": "./dist/types/src/types/index.d.ts",
|
|
29
33
|
"browser": "./dist/lib/browser/types/index.mjs",
|
|
30
34
|
"node": "./dist/lib/node-esm/types/index.mjs"
|
|
@@ -49,72 +53,73 @@
|
|
|
49
53
|
"src"
|
|
50
54
|
],
|
|
51
55
|
"dependencies": {
|
|
52
|
-
"@codemirror/autocomplete": "^6.
|
|
53
|
-
"@codemirror/state": "^6.
|
|
54
|
-
"@codemirror/view": "^6.
|
|
56
|
+
"@codemirror/autocomplete": "^6.19.0",
|
|
57
|
+
"@codemirror/state": "^6.5.2",
|
|
58
|
+
"@codemirror/view": "^6.38.4",
|
|
55
59
|
"@fluentui/react-tabster": "^9.24.2",
|
|
56
60
|
"@preact-signals/safe-react": "^0.9.0",
|
|
57
|
-
"@preact/signals-core": "^1.
|
|
61
|
+
"@preact/signals-core": "^1.12.1",
|
|
58
62
|
"@radix-ui/react-context": "1.1.1",
|
|
59
63
|
"@radix-ui/react-primitive": "2.0.2",
|
|
60
64
|
"@radix-ui/react-slot": "1.1.2",
|
|
61
65
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
62
66
|
"date-fns": "^3.3.1",
|
|
63
67
|
"lodash.orderby": "^4.6.0",
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/live-object": "0.8.4-main.
|
|
74
|
-
"@dxos/plugin-search": "0.8.4-main.
|
|
75
|
-
"@dxos/log": "0.8.4-main.
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/react-ui-attention": "0.8.4-main.
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/react-ui-
|
|
80
|
-
"@dxos/react-ui-
|
|
81
|
-
"@dxos/react-
|
|
82
|
-
"@dxos/react-ui-
|
|
83
|
-
"@dxos/react-ui-searchlist": "0.8.4-main.
|
|
84
|
-
"@dxos/react-ui-
|
|
85
|
-
"@dxos/react-ui-
|
|
86
|
-
"@dxos/react-ui-
|
|
87
|
-
"@dxos/react-ui-types": "0.8.4-main.
|
|
88
|
-
"@dxos/schema": "0.8.4-main.
|
|
89
|
-
"@dxos/util": "0.8.4-main.
|
|
68
|
+
"@dxos/async": "0.8.4-main.c4373fc",
|
|
69
|
+
"@dxos/context": "0.8.4-main.c4373fc",
|
|
70
|
+
"@dxos/debug": "0.8.4-main.c4373fc",
|
|
71
|
+
"@dxos/echo-db": "0.8.4-main.c4373fc",
|
|
72
|
+
"@dxos/invariant": "0.8.4-main.c4373fc",
|
|
73
|
+
"@dxos/keys": "0.8.4-main.c4373fc",
|
|
74
|
+
"@dxos/effect": "0.8.4-main.c4373fc",
|
|
75
|
+
"@dxos/echo": "0.8.4-main.c4373fc",
|
|
76
|
+
"@dxos/lit-grid": "0.8.4-main.c4373fc",
|
|
77
|
+
"@dxos/live-object": "0.8.4-main.c4373fc",
|
|
78
|
+
"@dxos/plugin-search": "0.8.4-main.c4373fc",
|
|
79
|
+
"@dxos/log": "0.8.4-main.c4373fc",
|
|
80
|
+
"@dxos/random": "0.8.4-main.c4373fc",
|
|
81
|
+
"@dxos/react-ui-attention": "0.8.4-main.c4373fc",
|
|
82
|
+
"@dxos/react-ui-editor": "0.8.4-main.c4373fc",
|
|
83
|
+
"@dxos/react-ui-components": "0.8.4-main.c4373fc",
|
|
84
|
+
"@dxos/react-ui-form": "0.8.4-main.c4373fc",
|
|
85
|
+
"@dxos/react-client": "0.8.4-main.c4373fc",
|
|
86
|
+
"@dxos/react-ui-grid": "0.8.4-main.c4373fc",
|
|
87
|
+
"@dxos/react-ui-searchlist": "0.8.4-main.c4373fc",
|
|
88
|
+
"@dxos/react-ui-menu": "0.8.4-main.c4373fc",
|
|
89
|
+
"@dxos/react-ui-stack": "0.8.4-main.c4373fc",
|
|
90
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.c4373fc",
|
|
91
|
+
"@dxos/react-ui-types": "0.8.4-main.c4373fc",
|
|
92
|
+
"@dxos/schema": "0.8.4-main.c4373fc",
|
|
93
|
+
"@dxos/util": "0.8.4-main.c4373fc"
|
|
90
94
|
},
|
|
91
95
|
"devDependencies": {
|
|
92
|
-
"@effect-rx/rx-react": "0.
|
|
93
|
-
"@effect/platform": "0.
|
|
96
|
+
"@effect-rx/rx-react": "0.42.4",
|
|
97
|
+
"@effect/platform": "0.92.1",
|
|
94
98
|
"@types/lodash.orderby": "^4.6.9",
|
|
95
|
-
"@types/react": "~
|
|
96
|
-
"@types/react-dom": "~
|
|
97
|
-
"effect": "3.
|
|
99
|
+
"@types/react": "~19.2.2",
|
|
100
|
+
"@types/react-dom": "~19.2.1",
|
|
101
|
+
"effect": "3.18.3",
|
|
98
102
|
"fast-check": "^3.19.0",
|
|
99
|
-
"react": "~
|
|
100
|
-
"react-dom": "~
|
|
101
|
-
"vite": "
|
|
102
|
-
"@dxos/
|
|
103
|
-
"@dxos/plugin-search": "0.8.4-main.
|
|
104
|
-
"@dxos/random": "0.8.4-main.
|
|
105
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
106
|
-
"@dxos/
|
|
107
|
-
"@dxos/
|
|
108
|
-
"@dxos/
|
|
103
|
+
"react": "~19.2.0",
|
|
104
|
+
"react-dom": "~19.2.0",
|
|
105
|
+
"vite": "7.1.9",
|
|
106
|
+
"@dxos/lit-ui": "0.8.4-main.c4373fc",
|
|
107
|
+
"@dxos/plugin-search": "0.8.4-main.c4373fc",
|
|
108
|
+
"@dxos/random": "0.8.4-main.c4373fc",
|
|
109
|
+
"@dxos/react-ui": "0.8.4-main.c4373fc",
|
|
110
|
+
"@dxos/echo-signals": "0.8.4-main.c4373fc",
|
|
111
|
+
"@dxos/react-ui-theme": "0.8.4-main.c4373fc",
|
|
112
|
+
"@dxos/storybook-utils": "0.8.4-main.c4373fc",
|
|
113
|
+
"@dxos/test-utils": "0.8.4-main.c4373fc"
|
|
109
114
|
},
|
|
110
115
|
"peerDependencies": {
|
|
111
116
|
"@effect-rx/rx-react": "^0.34.1",
|
|
112
117
|
"@effect/platform": "^0.80.12",
|
|
113
118
|
"effect": "^3.13.3",
|
|
114
|
-
"react": "
|
|
115
|
-
"react-dom": "
|
|
116
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
117
|
-
"@dxos/react-ui-theme": "0.8.4-main.
|
|
119
|
+
"react": "^19.0.0",
|
|
120
|
+
"react-dom": "^19.0.0",
|
|
121
|
+
"@dxos/react-ui": "0.8.4-main.c4373fc",
|
|
122
|
+
"@dxos/react-ui-theme": "0.8.4-main.c4373fc"
|
|
118
123
|
},
|
|
119
124
|
"publishConfig": {
|
|
120
125
|
"access": "public"
|
|
@@ -6,7 +6,7 @@ import React from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { DropdownMenu, useTranslation } from '@dxos/react-ui';
|
|
8
8
|
|
|
9
|
-
import { type
|
|
9
|
+
import { type ModalController, type TableModel } from '../../model';
|
|
10
10
|
import { translationKey } from '../../translations';
|
|
11
11
|
|
|
12
12
|
type ColumnActionsMenuProps = { model: TableModel; modals: ModalController };
|
|
@@ -10,7 +10,7 @@ import { Popover } from '@dxos/react-ui';
|
|
|
10
10
|
import { FieldEditor } from '@dxos/react-ui-form';
|
|
11
11
|
import { type FieldType } from '@dxos/schema';
|
|
12
12
|
|
|
13
|
-
import { type
|
|
13
|
+
import { type ModalController, type TableModel } from '../../model';
|
|
14
14
|
|
|
15
15
|
type ColumnSettingsProps = {
|
|
16
16
|
registry?: SchemaRegistry;
|
|
@@ -2,25 +2,24 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
6
|
-
|
|
7
|
-
import { type StoryObj, type Meta } from '@storybook/react-vite';
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React, { useMemo, useState } from 'react';
|
|
9
7
|
|
|
10
8
|
import { Obj } from '@dxos/echo';
|
|
11
|
-
import { FormatEnum, type JsonSchemaType } from '@dxos/echo
|
|
9
|
+
import { FormatEnum, type JsonSchemaType } from '@dxos/echo/internal';
|
|
12
10
|
import { faker } from '@dxos/random';
|
|
13
11
|
import { useClient } from '@dxos/react-client';
|
|
14
12
|
import { Filter, useQuery, useSchema } from '@dxos/react-client/echo';
|
|
15
13
|
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
14
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
16
15
|
import { type SchemaPropertyDefinition } from '@dxos/schema';
|
|
17
16
|
import { Testing } from '@dxos/schema/testing';
|
|
18
|
-
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
19
17
|
|
|
20
|
-
import { DynamicTable } from './DynamicTable';
|
|
21
18
|
import { type TableFeatures } from '../../model';
|
|
22
19
|
import { translations } from '../../translations';
|
|
23
20
|
|
|
21
|
+
import { DynamicTable } from './DynamicTable';
|
|
22
|
+
|
|
24
23
|
faker.seed(0);
|
|
25
24
|
|
|
26
25
|
const useTestPropertiesAndObjects = () => {
|
|
@@ -56,15 +55,20 @@ const DynamicTableStory = () => {
|
|
|
56
55
|
// Story definitions.
|
|
57
56
|
//
|
|
58
57
|
|
|
59
|
-
const meta
|
|
58
|
+
const meta = {
|
|
60
59
|
title: 'ui/react-ui-table/DynamicTable',
|
|
61
60
|
component: DynamicTable,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
decorators: [withTheme],
|
|
62
|
+
parameters: {
|
|
63
|
+
layout: 'fullscreen',
|
|
64
|
+
translations,
|
|
65
|
+
},
|
|
66
|
+
} satisfies Meta<typeof DynamicTable>;
|
|
65
67
|
|
|
66
68
|
export default meta;
|
|
67
69
|
|
|
70
|
+
type Story = StoryObj<typeof meta>;
|
|
71
|
+
|
|
68
72
|
export const Default: StoryObj = {
|
|
69
73
|
render: DynamicTableStory,
|
|
70
74
|
};
|
|
@@ -141,7 +145,7 @@ export const WithEchoSchema: StoryObj = {
|
|
|
141
145
|
types: [Testing.Contact],
|
|
142
146
|
createIdentity: true,
|
|
143
147
|
createSpace: true,
|
|
144
|
-
|
|
148
|
+
onCreateSpace: async ({ space }) => {
|
|
145
149
|
Array.from({ length: 10 }).forEach(() => {
|
|
146
150
|
space.db.add(
|
|
147
151
|
Obj.make(Testing.Contact, {
|
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import React, {
|
|
5
|
+
import type * as Schema from 'effect/Schema';
|
|
6
|
+
import React, { useCallback, useMemo, useRef } from 'react';
|
|
7
7
|
|
|
8
|
-
import { type JsonSchemaType } from '@dxos/echo
|
|
8
|
+
import { type JsonSchemaType } from '@dxos/echo/internal';
|
|
9
9
|
import { type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
|
|
10
10
|
import { mx } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
|
-
import { Table, type TableController } from './Table';
|
|
13
12
|
import { useTableModel } from '../../hooks';
|
|
14
13
|
import { type TableFeatures, TablePresentation, type TableRowAction } from '../../model';
|
|
15
|
-
import { getBaseSchema, makeDynamicTable
|
|
14
|
+
import { type TablePropertyDefinition, getBaseSchema, makeDynamicTable } from '../../util';
|
|
15
|
+
|
|
16
|
+
import { Table, type TableController } from './Table';
|
|
16
17
|
|
|
17
18
|
type DynamicTableProps = ThemedClassName<{
|
|
18
19
|
name?: string; // TODO(burdon): Remove?
|
|
@@ -44,15 +45,12 @@ export const DynamicTable = ({
|
|
|
44
45
|
...props
|
|
45
46
|
}: DynamicTableProps) => {
|
|
46
47
|
// TODO(burdon): Remove variance from the props (should be normalized externally; possibly via hooks).
|
|
47
|
-
const {
|
|
48
|
+
const { jsonSchema } = useMemo(
|
|
48
49
|
() => getBaseSchema({ typename: name, properties, jsonSchema: _jsonSchema, schema }),
|
|
49
50
|
[name, properties, _jsonSchema, schema],
|
|
50
51
|
);
|
|
51
52
|
|
|
52
|
-
const { projection, view } = useMemo(
|
|
53
|
-
() => makeDynamicTable({ typename, jsonSchema, properties }),
|
|
54
|
-
[typename, jsonSchema, properties],
|
|
55
|
-
);
|
|
53
|
+
const { projection, view } = useMemo(() => makeDynamicTable({ jsonSchema, properties }), [jsonSchema, properties]);
|
|
56
54
|
|
|
57
55
|
const tableRef = useRef<TableController>(null);
|
|
58
56
|
const handleCellUpdate = useCallback((cell: any) => {
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import type * as Schema from 'effect/Schema';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
8
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
9
|
+
|
|
10
|
+
import { Obj, Type } from '@dxos/echo';
|
|
11
|
+
import { type JsonSchemaType } from '@dxos/echo/internal';
|
|
12
|
+
import { type DxGrid } from '@dxos/lit-grid';
|
|
13
|
+
import '@dxos/lit-ui/dx-tag-picker.pcss';
|
|
14
|
+
import { faker } from '@dxos/random';
|
|
15
|
+
import { useClient } from '@dxos/react-client';
|
|
16
|
+
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
17
|
+
import { useAsyncEffect } from '@dxos/react-ui';
|
|
18
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
19
|
+
import { translations as formTranslations } from '@dxos/react-ui-form';
|
|
20
|
+
import { DataType } from '@dxos/schema';
|
|
21
|
+
import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
|
|
22
|
+
|
|
23
|
+
import { useTableModel } from '../../hooks';
|
|
24
|
+
import { type TableFeatures, TablePresentation, type TableRow } from '../../model';
|
|
25
|
+
import { translations } from '../../translations';
|
|
26
|
+
import { Table } from '../../types';
|
|
27
|
+
|
|
28
|
+
import { Table as TableComponent } from './Table';
|
|
29
|
+
|
|
30
|
+
faker.seed(1);
|
|
31
|
+
const generator: ValueGenerator = faker as any;
|
|
32
|
+
|
|
33
|
+
// TODO(burdon): Many-to-many relations.
|
|
34
|
+
// TODO(burdon): Mutable and immutable views.
|
|
35
|
+
// TODO(burdon): Reconcile schemas types and utils (see API PR).
|
|
36
|
+
// TODO(burdon): Base type for T (with id); see ECHO API PR?
|
|
37
|
+
const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
|
|
38
|
+
const client = useClient();
|
|
39
|
+
const { space } = useClientProvider();
|
|
40
|
+
const [view, setView] = useState<DataType.View>();
|
|
41
|
+
const [jsonSchema, setJsonSchema] = useState<JsonSchemaType>();
|
|
42
|
+
|
|
43
|
+
const features = useMemo<TableFeatures>(
|
|
44
|
+
() => ({ schemaEditable: false, dataEditable: true, selection: { enabled: false } }),
|
|
45
|
+
[],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
useAsyncEffect(async () => {
|
|
49
|
+
if (!space) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const {
|
|
54
|
+
jsonSchema,
|
|
55
|
+
schema: effectSchema,
|
|
56
|
+
view,
|
|
57
|
+
} = await Table.makeView({ client, space, typename: Type.getTypename(schema) });
|
|
58
|
+
setJsonSchema(jsonSchema);
|
|
59
|
+
setView(view);
|
|
60
|
+
space.db.add(view);
|
|
61
|
+
await space.db.schemaRegistry.register([effectSchema]);
|
|
62
|
+
}, [client, space, schema]);
|
|
63
|
+
|
|
64
|
+
const model = useTableModel<TableRow>({ view, schema: jsonSchema, rows: [], features });
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (!model || !space) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const objectGenerator = createAsyncGenerator(generator, schema, { db: space?.db, force: true });
|
|
72
|
+
void objectGenerator.createObjects(count).then((objects) => {
|
|
73
|
+
model.setRows(objects);
|
|
74
|
+
});
|
|
75
|
+
}, [model, space]);
|
|
76
|
+
|
|
77
|
+
const presentation = useMemo(() => {
|
|
78
|
+
if (!model) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return new TablePresentation(model);
|
|
83
|
+
}, [model]);
|
|
84
|
+
|
|
85
|
+
return { model, presentation };
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const DefaultStory = () => {
|
|
89
|
+
const client = useClient();
|
|
90
|
+
const { model: orgModel, presentation: orgPresentation } = useTestModel(DataType.Organization, 50);
|
|
91
|
+
const { model: contactModel, presentation: contactPresentation } = useTestModel(DataType.Person, 50);
|
|
92
|
+
const { space } = useClientProvider();
|
|
93
|
+
|
|
94
|
+
const handleCreate = useCallback(
|
|
95
|
+
(schema: Schema.Schema.AnyNoContext, values: any) => {
|
|
96
|
+
return client.spaces.default.db.add(Obj.make(schema, values));
|
|
97
|
+
},
|
|
98
|
+
[space],
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div className='is-full bs-full grid grid-cols-2 divide-x divide-separator'>
|
|
103
|
+
<TableComponent.Root>
|
|
104
|
+
<TableComponent.Main
|
|
105
|
+
model={orgModel}
|
|
106
|
+
schema={DataType.Organization}
|
|
107
|
+
presentation={orgPresentation}
|
|
108
|
+
onCreate={handleCreate}
|
|
109
|
+
client={client}
|
|
110
|
+
ignoreAttention
|
|
111
|
+
testId='relations-0'
|
|
112
|
+
/>
|
|
113
|
+
</TableComponent.Root>
|
|
114
|
+
<TableComponent.Root>
|
|
115
|
+
<TableComponent.Main
|
|
116
|
+
model={contactModel}
|
|
117
|
+
schema={DataType.Person}
|
|
118
|
+
presentation={contactPresentation}
|
|
119
|
+
onCreate={handleCreate}
|
|
120
|
+
client={client}
|
|
121
|
+
ignoreAttention
|
|
122
|
+
testId='relations-1'
|
|
123
|
+
/>
|
|
124
|
+
</TableComponent.Root>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const meta = {
|
|
130
|
+
title: 'ui/react-ui-table/Relations',
|
|
131
|
+
render: DefaultStory,
|
|
132
|
+
decorators: [
|
|
133
|
+
withTheme,
|
|
134
|
+
withClientProvider({
|
|
135
|
+
types: [DataType.View, DataType.Organization, DataType.Person, Table.Table],
|
|
136
|
+
createIdentity: true,
|
|
137
|
+
createSpace: true,
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
parameters: {
|
|
141
|
+
layout: 'fullscreen',
|
|
142
|
+
controls: { disable: true },
|
|
143
|
+
translations: [...translations, ...formTranslations],
|
|
144
|
+
},
|
|
145
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
146
|
+
|
|
147
|
+
export default meta;
|
|
148
|
+
|
|
149
|
+
type Story = StoryObj<typeof meta>;
|
|
150
|
+
|
|
151
|
+
export const Default: Story = {
|
|
152
|
+
// TODO(wittjosiah): This test is flaky, especially in CI.
|
|
153
|
+
// Most typical failure is `targetCell` returns `null`.
|
|
154
|
+
_play: async ({ canvasElement }: any) => {
|
|
155
|
+
const canvas = within(canvasElement);
|
|
156
|
+
const body = within(document.body);
|
|
157
|
+
|
|
158
|
+
// Get all dx-grid elements (should have 2 - one for each table)
|
|
159
|
+
const firstGrid = await canvas.findByTestId('relations-0', undefined, { timeout: 30_000 });
|
|
160
|
+
const secondGrid = await canvas.findByTestId('relations-1', undefined, { timeout: 30_000 });
|
|
161
|
+
|
|
162
|
+
// Focus on the second table (Person/contacts table)
|
|
163
|
+
await expect(secondGrid).toBeVisible();
|
|
164
|
+
|
|
165
|
+
// Scroll to the relations column (column 4) - this mimics the scrollToColumn call
|
|
166
|
+
(secondGrid.closest('dx-grid') as DxGrid).scrollToColumn(4);
|
|
167
|
+
|
|
168
|
+
// Wait for scroll to complete
|
|
169
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
170
|
+
|
|
171
|
+
// Find and click the target cell (first row, relations column)
|
|
172
|
+
const targetCell = secondGrid.querySelector('[data-dx-grid-plane="grid"] [aria-rowindex="0"][aria-colindex="4"]');
|
|
173
|
+
await expect(targetCell).toBeVisible();
|
|
174
|
+
|
|
175
|
+
// Click to focus the cell
|
|
176
|
+
await userEvent.click(targetCell as HTMLElement);
|
|
177
|
+
await expect(targetCell).toHaveFocus();
|
|
178
|
+
await userEvent.keyboard('{Enter}');
|
|
179
|
+
|
|
180
|
+
// Look for the combobox that should appear in edit mode
|
|
181
|
+
const combobox = await body.findByRole('combobox', undefined, { timeout: 5000 });
|
|
182
|
+
await userEvent.click(combobox);
|
|
183
|
+
|
|
184
|
+
const searchField = await body.findByPlaceholderText('Search…');
|
|
185
|
+
await userEvent.click(searchField);
|
|
186
|
+
|
|
187
|
+
// Get the first organization name from the first table to search for
|
|
188
|
+
const orgCell = firstGrid.querySelector(
|
|
189
|
+
'[data-dx-grid-plane="grid"] [aria-rowindex="0"][aria-colindex="0"] .dx-grid__cell__content',
|
|
190
|
+
) as HTMLElement;
|
|
191
|
+
|
|
192
|
+
const orgName = orgCell.textContent;
|
|
193
|
+
// Type the first 4 characters to search
|
|
194
|
+
await userEvent.type(searchField, orgName.substring(0, 4));
|
|
195
|
+
|
|
196
|
+
// Look for an option to select
|
|
197
|
+
const option = await body.findAllByRole('option');
|
|
198
|
+
await expect(option[0]).toBeVisible();
|
|
199
|
+
|
|
200
|
+
// Press Enter to select
|
|
201
|
+
await userEvent.keyboard('{Enter}');
|
|
202
|
+
|
|
203
|
+
// Look for and click save button
|
|
204
|
+
const saveButton = await body.findByTestId('save-button');
|
|
205
|
+
await userEvent.click(saveButton);
|
|
206
|
+
|
|
207
|
+
// Verify the relation was set (cell should now contain the org name)
|
|
208
|
+
await expect(targetCell).toHaveTextContent(orgName.substring(0, 4));
|
|
209
|
+
|
|
210
|
+
// Test object creation (new relations) - equivalent to "new relations work as expected" test
|
|
211
|
+
// Find a different cell to test object creation (second row, relations column)
|
|
212
|
+
const newTargetCell = secondGrid.querySelector(
|
|
213
|
+
'[data-dx-grid-plane="grid"] [aria-rowindex="1"][aria-colindex="4"]',
|
|
214
|
+
);
|
|
215
|
+
await expect(newTargetCell).toBeTruthy();
|
|
216
|
+
|
|
217
|
+
// Click to focus the cell
|
|
218
|
+
await userEvent.click(newTargetCell as Element);
|
|
219
|
+
|
|
220
|
+
await userEvent.keyboard('{Enter}');
|
|
221
|
+
|
|
222
|
+
// Look for the combobox that should appear in edit mode
|
|
223
|
+
const newCombobox = await body.findByRole('combobox');
|
|
224
|
+
await userEvent.click(newCombobox);
|
|
225
|
+
|
|
226
|
+
const newSearchField = await body.findByPlaceholderText('Search…');
|
|
227
|
+
await userEvent.click(newSearchField);
|
|
228
|
+
|
|
229
|
+
// Type a new object name (this will create a new object)
|
|
230
|
+
const newOrgName = 'Salieri LLC';
|
|
231
|
+
await userEvent.type(newSearchField, newOrgName);
|
|
232
|
+
|
|
233
|
+
// Look for an option to select (should be the create new option)
|
|
234
|
+
const newOption = await body.findAllByRole('option');
|
|
235
|
+
await expect(newOption[0]).toBeVisible();
|
|
236
|
+
|
|
237
|
+
// Press Enter to select/create
|
|
238
|
+
await userEvent.keyboard('{Enter}');
|
|
239
|
+
|
|
240
|
+
// Look for and click save button
|
|
241
|
+
const createReferencedObjectForm = await body.findByTestId('create-referenced-object-form');
|
|
242
|
+
const saveObjectButton = await within(createReferencedObjectForm).findByTestId('save-button');
|
|
243
|
+
await userEvent.click(saveObjectButton);
|
|
244
|
+
|
|
245
|
+
// Verify the new object was created and relation was set
|
|
246
|
+
await expect(newTargetCell).toHaveTextContent(newOrgName);
|
|
247
|
+
},
|
|
248
|
+
} as any;
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { DropdownMenu, useTranslation } from '@dxos/react-ui';
|
|
7
|
+
import { DropdownMenu, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
8
8
|
|
|
9
|
-
import { type
|
|
9
|
+
import { type ModalController, type TableModel } from '../../model';
|
|
10
10
|
import { translationKey } from '../../translations';
|
|
11
11
|
|
|
12
12
|
type RowActionsMenuProps = { model: TableModel; modals: ModalController };
|
|
@@ -38,7 +38,7 @@ export const RowActionsMenu = ({ model, modals }: RowActionsMenuProps) => {
|
|
|
38
38
|
model.handleRowAction(action.id, state.rowIndex);
|
|
39
39
|
}}
|
|
40
40
|
>
|
|
41
|
-
{
|
|
41
|
+
{toLocalizedString(action.label, t)}
|
|
42
42
|
</DropdownMenu.Item>
|
|
43
43
|
))}
|
|
44
44
|
</DropdownMenu.Viewport>
|