@dxos/react-ui-table 0.8.4-main.406dc2a → 0.8.4-main.52d7546f51
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-GTGYBRJA.mjs +1748 -0
- package/dist/lib/browser/chunk-GTGYBRJA.mjs.map +7 -0
- package/dist/lib/browser/chunk-OZBLY7XM.mjs +76 -0
- package/dist/lib/browser/chunk-OZBLY7XM.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1131 -999
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +30 -42
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/types/index.mjs +3 -3
- package/dist/lib/node-esm/chunk-DPNSZHU5.mjs +1750 -0
- package/dist/lib/node-esm/chunk-DPNSZHU5.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-WNZSKIRF.mjs +77 -0
- package/dist/lib/node-esm/chunk-WNZSKIRF.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1131 -999
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +30 -42
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/types/index.mjs +3 -3
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -2
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts +2 -2
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +4 -18
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +12 -9
- package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +8 -8
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +71 -5
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +10 -12
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -7
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +4 -4
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +4 -4
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +22 -15
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts +5 -6
- package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
- package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
- package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
- package/dist/types/src/hooks/useTableModel.d.ts +9 -9
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/modal-controller.d.ts +5 -1
- package/dist/types/src/model/modal-controller.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts +17 -8
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +104 -25
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +3 -1
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/playwright/TableManager.d.ts +2 -1
- package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
- package/dist/types/src/testing/useTestTableModel.d.ts +18 -15
- package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +4 -4
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Table.d.ts +31 -0
- package/dist/types/src/types/Table.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +14 -11
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
- package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +2 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/query-ast.d.ts +7 -0
- package/dist/types/src/util/query-ast.d.ts.map +1 -0
- package/dist/types/src/util/sort.d.ts +12 -0
- package/dist/types/src/util/sort.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +53 -53
- package/src/components/Table/ColumnActionsMenu.tsx +10 -6
- package/src/components/Table/ColumnSettings.tsx +6 -6
- package/src/components/Table/DynamicTable.stories.tsx +15 -15
- package/src/components/Table/DynamicTable.tsx +24 -16
- package/src/components/Table/Relations.stories.tsx +43 -54
- package/src/components/Table/RowActionsMenu.tsx +24 -15
- package/src/components/Table/Table.stories.tsx +89 -80
- package/src/components/Table/Table.tsx +335 -305
- package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
- package/src/components/TableCellEditor/FormCellEditor.tsx +110 -133
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +17 -13
- package/src/components/TableCellEditor/TableCellEditor.tsx +31 -31
- package/src/components/TableToolbar/TableToolbar.tsx +47 -31
- package/src/components/testing.ts +38 -12
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useAddRow.ts +8 -10
- package/src/hooks/useProjectionModel.ts +39 -0
- package/src/hooks/useTableModel.ts +36 -34
- package/src/model/modal-controller.ts +23 -12
- package/src/model/selection-model.ts +75 -44
- package/src/model/table-model.test.ts +82 -54
- package/src/model/table-model.ts +435 -170
- package/src/model/table-presentation.test.ts +59 -49
- package/src/model/table-presentation.ts +32 -27
- package/src/playwright/TableManager.ts +13 -6
- package/src/playwright/playwright.config.ts +1 -1
- package/src/playwright/smoke.spec.ts +56 -10
- package/src/testing/useTestTableModel.ts +45 -38
- package/src/translations.ts +3 -3
- package/src/types/Table.ts +90 -0
- package/src/types/index.ts +1 -1
- package/src/util/dynamic-table.test.ts +70 -0
- package/src/util/dynamic-table.ts +40 -28
- package/src/util/index.ts +2 -0
- package/src/util/query-ast.ts +19 -0
- package/src/util/sort.ts +90 -0
- package/dist/lib/browser/chunk-4K7JPALT.mjs +0 -66
- package/dist/lib/browser/chunk-4K7JPALT.mjs.map +0 -7
- package/dist/lib/browser/chunk-OZTXLZGM.mjs +0 -1804
- package/dist/lib/browser/chunk-OZTXLZGM.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-MK6OVUF6.mjs +0 -67
- package/dist/lib/node-esm/chunk-MK6OVUF6.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-S56Z4V4X.mjs +0 -1805
- package/dist/lib/node-esm/chunk-S56Z4V4X.mjs.map +0 -7
- package/dist/types/src/model/table-sorting.d.ts +0 -52
- package/dist/types/src/model/table-sorting.d.ts.map +0 -1
- package/dist/types/src/types/schema.d.ts +0 -28
- package/dist/types/src/types/schema.d.ts.map +0 -1
- package/src/model/table-sorting.ts +0 -225
- package/src/types/schema.ts +0 -73
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-table",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.52d7546f51",
|
|
4
4
|
"description": "A table component.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
|
-
"sideEffects":
|
|
13
|
+
"sideEffects": false,
|
|
10
14
|
"type": "module",
|
|
11
15
|
"exports": {
|
|
12
16
|
"./deprecated": {
|
|
@@ -56,70 +60,66 @@
|
|
|
56
60
|
"@codemirror/autocomplete": "^6.19.0",
|
|
57
61
|
"@codemirror/state": "^6.5.2",
|
|
58
62
|
"@codemirror/view": "^6.38.4",
|
|
59
|
-
"@
|
|
60
|
-
"@
|
|
61
|
-
"@preact/signals-core": "^1.12.1",
|
|
63
|
+
"@effect-atom/atom-react": "^0.5.0",
|
|
64
|
+
"@fluentui/react-tabster": "9.26.11",
|
|
62
65
|
"@radix-ui/react-context": "1.1.1",
|
|
63
66
|
"@radix-ui/react-primitive": "2.0.2",
|
|
64
67
|
"@radix-ui/react-slot": "1.1.2",
|
|
65
68
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
66
69
|
"date-fns": "^3.3.1",
|
|
67
70
|
"lodash.orderby": "^4.6.0",
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/debug": "0.8.4-main.
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/echo-
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/lit-grid": "0.8.4-main.
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/react-ui-
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/react-ui-
|
|
83
|
-
"@dxos/react-ui-
|
|
84
|
-
"@dxos/react-ui-form": "0.8.4-main.
|
|
85
|
-
"@dxos/react-ui-
|
|
86
|
-
"@dxos/react-ui-
|
|
87
|
-
"@dxos/react-ui-
|
|
88
|
-
"@dxos/react-ui-
|
|
89
|
-
"@dxos/
|
|
90
|
-
"@dxos/
|
|
91
|
-
"@dxos/
|
|
92
|
-
"@dxos/
|
|
93
|
-
"@dxos/util": "0.8.4-main.406dc2a"
|
|
71
|
+
"@dxos/context": "0.8.4-main.52d7546f51",
|
|
72
|
+
"@dxos/debug": "0.8.4-main.52d7546f51",
|
|
73
|
+
"@dxos/echo": "0.8.4-main.52d7546f51",
|
|
74
|
+
"@dxos/effect": "0.8.4-main.52d7546f51",
|
|
75
|
+
"@dxos/async": "0.8.4-main.52d7546f51",
|
|
76
|
+
"@dxos/echo-atom": "0.8.4-main.52d7546f51",
|
|
77
|
+
"@dxos/invariant": "0.8.4-main.52d7546f51",
|
|
78
|
+
"@dxos/keys": "0.8.4-main.52d7546f51",
|
|
79
|
+
"@dxos/lit-grid": "0.8.4-main.52d7546f51",
|
|
80
|
+
"@dxos/random": "0.8.4-main.52d7546f51",
|
|
81
|
+
"@dxos/log": "0.8.4-main.52d7546f51",
|
|
82
|
+
"@dxos/react-client": "0.8.4-main.52d7546f51",
|
|
83
|
+
"@dxos/react-ui-components": "0.8.4-main.52d7546f51",
|
|
84
|
+
"@dxos/react-ui-editor": "0.8.4-main.52d7546f51",
|
|
85
|
+
"@dxos/react-ui-grid": "0.8.4-main.52d7546f51",
|
|
86
|
+
"@dxos/react-ui-menu": "0.8.4-main.52d7546f51",
|
|
87
|
+
"@dxos/react-ui-form": "0.8.4-main.52d7546f51",
|
|
88
|
+
"@dxos/react-ui-attention": "0.8.4-main.52d7546f51",
|
|
89
|
+
"@dxos/react-ui-searchlist": "0.8.4-main.52d7546f51",
|
|
90
|
+
"@dxos/react-ui-stack": "0.8.4-main.52d7546f51",
|
|
91
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.52d7546f51",
|
|
92
|
+
"@dxos/schema": "0.8.4-main.52d7546f51",
|
|
93
|
+
"@dxos/types": "0.8.4-main.52d7546f51",
|
|
94
|
+
"@dxos/util": "0.8.4-main.52d7546f51",
|
|
95
|
+
"@dxos/ui-types": "0.8.4-main.52d7546f51"
|
|
94
96
|
},
|
|
95
97
|
"devDependencies": {
|
|
96
|
-
"@effect
|
|
97
|
-
"@effect/platform": "0.92.1",
|
|
98
|
+
"@effect/platform": "0.94.4",
|
|
98
99
|
"@types/lodash.orderby": "^4.6.9",
|
|
99
|
-
"@types/react": "~19.2.
|
|
100
|
-
"@types/react-dom": "~19.2.
|
|
101
|
-
"effect": "3.
|
|
100
|
+
"@types/react": "~19.2.7",
|
|
101
|
+
"@types/react-dom": "~19.2.3",
|
|
102
|
+
"effect": "3.19.16",
|
|
102
103
|
"fast-check": "^3.19.0",
|
|
103
|
-
"react": "~19.2.
|
|
104
|
-
"react-dom": "~19.2.
|
|
104
|
+
"react": "~19.2.3",
|
|
105
|
+
"react-dom": "~19.2.3",
|
|
105
106
|
"vite": "7.1.9",
|
|
106
|
-
"@dxos/
|
|
107
|
-
"@dxos/
|
|
108
|
-
"@dxos/react-
|
|
109
|
-
"@dxos/
|
|
110
|
-
"@dxos/
|
|
111
|
-
"@dxos/
|
|
112
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
113
|
-
"@dxos/test-utils": "0.8.4-main.406dc2a"
|
|
107
|
+
"@dxos/lit-ui": "0.8.4-main.52d7546f51",
|
|
108
|
+
"@dxos/react-ui": "0.8.4-main.52d7546f51",
|
|
109
|
+
"@dxos/react-client": "0.8.4-main.52d7546f51",
|
|
110
|
+
"@dxos/random": "0.8.4-main.52d7546f51",
|
|
111
|
+
"@dxos/test-utils": "0.8.4-main.52d7546f51",
|
|
112
|
+
"@dxos/ui-theme": "0.8.4-main.52d7546f51",
|
|
113
|
+
"@dxos/storybook-utils": "0.8.4-main.52d7546f51"
|
|
114
114
|
},
|
|
115
115
|
"peerDependencies": {
|
|
116
|
-
"@effect-
|
|
117
|
-
"@effect/platform": "
|
|
118
|
-
"effect": "
|
|
119
|
-
"react": "
|
|
120
|
-
"react-dom": "
|
|
121
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
122
|
-
"@dxos/
|
|
116
|
+
"@effect-atom/atom-react": "^0.5.0",
|
|
117
|
+
"@effect/platform": "0.94.4",
|
|
118
|
+
"effect": "3.19.16",
|
|
119
|
+
"react": "~19.2.3",
|
|
120
|
+
"react-dom": "~19.2.3",
|
|
121
|
+
"@dxos/react-ui": "0.8.4-main.52d7546f51",
|
|
122
|
+
"@dxos/ui-theme": "0.8.4-main.52d7546f51"
|
|
123
123
|
},
|
|
124
124
|
"publishConfig": {
|
|
125
125
|
"access": "public"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
5
6
|
import React from 'react';
|
|
6
7
|
|
|
7
8
|
import { DropdownMenu, useTranslation } from '@dxos/react-ui';
|
|
@@ -9,16 +10,19 @@ import { DropdownMenu, useTranslation } from '@dxos/react-ui';
|
|
|
9
10
|
import { type ModalController, type TableModel } from '../../model';
|
|
10
11
|
import { translationKey } from '../../translations';
|
|
11
12
|
|
|
12
|
-
type ColumnActionsMenuProps = {
|
|
13
|
+
export type ColumnActionsMenuProps = {
|
|
14
|
+
model: TableModel;
|
|
15
|
+
modals: ModalController;
|
|
16
|
+
};
|
|
13
17
|
|
|
14
18
|
export const ColumnActionsMenu = ({ model, modals }: ColumnActionsMenuProps) => {
|
|
15
19
|
const { t } = useTranslation(translationKey);
|
|
16
|
-
const state = modals.state
|
|
20
|
+
const state = useAtomValue(modals.state);
|
|
17
21
|
if (state?.type !== 'column') {
|
|
18
22
|
return null;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
const currentSort = model.
|
|
25
|
+
const currentSort = model.getSorting();
|
|
22
26
|
const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
|
|
23
27
|
|
|
24
28
|
return (
|
|
@@ -30,7 +34,7 @@ export const ColumnActionsMenu = ({ model, modals }: ColumnActionsMenuProps) =>
|
|
|
30
34
|
{(!isCurrentColumnSorted || currentSort?.direction === 'asc') && (
|
|
31
35
|
<DropdownMenu.Item
|
|
32
36
|
data-testid='column-sort-descending'
|
|
33
|
-
onClick={() => model.
|
|
37
|
+
onClick={() => model.setSort(state.fieldId, 'desc')}
|
|
34
38
|
>
|
|
35
39
|
{t('column action sort descending')}
|
|
36
40
|
</DropdownMenu.Item>
|
|
@@ -38,13 +42,13 @@ export const ColumnActionsMenu = ({ model, modals }: ColumnActionsMenuProps) =>
|
|
|
38
42
|
{(!isCurrentColumnSorted || currentSort?.direction === 'desc') && (
|
|
39
43
|
<DropdownMenu.Item
|
|
40
44
|
data-testid='column-sort-ascending'
|
|
41
|
-
onClick={() => model.
|
|
45
|
+
onClick={() => model.setSort(state.fieldId, 'asc')}
|
|
42
46
|
>
|
|
43
47
|
{t('column action sort ascending')}
|
|
44
48
|
</DropdownMenu.Item>
|
|
45
49
|
)}
|
|
46
50
|
{isCurrentColumnSorted && (
|
|
47
|
-
<DropdownMenu.Item data-testid='column-clear-sort' onClick={() => model.
|
|
51
|
+
<DropdownMenu.Item data-testid='column-clear-sort' onClick={() => model.clearSort()}>
|
|
48
52
|
{t('column action clear sorting')}
|
|
49
53
|
</DropdownMenu.Item>
|
|
50
54
|
)}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
5
6
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
import { type SchemaRegistry } from '@dxos/echo-db';
|
|
8
|
+
import { type SchemaRegistry } from '@dxos/echo';
|
|
9
9
|
import { Popover } from '@dxos/react-ui';
|
|
10
10
|
import { FieldEditor } from '@dxos/react-ui-form';
|
|
11
11
|
import { type FieldType } from '@dxos/schema';
|
|
@@ -13,7 +13,7 @@ import { type FieldType } from '@dxos/schema';
|
|
|
13
13
|
import { type ModalController, type TableModel } from '../../model';
|
|
14
14
|
|
|
15
15
|
type ColumnSettingsProps = {
|
|
16
|
-
registry?: SchemaRegistry;
|
|
16
|
+
registry?: SchemaRegistry.SchemaRegistry;
|
|
17
17
|
model?: TableModel;
|
|
18
18
|
modals: ModalController;
|
|
19
19
|
onNewColumn: () => void;
|
|
@@ -21,7 +21,7 @@ type ColumnSettingsProps = {
|
|
|
21
21
|
|
|
22
22
|
export const ColumnSettings = ({ registry, model, modals, onNewColumn }: ColumnSettingsProps) => {
|
|
23
23
|
const [newField, setNewField] = useState<FieldType>();
|
|
24
|
-
const state = modals.state
|
|
24
|
+
const state = useAtomValue(modals.state);
|
|
25
25
|
|
|
26
26
|
useEffect(() => {
|
|
27
27
|
if (state?.type === 'columnSettings' && state.mode.type === 'create' && model?.projection) {
|
|
@@ -38,11 +38,11 @@ export const ColumnSettings = ({ registry, model, modals, onNewColumn }: ColumnS
|
|
|
38
38
|
if (state?.type === 'columnSettings') {
|
|
39
39
|
const { mode } = state;
|
|
40
40
|
if (mode.type === 'edit') {
|
|
41
|
-
return model?.projection?.
|
|
41
|
+
return model?.projection?.getFields().find((f) => f.id === mode.fieldId);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
return undefined;
|
|
45
|
-
}, [model?.projection
|
|
45
|
+
}, [model?.projection, state]);
|
|
46
46
|
|
|
47
47
|
const field = existingField ?? newField;
|
|
48
48
|
|
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import type * as Types from 'effect/Types';
|
|
6
7
|
import React, { useMemo, useState } from 'react';
|
|
7
8
|
|
|
8
|
-
import { Obj } from '@dxos/echo';
|
|
9
|
-
import {
|
|
9
|
+
import { type JsonSchema, Obj } from '@dxos/echo';
|
|
10
|
+
import { Format } from '@dxos/echo/internal';
|
|
10
11
|
import { faker } from '@dxos/random';
|
|
11
|
-
import { useClient } from '@dxos/react-client';
|
|
12
12
|
import { Filter, useQuery, useSchema } from '@dxos/react-client/echo';
|
|
13
|
-
import {
|
|
13
|
+
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
14
14
|
import { withTheme } from '@dxos/react-ui/testing';
|
|
15
15
|
import { type SchemaPropertyDefinition } from '@dxos/schema';
|
|
16
|
-
import {
|
|
16
|
+
import { TestSchema } from '@dxos/schema/testing';
|
|
17
|
+
import { withRegistry } from '@dxos/storybook-utils';
|
|
17
18
|
|
|
18
19
|
import { type TableFeatures } from '../../model';
|
|
19
20
|
import { translations } from '../../translations';
|
|
@@ -25,8 +26,8 @@ faker.seed(0);
|
|
|
25
26
|
const useTestPropertiesAndObjects = () => {
|
|
26
27
|
const properties = useMemo<SchemaPropertyDefinition[]>(
|
|
27
28
|
() => [
|
|
28
|
-
{ name: 'name', format:
|
|
29
|
-
{ name: 'age', format:
|
|
29
|
+
{ name: 'name', format: Format.TypeFormat.String },
|
|
30
|
+
{ name: 'age', format: Format.TypeFormat.Number },
|
|
30
31
|
],
|
|
31
32
|
[],
|
|
32
33
|
);
|
|
@@ -58,7 +59,7 @@ const DynamicTableStory = () => {
|
|
|
58
59
|
const meta = {
|
|
59
60
|
title: 'ui/react-ui-table/DynamicTable',
|
|
60
61
|
component: DynamicTable,
|
|
61
|
-
decorators: [withTheme],
|
|
62
|
+
decorators: [withTheme(), withRegistry],
|
|
62
63
|
parameters: {
|
|
63
64
|
layout: 'fullscreen',
|
|
64
65
|
translations,
|
|
@@ -101,7 +102,7 @@ export const WithClickToSelect: StoryObj = {
|
|
|
101
102
|
|
|
102
103
|
export const WithJsonSchema: StoryObj = {
|
|
103
104
|
render: () => {
|
|
104
|
-
const schema = useMemo<
|
|
105
|
+
const schema = useMemo<Types.DeepMutable<JsonSchema.JsonSchema>>(
|
|
105
106
|
() => ({
|
|
106
107
|
type: 'object',
|
|
107
108
|
properties: {
|
|
@@ -130,10 +131,9 @@ export const WithJsonSchema: StoryObj = {
|
|
|
130
131
|
|
|
131
132
|
export const WithEchoSchema: StoryObj = {
|
|
132
133
|
render: () => {
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
const objects = useQuery(space, schema ? Filter.type(schema) : Filter.nothing());
|
|
134
|
+
const { space } = useClientStory();
|
|
135
|
+
const schema = useSchema(space?.db, TestSchema.Person.typename);
|
|
136
|
+
const objects = useQuery(space?.db, schema ? Filter.type(schema) : Filter.nothing());
|
|
137
137
|
if (!schema) {
|
|
138
138
|
return <div>Loading schema...</div>;
|
|
139
139
|
}
|
|
@@ -142,13 +142,13 @@ export const WithEchoSchema: StoryObj = {
|
|
|
142
142
|
},
|
|
143
143
|
decorators: [
|
|
144
144
|
withClientProvider({
|
|
145
|
-
types: [
|
|
145
|
+
types: [TestSchema.Person],
|
|
146
146
|
createIdentity: true,
|
|
147
147
|
createSpace: true,
|
|
148
148
|
onCreateSpace: async ({ space }) => {
|
|
149
149
|
Array.from({ length: 10 }).forEach(() => {
|
|
150
150
|
space.db.add(
|
|
151
|
-
Obj.make(
|
|
151
|
+
Obj.make(TestSchema.Person, {
|
|
152
152
|
name: faker.person.fullName(),
|
|
153
153
|
email: faker.internet.email(),
|
|
154
154
|
}),
|
|
@@ -2,25 +2,29 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import { RegistryContext } from '@effect-atom/atom-react';
|
|
6
|
+
import type * as Types from 'effect/Types';
|
|
7
|
+
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
8
|
|
|
8
|
-
import { type
|
|
9
|
+
import { type Type } from '@dxos/echo';
|
|
10
|
+
import { type JsonSchema } from '@dxos/echo';
|
|
9
11
|
import { type ThemedClassName, useDefaultValue } from '@dxos/react-ui';
|
|
10
|
-
import {
|
|
12
|
+
import { type ProjectionModel } from '@dxos/schema';
|
|
13
|
+
import { mx } from '@dxos/ui-theme';
|
|
11
14
|
|
|
12
15
|
import { useTableModel } from '../../hooks';
|
|
13
16
|
import { type TableFeatures, TablePresentation, type TableRowAction } from '../../model';
|
|
17
|
+
import { type Table as TableType } from '../../types';
|
|
14
18
|
import { type TablePropertyDefinition, getBaseSchema, makeDynamicTable } from '../../util';
|
|
15
19
|
|
|
16
20
|
import { Table, type TableController } from './Table';
|
|
17
21
|
|
|
18
|
-
type DynamicTableProps = ThemedClassName<{
|
|
22
|
+
export type DynamicTableProps<T extends Type.Entity.Any = Type.Entity.Any> = ThemedClassName<{
|
|
23
|
+
schema?: T;
|
|
19
24
|
name?: string; // TODO(burdon): Remove?
|
|
20
25
|
rows: any[];
|
|
21
26
|
properties?: TablePropertyDefinition[];
|
|
22
|
-
jsonSchema?:
|
|
23
|
-
schema?: Schema.Schema.AnyNoContext;
|
|
27
|
+
jsonSchema?: Types.DeepMutable<JsonSchema.JsonSchema>;
|
|
24
28
|
features?: Partial<TableFeatures>;
|
|
25
29
|
rowActions?: TableRowAction[];
|
|
26
30
|
onRowClick?: (row: any) => void;
|
|
@@ -32,25 +36,30 @@ type DynamicTableProps = ThemedClassName<{
|
|
|
32
36
|
*/
|
|
33
37
|
// TODO(burdon): Instead of creating component variants, create helpers/hooks that normalize the props.
|
|
34
38
|
// TODO(burdon): Warning: Cannot update a component (`DynamicTable`) while rendering a different component (`DynamicTable`).
|
|
35
|
-
export const DynamicTable = ({
|
|
39
|
+
export const DynamicTable = <T extends Type.Entity.Any = Type.Entity.Any>({
|
|
36
40
|
classNames,
|
|
41
|
+
schema,
|
|
37
42
|
name = 'example.com/dynamic-table', // Rmove default or make random; this will lead to type collisions.
|
|
38
43
|
rows,
|
|
39
44
|
properties,
|
|
40
45
|
jsonSchema: _jsonSchema,
|
|
41
|
-
schema,
|
|
42
46
|
rowActions,
|
|
43
47
|
onRowClick,
|
|
44
48
|
onRowAction,
|
|
45
49
|
...props
|
|
46
|
-
}: DynamicTableProps) => {
|
|
50
|
+
}: DynamicTableProps<T>) => {
|
|
51
|
+
const registry = useContext(RegistryContext);
|
|
52
|
+
const [dynamicTable, setDynamicTable] = useState<{ object: TableType.Table; projection: ProjectionModel }>();
|
|
53
|
+
|
|
47
54
|
// TODO(burdon): Remove variance from the props (should be normalized externally; possibly via hooks).
|
|
48
55
|
const { jsonSchema } = useMemo(
|
|
49
56
|
() => getBaseSchema({ typename: name, properties, jsonSchema: _jsonSchema, schema }),
|
|
50
57
|
[name, properties, _jsonSchema, schema],
|
|
51
58
|
);
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
setDynamicTable(makeDynamicTable({ registry, jsonSchema, properties }));
|
|
62
|
+
}, [registry, jsonSchema, properties]);
|
|
54
63
|
|
|
55
64
|
const tableRef = useRef<TableController>(null);
|
|
56
65
|
const handleCellUpdate = useCallback((cell: any) => {
|
|
@@ -72,9 +81,8 @@ export const DynamicTable = ({
|
|
|
72
81
|
|
|
73
82
|
const model = useTableModel({
|
|
74
83
|
rows,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
projection,
|
|
84
|
+
object: dynamicTable?.object,
|
|
85
|
+
projection: dynamicTable?.projection,
|
|
78
86
|
features,
|
|
79
87
|
rowActions,
|
|
80
88
|
onCellUpdate: handleCellUpdate,
|
|
@@ -84,9 +92,9 @@ export const DynamicTable = ({
|
|
|
84
92
|
|
|
85
93
|
const presentation = useMemo(() => {
|
|
86
94
|
if (model) {
|
|
87
|
-
return new TablePresentation(model);
|
|
95
|
+
return new TablePresentation(registry, model);
|
|
88
96
|
}
|
|
89
|
-
}, [model]);
|
|
97
|
+
}, [registry, model]);
|
|
90
98
|
|
|
91
99
|
// TODO(burdon): Do we need the outer divs?
|
|
92
100
|
return (
|
|
@@ -2,25 +2,26 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { RegistryContext } from '@effect-atom/atom-react';
|
|
5
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
-
import
|
|
7
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
7
|
+
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
8
8
|
import { expect, userEvent, within } from 'storybook/test';
|
|
9
9
|
|
|
10
10
|
import { Obj, Type } from '@dxos/echo';
|
|
11
|
-
import {
|
|
11
|
+
import { invariant } from '@dxos/invariant';
|
|
12
12
|
import { type DxGrid } from '@dxos/lit-grid';
|
|
13
13
|
import '@dxos/lit-ui/dx-tag-picker.pcss';
|
|
14
14
|
import { faker } from '@dxos/random';
|
|
15
|
-
import {
|
|
16
|
-
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
15
|
+
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
17
16
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
18
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
17
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
19
18
|
import { translations as formTranslations } from '@dxos/react-ui-form';
|
|
20
|
-
import {
|
|
19
|
+
import { View } from '@dxos/schema';
|
|
21
20
|
import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
|
|
21
|
+
import { withRegistry } from '@dxos/storybook-utils';
|
|
22
|
+
import { Organization, Person } from '@dxos/types';
|
|
22
23
|
|
|
23
|
-
import { useTableModel } from '../../hooks';
|
|
24
|
+
import { useProjectionModel, useTableModel } from '../../hooks';
|
|
24
25
|
import { type TableFeatures, TablePresentation, type TableRow } from '../../model';
|
|
25
26
|
import { translations } from '../../translations';
|
|
26
27
|
import { Table } from '../../types';
|
|
@@ -35,10 +36,9 @@ const generator: ValueGenerator = faker as any;
|
|
|
35
36
|
// TODO(burdon): Reconcile schemas types and utils (see API PR).
|
|
36
37
|
// TODO(burdon): Base type for T (with id); see ECHO API PR?
|
|
37
38
|
const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
|
|
38
|
-
const
|
|
39
|
-
const { space } =
|
|
40
|
-
const [
|
|
41
|
-
const [jsonSchema, setJsonSchema] = useState<JsonSchemaType>();
|
|
39
|
+
const registry = useContext(RegistryContext);
|
|
40
|
+
const { space } = useClientStory();
|
|
41
|
+
const [object, setObject] = useState<Table.Table>();
|
|
42
42
|
|
|
43
43
|
const features = useMemo<TableFeatures>(
|
|
44
44
|
() => ({ schemaEditable: false, dataEditable: true, selection: { enabled: false } }),
|
|
@@ -50,18 +50,14 @@ const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
|
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
const {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
setJsonSchema(jsonSchema);
|
|
59
|
-
setView(view);
|
|
60
|
-
space.db.add(view);
|
|
61
|
-
await space.db.schemaRegistry.register([effectSchema]);
|
|
62
|
-
}, [client, space, schema]);
|
|
53
|
+
const { view, jsonSchema } = await View.makeFromDatabase({ db: space.db, typename: Type.getTypename(schema) });
|
|
54
|
+
const object = Table.make({ view, jsonSchema });
|
|
55
|
+
setObject(object);
|
|
56
|
+
space.db.add(object);
|
|
57
|
+
}, [space, schema]);
|
|
63
58
|
|
|
64
|
-
const
|
|
59
|
+
const projection = useProjectionModel(schema, object, registry);
|
|
60
|
+
const model = useTableModel<TableRow>({ object, projection, db: space?.db, features });
|
|
65
61
|
|
|
66
62
|
useEffect(() => {
|
|
67
63
|
if (!model || !space) {
|
|
@@ -79,21 +75,22 @@ const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
|
|
|
79
75
|
return;
|
|
80
76
|
}
|
|
81
77
|
|
|
82
|
-
return new TablePresentation(model);
|
|
83
|
-
}, [model]);
|
|
78
|
+
return new TablePresentation(registry, model);
|
|
79
|
+
}, [registry, model]);
|
|
84
80
|
|
|
85
81
|
return { model, presentation };
|
|
86
82
|
};
|
|
87
83
|
|
|
88
84
|
const DefaultStory = () => {
|
|
89
|
-
const
|
|
90
|
-
const { model:
|
|
91
|
-
const {
|
|
92
|
-
const { space } = useClientProvider();
|
|
85
|
+
const { model: orgModel, presentation: orgPresentation } = useTestModel(Organization.Organization, 50);
|
|
86
|
+
const { model: contactModel, presentation: contactPresentation } = useTestModel(Person.Person, 50);
|
|
87
|
+
const { space } = useClientStory();
|
|
93
88
|
|
|
94
89
|
const handleCreate = useCallback(
|
|
95
|
-
(schema:
|
|
96
|
-
|
|
90
|
+
(schema: Type.Entity.Any, values: any) => {
|
|
91
|
+
invariant(Type.isObjectSchema(schema));
|
|
92
|
+
invariant(space);
|
|
93
|
+
return space.db.add(Obj.make(schema, values));
|
|
97
94
|
},
|
|
98
95
|
[space],
|
|
99
96
|
);
|
|
@@ -103,10 +100,9 @@ const DefaultStory = () => {
|
|
|
103
100
|
<TableComponent.Root>
|
|
104
101
|
<TableComponent.Main
|
|
105
102
|
model={orgModel}
|
|
106
|
-
schema={
|
|
103
|
+
schema={Organization.Organization}
|
|
107
104
|
presentation={orgPresentation}
|
|
108
105
|
onCreate={handleCreate}
|
|
109
|
-
client={client}
|
|
110
106
|
ignoreAttention
|
|
111
107
|
testId='relations-0'
|
|
112
108
|
/>
|
|
@@ -114,10 +110,9 @@ const DefaultStory = () => {
|
|
|
114
110
|
<TableComponent.Root>
|
|
115
111
|
<TableComponent.Main
|
|
116
112
|
model={contactModel}
|
|
117
|
-
schema={
|
|
113
|
+
schema={Person.Person}
|
|
118
114
|
presentation={contactPresentation}
|
|
119
115
|
onCreate={handleCreate}
|
|
120
|
-
client={client}
|
|
121
116
|
ignoreAttention
|
|
122
117
|
testId='relations-1'
|
|
123
118
|
/>
|
|
@@ -130,9 +125,12 @@ const meta = {
|
|
|
130
125
|
title: 'ui/react-ui-table/Relations',
|
|
131
126
|
render: DefaultStory,
|
|
132
127
|
decorators: [
|
|
133
|
-
withTheme,
|
|
128
|
+
withTheme(),
|
|
129
|
+
withRegistry,
|
|
130
|
+
// TODO(thure): Shouldn't `layout: 'fullscreen'` below make this unnecessary?
|
|
131
|
+
withLayout({ classNames: 'fixed inset-0' }),
|
|
134
132
|
withClientProvider({
|
|
135
|
-
types: [
|
|
133
|
+
types: [View.View, Organization.Organization, Person.Person, Table.Table],
|
|
136
134
|
createIdentity: true,
|
|
137
135
|
createSpace: true,
|
|
138
136
|
}),
|
|
@@ -149,9 +147,7 @@ export default meta;
|
|
|
149
147
|
type Story = StoryObj<typeof meta>;
|
|
150
148
|
|
|
151
149
|
export const Default: Story = {
|
|
152
|
-
|
|
153
|
-
// Most typical failure is `targetCell` returns `null`.
|
|
154
|
-
_play: async ({ canvasElement }: any) => {
|
|
150
|
+
play: async ({ canvasElement }: any) => {
|
|
155
151
|
const canvas = within(canvasElement);
|
|
156
152
|
const body = within(document.body);
|
|
157
153
|
|
|
@@ -165,11 +161,8 @@ export const Default: Story = {
|
|
|
165
161
|
// Scroll to the relations column (column 4) - this mimics the scrollToColumn call
|
|
166
162
|
(secondGrid.closest('dx-grid') as DxGrid).scrollToColumn(4);
|
|
167
163
|
|
|
168
|
-
// Wait for scroll to complete
|
|
169
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
170
|
-
|
|
171
164
|
// Find and click the target cell (first row, relations column)
|
|
172
|
-
const targetCell = secondGrid.
|
|
165
|
+
const targetCell = await within(secondGrid).findByTestId('grid.4.0', undefined, { timeout: 10_000 });
|
|
173
166
|
await expect(targetCell).toBeVisible();
|
|
174
167
|
|
|
175
168
|
// Click to focus the cell
|
|
@@ -185,11 +178,9 @@ export const Default: Story = {
|
|
|
185
178
|
await userEvent.click(searchField);
|
|
186
179
|
|
|
187
180
|
// Get the first organization name from the first table to search for
|
|
188
|
-
const orgCell = firstGrid.
|
|
189
|
-
'[data-dx-grid-plane="grid"] [aria-rowindex="0"][aria-colindex="0"] .dx-grid__cell__content',
|
|
190
|
-
) as HTMLElement;
|
|
181
|
+
const orgCell = await within(firstGrid).findByTestId('grid.0.0', undefined, { timeout: 10_000 });
|
|
191
182
|
|
|
192
|
-
const orgName = orgCell.textContent;
|
|
183
|
+
const orgName = (orgCell.querySelector('.dx-grid__cell__content') as HTMLElement).textContent;
|
|
193
184
|
// Type the first 4 characters to search
|
|
194
185
|
await userEvent.type(searchField, orgName.substring(0, 4));
|
|
195
186
|
|
|
@@ -209,9 +200,7 @@ export const Default: Story = {
|
|
|
209
200
|
|
|
210
201
|
// Test object creation (new relations) - equivalent to "new relations work as expected" test
|
|
211
202
|
// Find a different cell to test object creation (second row, relations column)
|
|
212
|
-
const newTargetCell = secondGrid.
|
|
213
|
-
'[data-dx-grid-plane="grid"] [aria-rowindex="1"][aria-colindex="4"]',
|
|
214
|
-
);
|
|
203
|
+
const newTargetCell = await within(secondGrid).findByTestId('grid.4.1', undefined, { timeout: 10_000 });
|
|
215
204
|
await expect(newTargetCell).toBeTruthy();
|
|
216
205
|
|
|
217
206
|
// Click to focus the cell
|
|
@@ -230,9 +219,9 @@ export const Default: Story = {
|
|
|
230
219
|
const newOrgName = 'Salieri LLC';
|
|
231
220
|
await userEvent.type(newSearchField, newOrgName);
|
|
232
221
|
|
|
233
|
-
//
|
|
234
|
-
const
|
|
235
|
-
await expect(
|
|
222
|
+
// Wait for the create option to appear (debounce is 200ms, allow time for render)
|
|
223
|
+
const createOption = await body.findByRole('option', undefined, { timeout: 500 });
|
|
224
|
+
await expect(createOption).toBeVisible();
|
|
236
225
|
|
|
237
226
|
// Press Enter to select/create
|
|
238
227
|
await userEvent.keyboard('{Enter}');
|