@dxos/react-ui-table 0.8.4-main.e098934 → 0.8.4-main.ead640a
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 → chunk-4K7JPALT.mjs} +5 -5
- package/dist/lib/browser/chunk-4K7JPALT.mjs.map +7 -0
- package/dist/lib/browser/{chunk-BBXDTWCX.mjs → chunk-OZTXLZGM.mjs} +24 -42
- package/dist/lib/browser/chunk-OZTXLZGM.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +123 -269
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +8 -6
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node-esm/{chunk-K734DJB7.mjs → chunk-MK6OVUF6.mjs} +5 -5
- package/dist/lib/node-esm/chunk-MK6OVUF6.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-RNQDU7IQ.mjs → chunk-S56Z4V4X.mjs} +24 -42
- package/dist/lib/node-esm/chunk-S56Z4V4X.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +123 -269
- 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 +8 -6
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/types/index.mjs +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 +3 -3
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +71 -7
- package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +5 -2
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +5 -6
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +7 -5
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -3
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +1 -2
- 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/testing.d.ts +3 -3
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts +1 -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 +0 -7
- package/dist/types/src/model/modal-controller.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +1 -1
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/testing/useTestTableModel.d.ts +1 -1
- package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +3 -3
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +3 -4
- package/dist/types/src/util/dynamic-table.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/tsconfig.tsbuildinfo +1 -1
- package/package.json +50 -50
- package/src/components/Table/DynamicTable.stories.tsx +8 -7
- package/src/components/Table/DynamicTable.tsx +4 -7
- package/src/components/Table/Relations.stories.tsx +126 -11
- package/src/components/Table/Table.stories.tsx +33 -32
- package/src/components/Table/Table.tsx +13 -9
- package/src/components/TableCellEditor/FormCellEditor.tsx +51 -41
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +17 -45
- package/src/components/TableCellEditor/TableCellEditor.tsx +7 -94
- package/src/components/TableCellEditor/index.ts +1 -0
- package/src/components/testing.ts +2 -2
- package/src/hooks/useAddRow.ts +1 -1
- package/src/hooks/useTableModel.ts +1 -1
- package/src/model/modal-controller.ts +0 -28
- package/src/model/table-model.test.ts +10 -5
- package/src/model/table-model.ts +2 -1
- package/src/model/table-presentation.test.ts +13 -16
- package/src/model/table-presentation.ts +4 -5
- package/src/model/table-sorting.ts +1 -1
- package/src/testing/useTestTableModel.ts +6 -4
- package/src/types/schema.ts +4 -4
- package/src/util/dynamic-table.ts +5 -6
- package/src/util/schema.ts +4 -4
- package/dist/lib/browser/chunk-63UUF4IG.mjs.map +0 -7
- package/dist/lib/browser/chunk-BBXDTWCX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-K734DJB7.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RNQDU7IQ.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/src/components/Table/CreateRefPanel.tsx +0 -103
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.ead640a",
|
|
4
4
|
"description": "A table component.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -53,73 +53,73 @@
|
|
|
53
53
|
"src"
|
|
54
54
|
],
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@codemirror/autocomplete": "^6.
|
|
56
|
+
"@codemirror/autocomplete": "^6.19.0",
|
|
57
57
|
"@codemirror/state": "^6.5.2",
|
|
58
|
-
"@codemirror/view": "^6.38.
|
|
58
|
+
"@codemirror/view": "^6.38.4",
|
|
59
59
|
"@fluentui/react-tabster": "^9.24.2",
|
|
60
60
|
"@preact-signals/safe-react": "^0.9.0",
|
|
61
|
-
"@preact/signals-core": "^1.
|
|
61
|
+
"@preact/signals-core": "^1.12.1",
|
|
62
62
|
"@radix-ui/react-context": "1.1.1",
|
|
63
63
|
"@radix-ui/react-primitive": "2.0.2",
|
|
64
64
|
"@radix-ui/react-slot": "1.1.2",
|
|
65
65
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
66
66
|
"date-fns": "^3.3.1",
|
|
67
67
|
"lodash.orderby": "^4.6.0",
|
|
68
|
-
"@dxos/async": "0.8.4-main.
|
|
69
|
-
"@dxos/context": "0.8.4-main.
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/echo
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/
|
|
74
|
-
"@dxos/invariant": "0.8.4-main.
|
|
75
|
-
"@dxos/keys": "0.8.4-main.
|
|
76
|
-
"@dxos/lit-grid": "0.8.4-main.
|
|
77
|
-
"@dxos/live-object": "0.8.4-main.
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/plugin-search": "0.8.4-main.
|
|
81
|
-
"@dxos/
|
|
82
|
-
"@dxos/react-
|
|
83
|
-
"@dxos/react-ui-
|
|
84
|
-
"@dxos/react-ui-editor": "0.8.4-main.
|
|
85
|
-
"@dxos/react-ui-
|
|
86
|
-
"@dxos/react-ui-
|
|
87
|
-
"@dxos/react-ui-menu": "0.8.4-main.
|
|
88
|
-
"@dxos/react-ui-
|
|
89
|
-
"@dxos/react-ui-
|
|
90
|
-
"@dxos/
|
|
91
|
-
"@dxos/react-ui-types": "0.8.4-main.
|
|
92
|
-
"@dxos/util": "0.8.4-main.
|
|
93
|
-
"@dxos/react-ui-
|
|
94
|
-
"@dxos/schema": "0.8.4-main.e098934"
|
|
68
|
+
"@dxos/async": "0.8.4-main.ead640a",
|
|
69
|
+
"@dxos/context": "0.8.4-main.ead640a",
|
|
70
|
+
"@dxos/debug": "0.8.4-main.ead640a",
|
|
71
|
+
"@dxos/echo": "0.8.4-main.ead640a",
|
|
72
|
+
"@dxos/echo-db": "0.8.4-main.ead640a",
|
|
73
|
+
"@dxos/effect": "0.8.4-main.ead640a",
|
|
74
|
+
"@dxos/invariant": "0.8.4-main.ead640a",
|
|
75
|
+
"@dxos/keys": "0.8.4-main.ead640a",
|
|
76
|
+
"@dxos/lit-grid": "0.8.4-main.ead640a",
|
|
77
|
+
"@dxos/live-object": "0.8.4-main.ead640a",
|
|
78
|
+
"@dxos/log": "0.8.4-main.ead640a",
|
|
79
|
+
"@dxos/random": "0.8.4-main.ead640a",
|
|
80
|
+
"@dxos/plugin-search": "0.8.4-main.ead640a",
|
|
81
|
+
"@dxos/react-client": "0.8.4-main.ead640a",
|
|
82
|
+
"@dxos/react-ui-attention": "0.8.4-main.ead640a",
|
|
83
|
+
"@dxos/react-ui-components": "0.8.4-main.ead640a",
|
|
84
|
+
"@dxos/react-ui-editor": "0.8.4-main.ead640a",
|
|
85
|
+
"@dxos/react-ui-grid": "0.8.4-main.ead640a",
|
|
86
|
+
"@dxos/react-ui-searchlist": "0.8.4-main.ead640a",
|
|
87
|
+
"@dxos/react-ui-menu": "0.8.4-main.ead640a",
|
|
88
|
+
"@dxos/react-ui-stack": "0.8.4-main.ead640a",
|
|
89
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.4-main.ead640a",
|
|
90
|
+
"@dxos/schema": "0.8.4-main.ead640a",
|
|
91
|
+
"@dxos/react-ui-types": "0.8.4-main.ead640a",
|
|
92
|
+
"@dxos/util": "0.8.4-main.ead640a",
|
|
93
|
+
"@dxos/react-ui-form": "0.8.4-main.ead640a"
|
|
95
94
|
},
|
|
96
95
|
"devDependencies": {
|
|
97
|
-
"@effect-rx/rx-react": "0.
|
|
98
|
-
"@effect/platform": "0.
|
|
96
|
+
"@effect-rx/rx-react": "0.42.4",
|
|
97
|
+
"@effect/platform": "0.92.1",
|
|
99
98
|
"@types/lodash.orderby": "^4.6.9",
|
|
100
|
-
"@types/react": "~
|
|
101
|
-
"@types/react-dom": "~
|
|
102
|
-
"effect": "3.
|
|
99
|
+
"@types/react": "~19.2.2",
|
|
100
|
+
"@types/react-dom": "~19.2.1",
|
|
101
|
+
"effect": "3.18.3",
|
|
103
102
|
"fast-check": "^3.19.0",
|
|
104
|
-
"react": "~
|
|
105
|
-
"react-dom": "~
|
|
106
|
-
"vite": "7.1.
|
|
107
|
-
"@dxos/
|
|
108
|
-
"@dxos/
|
|
109
|
-
"@dxos/
|
|
110
|
-
"@dxos/
|
|
111
|
-
"@dxos/react-ui
|
|
112
|
-
"@dxos/
|
|
113
|
-
"@dxos/
|
|
103
|
+
"react": "~19.2.0",
|
|
104
|
+
"react-dom": "~19.2.0",
|
|
105
|
+
"vite": "7.1.9",
|
|
106
|
+
"@dxos/echo-signals": "0.8.4-main.ead640a",
|
|
107
|
+
"@dxos/lit-ui": "0.8.4-main.ead640a",
|
|
108
|
+
"@dxos/plugin-search": "0.8.4-main.ead640a",
|
|
109
|
+
"@dxos/random": "0.8.4-main.ead640a",
|
|
110
|
+
"@dxos/react-ui": "0.8.4-main.ead640a",
|
|
111
|
+
"@dxos/react-ui-theme": "0.8.4-main.ead640a",
|
|
112
|
+
"@dxos/storybook-utils": "0.8.4-main.ead640a",
|
|
113
|
+
"@dxos/test-utils": "0.8.4-main.ead640a"
|
|
114
114
|
},
|
|
115
115
|
"peerDependencies": {
|
|
116
116
|
"@effect-rx/rx-react": "^0.34.1",
|
|
117
117
|
"@effect/platform": "^0.80.12",
|
|
118
118
|
"effect": "^3.13.3",
|
|
119
|
-
"react": "
|
|
120
|
-
"react-dom": "
|
|
121
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
122
|
-
"@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.ead640a",
|
|
122
|
+
"@dxos/react-ui-theme": "0.8.4-main.ead640a"
|
|
123
123
|
},
|
|
124
124
|
"publishConfig": {
|
|
125
125
|
"access": "public"
|
|
@@ -2,20 +2,18 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
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
18
|
import { type TableFeatures } from '../../model';
|
|
21
19
|
import { translations } from '../../translations';
|
|
@@ -60,8 +58,11 @@ const DynamicTableStory = () => {
|
|
|
60
58
|
const meta = {
|
|
61
59
|
title: 'ui/react-ui-table/DynamicTable',
|
|
62
60
|
component: DynamicTable,
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
decorators: [withTheme],
|
|
62
|
+
parameters: {
|
|
63
|
+
layout: 'fullscreen',
|
|
64
|
+
translations,
|
|
65
|
+
},
|
|
65
66
|
} satisfies Meta<typeof DynamicTable>;
|
|
66
67
|
|
|
67
68
|
export default meta;
|
|
@@ -144,7 +145,7 @@ export const WithEchoSchema: StoryObj = {
|
|
|
144
145
|
types: [Testing.Contact],
|
|
145
146
|
createIdentity: true,
|
|
146
147
|
createSpace: true,
|
|
147
|
-
|
|
148
|
+
onCreateSpace: async ({ space }) => {
|
|
148
149
|
Array.from({ length: 10 }).forEach(() => {
|
|
149
150
|
space.db.add(
|
|
150
151
|
Obj.make(Testing.Contact, {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import type * as Schema from 'effect/Schema';
|
|
6
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
|
|
|
@@ -45,15 +45,12 @@ export const DynamicTable = ({
|
|
|
45
45
|
...props
|
|
46
46
|
}: DynamicTableProps) => {
|
|
47
47
|
// TODO(burdon): Remove variance from the props (should be normalized externally; possibly via hooks).
|
|
48
|
-
const {
|
|
48
|
+
const { jsonSchema } = useMemo(
|
|
49
49
|
() => getBaseSchema({ typename: name, properties, jsonSchema: _jsonSchema, schema }),
|
|
50
50
|
[name, properties, _jsonSchema, schema],
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
const { projection, view } = useMemo(
|
|
54
|
-
() => makeDynamicTable({ typename, jsonSchema, properties }),
|
|
55
|
-
[typename, jsonSchema, properties],
|
|
56
|
-
);
|
|
53
|
+
const { projection, view } = useMemo(() => makeDynamicTable({ jsonSchema, properties }), [jsonSchema, properties]);
|
|
57
54
|
|
|
58
55
|
const tableRef = useRef<TableController>(null);
|
|
59
56
|
const handleCellUpdate = useCallback((cell: any) => {
|
|
@@ -2,20 +2,23 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
|
|
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';
|
|
12
14
|
import { faker } from '@dxos/random';
|
|
13
15
|
import { useClient } from '@dxos/react-client';
|
|
14
16
|
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
15
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';
|
|
16
20
|
import { DataType } from '@dxos/schema';
|
|
17
21
|
import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
|
|
18
|
-
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
19
22
|
|
|
20
23
|
import { useTableModel } from '../../hooks';
|
|
21
24
|
import { type TableFeatures, TablePresentation, type TableRow } from '../../model';
|
|
@@ -86,6 +89,14 @@ const DefaultStory = () => {
|
|
|
86
89
|
const client = useClient();
|
|
87
90
|
const { model: orgModel, presentation: orgPresentation } = useTestModel(DataType.Organization, 50);
|
|
88
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
|
+
);
|
|
89
100
|
|
|
90
101
|
return (
|
|
91
102
|
<div className='is-full bs-full grid grid-cols-2 divide-x divide-separator'>
|
|
@@ -94,8 +105,10 @@ const DefaultStory = () => {
|
|
|
94
105
|
model={orgModel}
|
|
95
106
|
schema={DataType.Organization}
|
|
96
107
|
presentation={orgPresentation}
|
|
108
|
+
onCreate={handleCreate}
|
|
97
109
|
client={client}
|
|
98
110
|
ignoreAttention
|
|
111
|
+
testId='relations-0'
|
|
99
112
|
/>
|
|
100
113
|
</TableComponent.Root>
|
|
101
114
|
<TableComponent.Root>
|
|
@@ -103,8 +116,10 @@ const DefaultStory = () => {
|
|
|
103
116
|
model={contactModel}
|
|
104
117
|
schema={DataType.Person}
|
|
105
118
|
presentation={contactPresentation}
|
|
119
|
+
onCreate={handleCreate}
|
|
106
120
|
client={client}
|
|
107
121
|
ignoreAttention
|
|
122
|
+
testId='relations-1'
|
|
108
123
|
/>
|
|
109
124
|
</TableComponent.Root>
|
|
110
125
|
</div>
|
|
@@ -114,20 +129,120 @@ const DefaultStory = () => {
|
|
|
114
129
|
const meta = {
|
|
115
130
|
title: 'ui/react-ui-table/Relations',
|
|
116
131
|
render: DefaultStory,
|
|
117
|
-
parameters: { translations, controls: { disable: true } },
|
|
118
132
|
decorators: [
|
|
133
|
+
withTheme,
|
|
119
134
|
withClientProvider({
|
|
120
135
|
types: [DataType.View, DataType.Organization, DataType.Person, Table.Table],
|
|
121
136
|
createIdentity: true,
|
|
122
137
|
createSpace: true,
|
|
123
138
|
}),
|
|
124
|
-
withTheme,
|
|
125
|
-
withLayout({ fullscreen: true }),
|
|
126
139
|
],
|
|
140
|
+
parameters: {
|
|
141
|
+
layout: 'fullscreen',
|
|
142
|
+
controls: { disable: true },
|
|
143
|
+
translations: [...translations, ...formTranslations],
|
|
144
|
+
},
|
|
127
145
|
} satisfies Meta<typeof DefaultStory>;
|
|
128
146
|
|
|
129
147
|
export default meta;
|
|
130
148
|
|
|
131
149
|
type Story = StoryObj<typeof meta>;
|
|
132
150
|
|
|
133
|
-
export const Default: Story = {
|
|
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;
|
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
9
7
|
import React, { useCallback } from 'react';
|
|
10
8
|
|
|
11
|
-
import {
|
|
9
|
+
import { Obj, type QueryAST, Type } from '@dxos/echo';
|
|
12
10
|
import {
|
|
13
11
|
EchoObject,
|
|
14
12
|
FormatAnnotation,
|
|
@@ -16,17 +14,18 @@ import {
|
|
|
16
14
|
GeneratorAnnotation,
|
|
17
15
|
LabelAnnotation,
|
|
18
16
|
PropertyMetaAnnotationId,
|
|
19
|
-
} from '@dxos/echo
|
|
17
|
+
} from '@dxos/echo/internal';
|
|
18
|
+
import { live } from '@dxos/echo/internal';
|
|
20
19
|
import { invariant } from '@dxos/invariant';
|
|
21
20
|
import { faker } from '@dxos/random';
|
|
22
21
|
import { PublicKey } from '@dxos/react-client';
|
|
23
|
-
import { type Space
|
|
22
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
24
23
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
24
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
25
25
|
import { ViewEditor } from '@dxos/react-ui-form';
|
|
26
26
|
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
27
|
-
import { DataType, getSchemaFromPropertyDefinitions } from '@dxos/schema';
|
|
27
|
+
import { DataType, getSchemaFromPropertyDefinitions, getTypenameFromQuery } from '@dxos/schema';
|
|
28
28
|
import { Testing, createObjectFactory } from '@dxos/schema/testing';
|
|
29
|
-
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
30
29
|
|
|
31
30
|
import { useTestTableModel } from '../../testing';
|
|
32
31
|
import { translations } from '../../translations';
|
|
@@ -77,12 +76,12 @@ const StoryViewEditor = ({
|
|
|
77
76
|
handleDeleteColumn: (fieldId: string) => void;
|
|
78
77
|
}) => {
|
|
79
78
|
const handleQueryChanged = useCallback(
|
|
80
|
-
(
|
|
79
|
+
(newQuery: QueryAST.Query) => {
|
|
81
80
|
invariant(schema);
|
|
82
81
|
invariant(Type.isMutable(schema));
|
|
83
|
-
schema.updateTypename(
|
|
82
|
+
schema.updateTypename(getTypenameFromQuery(newQuery));
|
|
84
83
|
invariant(view);
|
|
85
|
-
view.query =
|
|
84
|
+
view.query.ast = newQuery;
|
|
86
85
|
},
|
|
87
86
|
[schema, view],
|
|
88
87
|
);
|
|
@@ -160,21 +159,13 @@ type StoryProps = { rows?: number };
|
|
|
160
159
|
const meta = {
|
|
161
160
|
title: 'ui/react-ui-table/Table',
|
|
162
161
|
render: DefaultStory,
|
|
163
|
-
parameters: {
|
|
164
|
-
translations,
|
|
165
|
-
layout: 'fullscreen',
|
|
166
|
-
controls: {
|
|
167
|
-
disable: true,
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
162
|
decorators: [
|
|
171
163
|
withTheme,
|
|
172
|
-
withLayout({ fullscreen: true }),
|
|
173
164
|
withClientProvider({
|
|
174
165
|
types: [DataType.View, Table.Table],
|
|
175
166
|
createIdentity: true,
|
|
176
167
|
createSpace: true,
|
|
177
|
-
|
|
168
|
+
onCreateSpace: async ({ client, space }) => {
|
|
178
169
|
const [schema] = await space.db.schemaRegistry.register([TestSchema]);
|
|
179
170
|
const { view } = await Table.makeView({ client, space, typename: schema.typename });
|
|
180
171
|
view.projection.fields = [
|
|
@@ -196,6 +187,13 @@ const meta = {
|
|
|
196
187
|
},
|
|
197
188
|
}),
|
|
198
189
|
],
|
|
190
|
+
parameters: {
|
|
191
|
+
layout: 'fullscreen',
|
|
192
|
+
controls: {
|
|
193
|
+
disable: true,
|
|
194
|
+
},
|
|
195
|
+
translations,
|
|
196
|
+
},
|
|
199
197
|
} satisfies Meta<typeof TableComponent>;
|
|
200
198
|
|
|
201
199
|
export default meta;
|
|
@@ -206,13 +204,12 @@ export const Default: Story = {};
|
|
|
206
204
|
|
|
207
205
|
export const StaticSchema: StoryObj = {
|
|
208
206
|
render: DefaultStory,
|
|
209
|
-
parameters: { translations },
|
|
210
207
|
decorators: [
|
|
211
208
|
withClientProvider({
|
|
212
209
|
types: [DataType.View, Table.Table, Testing.Contact, Testing.Organization],
|
|
213
210
|
createIdentity: true,
|
|
214
211
|
createSpace: true,
|
|
215
|
-
|
|
212
|
+
onCreateSpace: async ({ client, space }) => {
|
|
216
213
|
const { view } = await Table.makeView({ client, space, typename: Testing.Contact.typename });
|
|
217
214
|
space.db.add(view);
|
|
218
215
|
|
|
@@ -223,9 +220,11 @@ export const StaticSchema: StoryObj = {
|
|
|
223
220
|
]);
|
|
224
221
|
},
|
|
225
222
|
}),
|
|
226
|
-
withLayout({ fullscreen: true }),
|
|
227
|
-
withTheme,
|
|
228
223
|
],
|
|
224
|
+
parameters: {
|
|
225
|
+
layout: 'fullscreen',
|
|
226
|
+
translations,
|
|
227
|
+
},
|
|
229
228
|
};
|
|
230
229
|
|
|
231
230
|
const ContactWithArrayOfEmails = Schema.Struct({
|
|
@@ -247,13 +246,12 @@ const ContactWithArrayOfEmails = Schema.Struct({
|
|
|
247
246
|
|
|
248
247
|
export const ArrayOfObjects: StoryObj = {
|
|
249
248
|
render: DefaultStory,
|
|
250
|
-
parameters: { translations },
|
|
251
249
|
decorators: [
|
|
252
250
|
withClientProvider({
|
|
253
251
|
types: [DataType.View, Table.Table, Testing.Contact, Testing.Organization, ContactWithArrayOfEmails],
|
|
254
252
|
createIdentity: true,
|
|
255
253
|
createSpace: true,
|
|
256
|
-
|
|
254
|
+
onCreateSpace: async ({ client, space }) => {
|
|
257
255
|
const { view } = await Table.makeView({ client, space, typename: ContactWithArrayOfEmails.typename });
|
|
258
256
|
space.db.add(view);
|
|
259
257
|
|
|
@@ -265,21 +263,22 @@ export const ArrayOfObjects: StoryObj = {
|
|
|
265
263
|
]);
|
|
266
264
|
},
|
|
267
265
|
}),
|
|
268
|
-
withLayout({ fullscreen: true }),
|
|
269
|
-
withTheme,
|
|
270
266
|
],
|
|
267
|
+
parameters: {
|
|
268
|
+
layout: 'fullscreen',
|
|
269
|
+
translations,
|
|
270
|
+
},
|
|
271
271
|
};
|
|
272
272
|
|
|
273
273
|
export const Tags: Meta<StoryProps> = {
|
|
274
274
|
title: 'ui/react-ui-table/Table',
|
|
275
275
|
render: DefaultStory,
|
|
276
|
-
parameters: { translations },
|
|
277
276
|
decorators: [
|
|
278
277
|
withClientProvider({
|
|
279
278
|
types: [DataType.View, Table.Table],
|
|
280
279
|
createIdentity: true,
|
|
281
280
|
createSpace: true,
|
|
282
|
-
|
|
281
|
+
onCreateSpace: async ({ client, space }) => {
|
|
283
282
|
// Configure schema.
|
|
284
283
|
const typename = 'example.com/SingleSelect';
|
|
285
284
|
const selectOptions = [
|
|
@@ -321,7 +320,9 @@ export const Tags: Meta<StoryProps> = {
|
|
|
321
320
|
});
|
|
322
321
|
},
|
|
323
322
|
}),
|
|
324
|
-
withLayout({ fullscreen: true }),
|
|
325
|
-
withTheme,
|
|
326
323
|
],
|
|
324
|
+
parameters: {
|
|
325
|
+
layout: 'fullscreen',
|
|
326
|
+
translations,
|
|
327
|
+
},
|
|
327
328
|
};
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import type * as Schema from 'effect/Schema';
|
|
6
|
+
import * as String from 'effect/String';
|
|
6
7
|
import React, {
|
|
7
8
|
type MouseEvent,
|
|
8
9
|
type PropsWithChildren,
|
|
@@ -15,8 +16,8 @@ import React, {
|
|
|
15
16
|
useState,
|
|
16
17
|
} from 'react';
|
|
17
18
|
|
|
18
|
-
import { type Client } from '@dxos/react-client';
|
|
19
19
|
// TODO(wittjosiah): Remove dependency on react-client.
|
|
20
|
+
import { type Client } from '@dxos/react-client';
|
|
20
21
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
21
22
|
import {
|
|
22
23
|
type DxGridElement,
|
|
@@ -34,11 +35,10 @@ import { mx } from '@dxos/react-ui-theme';
|
|
|
34
35
|
|
|
35
36
|
import { type InsertRowResult, ModalController, type TableModel, type TablePresentation } from '../../model';
|
|
36
37
|
import { tableButtons, tableControls } from '../../util';
|
|
37
|
-
import { type TableCellEditorProps, TableValueEditor } from '../TableCellEditor';
|
|
38
|
+
import { type OnCreateHandler, type TableCellEditorProps, TableValueEditor } from '../TableCellEditor';
|
|
38
39
|
|
|
39
40
|
import { ColumnActionsMenu } from './ColumnActionsMenu';
|
|
40
41
|
import { ColumnSettings } from './ColumnSettings';
|
|
41
|
-
import { CreateRefPanel } from './CreateRefPanel';
|
|
42
42
|
import { RowActionsMenu } from './RowActionsMenu';
|
|
43
43
|
|
|
44
44
|
const columnDefault = { grid: { minSize: 80, maxSize: 640 } };
|
|
@@ -80,15 +80,17 @@ export type TableController = {
|
|
|
80
80
|
export type TableMainProps = {
|
|
81
81
|
model?: TableModel;
|
|
82
82
|
presentation?: TablePresentation;
|
|
83
|
-
schema?: Schema.AnyNoContext;
|
|
83
|
+
schema?: Schema.Schema.AnyNoContext;
|
|
84
84
|
client?: Client;
|
|
85
85
|
// TODO(burdon): Rename since attention isn't a useful concept here? Standardize across other components. Pass property into useAttention.
|
|
86
86
|
ignoreAttention?: boolean;
|
|
87
|
+
onCreate?: OnCreateHandler;
|
|
87
88
|
onRowClick?: (row: any) => void;
|
|
89
|
+
testId?: string;
|
|
88
90
|
};
|
|
89
91
|
|
|
90
92
|
const TableMain = forwardRef<TableController, TableMainProps>(
|
|
91
|
-
({ model, presentation, ignoreAttention, schema, client, onRowClick }, forwardedRef) => {
|
|
93
|
+
({ model, presentation, ignoreAttention, schema, client, onCreate, onRowClick, testId }, forwardedRef) => {
|
|
92
94
|
const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
|
|
93
95
|
const { hasAttention } = useAttention(model?.id ?? 'table');
|
|
94
96
|
const modals = useMemo(() => new ModalController(), []);
|
|
@@ -275,7 +277,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
275
277
|
const handleFocus = useCallback<NonNullable<TableCellEditorProps['onFocus']>>(
|
|
276
278
|
(increment, delta, cell) => {
|
|
277
279
|
if (dxGrid && model) {
|
|
278
|
-
if (cell?.plane === 'grid' && cell?.row >= model.getRowCount() - 1) {
|
|
280
|
+
if (cell?.plane === 'grid' && cell?.row >= model.getRowCount() - 1 && increment !== 'col') {
|
|
279
281
|
handleInsertRowResult(draftRowCount < 1 ? model.insertRow() : 'final');
|
|
280
282
|
} else if (cell?.plane === 'frozenRowsEnd' && increment === 'row') {
|
|
281
283
|
handleSaveDraftRow(cell.row);
|
|
@@ -320,7 +322,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
320
322
|
void navigator.clipboard.readText().then((clipboardText) => {
|
|
321
323
|
try {
|
|
322
324
|
// Attempt to set the cell's content to clipboard content
|
|
323
|
-
model.setCellData(cell, clipboardText);
|
|
325
|
+
model.setCellData(cell, String.trim(clipboardText).replace(/[\n\r]+/, ' '));
|
|
324
326
|
handleSave();
|
|
325
327
|
} catch {
|
|
326
328
|
// If validation fails, emit a DxEditRequest event with initialContent from clipboard
|
|
@@ -356,6 +358,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
356
358
|
try {
|
|
357
359
|
model.setCellData(cell, undefined);
|
|
358
360
|
event.preventDefault();
|
|
361
|
+
handleSave();
|
|
359
362
|
} catch {
|
|
360
363
|
// Delete results in a validation error; don’t prevent default so dx-grid can emit an edit request.
|
|
361
364
|
}
|
|
@@ -404,6 +407,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
404
407
|
schema={schema}
|
|
405
408
|
onFocus={handleFocus}
|
|
406
409
|
onSave={handleSave}
|
|
410
|
+
onCreate={onCreate}
|
|
407
411
|
client={client}
|
|
408
412
|
/>
|
|
409
413
|
<Grid.Content
|
|
@@ -419,12 +423,12 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
419
423
|
onClick={handleGridClick}
|
|
420
424
|
onKeyDownCapture={handleKeyDown}
|
|
421
425
|
onWheelCapture={handleWheel}
|
|
426
|
+
{...(testId && { 'data-testid': testId })}
|
|
422
427
|
ref={setDxGrid}
|
|
423
428
|
/>
|
|
424
429
|
<RowActionsMenu model={model} modals={modals} />
|
|
425
430
|
<ColumnActionsMenu model={model} modals={modals} />
|
|
426
431
|
<ColumnSettings model={model} modals={modals} onNewColumn={handleNewColumn} />
|
|
427
|
-
<CreateRefPanel model={model} modals={modals} />
|
|
428
432
|
</Grid.Root>
|
|
429
433
|
);
|
|
430
434
|
},
|