@dxos/react-ui-table 0.8.4-main.70d3990 → 0.8.4-main.74a063c4e0
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-5XWSB3JP.mjs → chunk-BF54SSNL.mjs} +27 -28
- package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
- package/dist/lib/browser/{chunk-KNC7XYT6.mjs → chunk-NTWHM2PX.mjs} +620 -652
- package/dist/lib/browser/chunk-NTWHM2PX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1164 -1021
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +22 -21
- 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-MKTMOY46.mjs → chunk-SIRDIPHZ.mjs} +27 -28
- package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-CWSGS3Y2.mjs → chunk-Z3TLFG6Z.mjs} +620 -651
- package/dist/lib/node-esm/chunk-Z3TLFG6Z.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1164 -1021
- 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 +22 -21
- 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/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 +21 -37
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +82 -81
- 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 +28 -21
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +84 -83
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableContent.d.ts +21 -0
- package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts +25 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
- package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +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 +24 -26
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +22 -13
- package/dist/types/src/components/testing.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 +2 -1
- package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -1
- package/dist/types/src/hooks/useTableModel.d.ts +6 -5
- 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 +100 -18
- 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 +5 -8
- package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +21 -23
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Table.d.ts +13 -15
- package/dist/types/src/types/Table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +12 -10
- 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 +55 -56
- package/src/components/Table/ColumnActionsMenu.tsx +15 -11
- package/src/components/Table/ColumnSettings.tsx +8 -9
- package/src/components/Table/DynamicTable.stories.tsx +22 -23
- package/src/components/Table/DynamicTable.tsx +32 -40
- package/src/components/Table/Relations.stories.tsx +56 -48
- package/src/components/Table/RowActionsMenu.tsx +3 -2
- package/src/components/Table/Table.stories.tsx +89 -78
- package/src/components/Table/Table.tsx +43 -407
- package/src/components/Table/TableContent.tsx +421 -0
- package/src/components/{TableToolbar → Table}/TableToolbar.tsx +43 -44
- package/src/components/TableCellEditor/CellValidationMessage.tsx +5 -5
- package/src/components/TableCellEditor/FormCellEditor.tsx +118 -135
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +16 -14
- package/src/components/TableCellEditor/TableCellEditor.tsx +33 -29
- package/src/components/index.ts +0 -1
- package/src/components/testing.ts +42 -16
- package/src/hooks/useAddRow.ts +8 -10
- package/src/hooks/useProjectionModel.ts +29 -9
- package/src/hooks/useTableModel.ts +27 -23
- package/src/model/modal-controller.ts +23 -12
- package/src/model/selection-model.ts +75 -44
- package/src/model/table-model.test.ts +81 -54
- package/src/model/table-model.ts +410 -138
- package/src/model/table-presentation.test.ts +58 -49
- package/src/model/table-presentation.ts +34 -29
- package/src/playwright/TableManager.ts +12 -5
- package/src/playwright/playwright.config.ts +1 -1
- package/src/playwright/smoke.spec.ts +51 -7
- package/src/testing/useTestTableModel.ts +26 -27
- package/src/translations.ts +20 -22
- package/src/types/Table.ts +28 -38
- package/src/util/dynamic-table.test.ts +70 -0
- package/src/util/dynamic-table.ts +36 -19
- package/src/util/index.ts +2 -0
- package/src/util/query-ast.ts +22 -0
- package/src/util/sort.ts +90 -0
- package/src/util/table-buttons.ts +1 -1
- package/src/util/table-controls.ts +2 -2
- package/dist/lib/browser/chunk-5XWSB3JP.mjs.map +0 -7
- package/dist/lib/browser/chunk-KNC7XYT6.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CWSGS3Y2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-MKTMOY46.mjs.map +0 -7
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +0 -21
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +0 -1
- package/dist/types/src/components/TableToolbar/index.d.ts +0 -2
- package/dist/types/src/components/TableToolbar/index.d.ts.map +0 -1
- package/dist/types/src/model/table-sorting.d.ts +0 -56
- package/dist/types/src/model/table-sorting.d.ts.map +0 -1
- package/src/components/TableToolbar/index.ts +0 -5
- package/src/model/table-sorting.ts +0 -234
|
@@ -2,41 +2,42 @@
|
|
|
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
|
|
8
|
-
import { expect, userEvent, within } from 'storybook/test';
|
|
7
|
+
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
8
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test';
|
|
9
9
|
|
|
10
10
|
import { Obj, Type } from '@dxos/echo';
|
|
11
|
+
import { View } from '@dxos/echo';
|
|
12
|
+
import { invariant } from '@dxos/invariant';
|
|
11
13
|
import { type DxGrid } from '@dxos/lit-grid';
|
|
12
|
-
import '@dxos/
|
|
13
|
-
import {
|
|
14
|
-
import { useClient } from '@dxos/react-client';
|
|
15
|
-
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
14
|
+
import { random } from '@dxos/random';
|
|
15
|
+
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
16
16
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
17
|
-
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
18
17
|
import { translations as formTranslations } from '@dxos/react-ui-form';
|
|
19
|
-
import {
|
|
18
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
19
|
+
import { ViewModel } from '@dxos/schema';
|
|
20
20
|
import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
|
|
21
|
+
import { withRegistry } from '@dxos/storybook-utils';
|
|
21
22
|
import { Organization, Person } from '@dxos/types';
|
|
23
|
+
import '@dxos/lit-ui/dx-tag-picker.pcss';
|
|
22
24
|
|
|
23
25
|
import { useProjectionModel, useTableModel } from '../../hooks';
|
|
24
26
|
import { type TableFeatures, TablePresentation, type TableRow } from '../../model';
|
|
25
27
|
import { translations } from '../../translations';
|
|
26
28
|
import { Table } from '../../types';
|
|
27
|
-
|
|
28
29
|
import { Table as TableComponent } from './Table';
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
const generator: ValueGenerator =
|
|
31
|
+
random.seed(1);
|
|
32
|
+
const generator: ValueGenerator = random as any;
|
|
32
33
|
|
|
33
34
|
// TODO(burdon): Many-to-many relations.
|
|
34
35
|
// TODO(burdon): Mutable and immutable views.
|
|
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
|
-
const useTestModel = <S extends Type.
|
|
38
|
-
const
|
|
39
|
-
const { space } =
|
|
38
|
+
const useTestModel = <S extends Type.AnyObj>(schema: S, count: number) => {
|
|
39
|
+
const registry = useContext(RegistryContext);
|
|
40
|
+
const { space } = useClientStory();
|
|
40
41
|
const [object, setObject] = useState<Table.Table>();
|
|
41
42
|
|
|
42
43
|
const features = useMemo<TableFeatures>(
|
|
@@ -49,15 +50,14 @@ const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
|
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
const { view, jsonSchema } = await
|
|
53
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename: Type.getTypename(schema) });
|
|
53
54
|
const object = Table.make({ view, jsonSchema });
|
|
54
55
|
setObject(object);
|
|
55
56
|
space.db.add(object);
|
|
56
|
-
|
|
57
|
-
}, [client, space, schema]);
|
|
57
|
+
}, [space, schema]);
|
|
58
58
|
|
|
59
|
-
const projection = useProjectionModel(schema, object);
|
|
60
|
-
const model = useTableModel<TableRow>({ object, projection, features });
|
|
59
|
+
const projection = useProjectionModel(schema, object, registry);
|
|
60
|
+
const model = useTableModel<TableRow>({ object, projection, db: space?.db, features });
|
|
61
61
|
|
|
62
62
|
useEffect(() => {
|
|
63
63
|
if (!model || !space) {
|
|
@@ -75,45 +75,44 @@ const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
|
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
return new TablePresentation(model);
|
|
79
|
-
}, [model]);
|
|
78
|
+
return new TablePresentation(registry, model);
|
|
79
|
+
}, [registry, model]);
|
|
80
80
|
|
|
81
81
|
return { model, presentation };
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
const DefaultStory = () => {
|
|
85
|
-
const client = useClient();
|
|
86
85
|
const { model: orgModel, presentation: orgPresentation } = useTestModel(Organization.Organization, 50);
|
|
87
86
|
const { model: contactModel, presentation: contactPresentation } = useTestModel(Person.Person, 50);
|
|
88
|
-
const { space } =
|
|
87
|
+
const { space } = useClientStory();
|
|
89
88
|
|
|
90
89
|
const handleCreate = useCallback(
|
|
91
|
-
(schema:
|
|
92
|
-
|
|
90
|
+
(schema: Type.AnyEntity, values: any) => {
|
|
91
|
+
invariant(Type.isObjectSchema(schema));
|
|
92
|
+
invariant(space);
|
|
93
|
+
return space.db.add(Obj.make(schema, values));
|
|
93
94
|
},
|
|
94
95
|
[space],
|
|
95
96
|
);
|
|
96
97
|
|
|
97
98
|
return (
|
|
98
|
-
<div className='
|
|
99
|
+
<div className='dx-expander grid grid-cols-2 divide-x divide-separator'>
|
|
99
100
|
<TableComponent.Root>
|
|
100
|
-
<TableComponent.
|
|
101
|
+
<TableComponent.Content
|
|
101
102
|
model={orgModel}
|
|
102
103
|
schema={Organization.Organization}
|
|
103
104
|
presentation={orgPresentation}
|
|
104
105
|
onCreate={handleCreate}
|
|
105
|
-
client={client}
|
|
106
106
|
ignoreAttention
|
|
107
107
|
testId='relations-0'
|
|
108
108
|
/>
|
|
109
109
|
</TableComponent.Root>
|
|
110
110
|
<TableComponent.Root>
|
|
111
|
-
<TableComponent.
|
|
111
|
+
<TableComponent.Content
|
|
112
112
|
model={contactModel}
|
|
113
113
|
schema={Person.Person}
|
|
114
114
|
presentation={contactPresentation}
|
|
115
115
|
onCreate={handleCreate}
|
|
116
|
-
client={client}
|
|
117
116
|
ignoreAttention
|
|
118
117
|
testId='relations-1'
|
|
119
118
|
/>
|
|
@@ -126,8 +125,9 @@ const meta = {
|
|
|
126
125
|
title: 'ui/react-ui-table/Relations',
|
|
127
126
|
render: DefaultStory,
|
|
128
127
|
decorators: [
|
|
129
|
-
withTheme,
|
|
130
|
-
|
|
128
|
+
withTheme(),
|
|
129
|
+
withRegistry,
|
|
130
|
+
// TODO(thure): Shouldn't `layout: 'fullscreen'` below make this unnecessary?
|
|
131
131
|
withLayout({ classNames: 'fixed inset-0' }),
|
|
132
132
|
withClientProvider({
|
|
133
133
|
types: [View.View, Organization.Organization, Person.Person, Table.Table],
|
|
@@ -147,7 +147,7 @@ export default meta;
|
|
|
147
147
|
type Story = StoryObj<typeof meta>;
|
|
148
148
|
|
|
149
149
|
export const Default: Story = {
|
|
150
|
-
play: async ({ canvasElement }
|
|
150
|
+
play: async ({ canvasElement }) => {
|
|
151
151
|
const canvas = within(canvasElement);
|
|
152
152
|
const body = within(document.body);
|
|
153
153
|
|
|
@@ -195,8 +195,15 @@ export const Default: Story = {
|
|
|
195
195
|
const saveButton = await body.findByTestId('save-button');
|
|
196
196
|
await userEvent.click(saveButton);
|
|
197
197
|
|
|
198
|
-
// Verify the relation was set (cell should now contain the org name)
|
|
199
|
-
|
|
198
|
+
// Verify the relation was set (cell should now contain the org name).
|
|
199
|
+
// Wait for the grid (Lit web component) to repaint after the reactive data update.
|
|
200
|
+
await waitFor(
|
|
201
|
+
async () => {
|
|
202
|
+
const updatedCell = within(secondGrid).getByTestId('grid.4.0');
|
|
203
|
+
await expect(updatedCell).toHaveTextContent(orgName.substring(0, 4));
|
|
204
|
+
},
|
|
205
|
+
{ timeout: 5000 },
|
|
206
|
+
);
|
|
200
207
|
|
|
201
208
|
// Test object creation (new relations) - equivalent to "new relations work as expected" test
|
|
202
209
|
// Find a different cell to test object creation (second row, relations column)
|
|
@@ -215,23 +222,24 @@ export const Default: Story = {
|
|
|
215
222
|
const newSearchField = await body.findByPlaceholderText('Search…');
|
|
216
223
|
await userEvent.click(newSearchField);
|
|
217
224
|
|
|
218
|
-
// Type a new object name (this will create a new object)
|
|
225
|
+
// Type a new object name (this will create a new object).
|
|
219
226
|
const newOrgName = 'Salieri LLC';
|
|
220
227
|
await userEvent.type(newSearchField, newOrgName);
|
|
221
228
|
|
|
222
|
-
//
|
|
223
|
-
const
|
|
224
|
-
await
|
|
229
|
+
// Click the create option directly to open the create form.
|
|
230
|
+
const createOptionLabel = await body.findByText(/Create new object/, undefined, { timeout: 2000 });
|
|
231
|
+
await userEvent.click(createOptionLabel.closest('[role="option"]') as HTMLElement);
|
|
225
232
|
|
|
226
|
-
//
|
|
227
|
-
await
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const createReferencedObjectForm = await body.findByTestId('create-referenced-object-form');
|
|
233
|
+
// Look for and click save button.
|
|
234
|
+
const createReferencedObjectForm = await body.findByTestId('create-referenced-object-form', undefined, {
|
|
235
|
+
timeout: 2000,
|
|
236
|
+
});
|
|
231
237
|
const saveObjectButton = await within(createReferencedObjectForm).findByTestId('save-button');
|
|
238
|
+
await expect(saveObjectButton).not.toBeDisabled();
|
|
232
239
|
await userEvent.click(saveObjectButton);
|
|
233
240
|
|
|
234
|
-
// Verify the
|
|
235
|
-
await
|
|
241
|
+
// Verify the relation was set by checking for the accessory link anchor in the cell.
|
|
242
|
+
const updatedNewCell = await within(secondGrid).findByTestId('grid.4.1', undefined, { timeout: 5000 });
|
|
243
|
+
await expect(updatedNewCell.querySelector('dx-anchor')).toBeTruthy();
|
|
236
244
|
},
|
|
237
|
-
}
|
|
245
|
+
};
|
|
@@ -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, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
@@ -13,8 +14,8 @@ type RowActionsMenuProps = { model: TableModel; modals: ModalController };
|
|
|
13
14
|
|
|
14
15
|
export const RowActionsMenu = ({ model, modals }: RowActionsMenuProps) => {
|
|
15
16
|
const { t } = useTranslation(translationKey);
|
|
16
|
-
const hasSelection = model.selection.hasSelection
|
|
17
|
-
const state = modals.state
|
|
17
|
+
const hasSelection = model.selection.hasSelection;
|
|
18
|
+
const state = useAtomValue(modals.state);
|
|
18
19
|
if (state?.type !== 'row') {
|
|
19
20
|
return null;
|
|
20
21
|
}
|
|
@@ -6,24 +6,24 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
6
6
|
import * as Schema from 'effect/Schema';
|
|
7
7
|
import React, { useCallback } from 'react';
|
|
8
8
|
|
|
9
|
-
import { Annotation, Format, Obj, type QueryAST, Type } from '@dxos/echo';
|
|
10
|
-
import {
|
|
9
|
+
import { Annotation, type Database, Format, Obj, type QueryAST, Ref, Type } from '@dxos/echo';
|
|
10
|
+
import { View } from '@dxos/echo';
|
|
11
|
+
import { type Mutable, PropertyMetaAnnotationId } from '@dxos/echo/internal';
|
|
11
12
|
import { invariant } from '@dxos/invariant';
|
|
12
|
-
import {
|
|
13
|
+
import { random } from '@dxos/random';
|
|
13
14
|
import { PublicKey } from '@dxos/react-client';
|
|
14
|
-
import { type Space } from '@dxos/react-client/echo';
|
|
15
15
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
16
|
-
import {
|
|
16
|
+
import { Panel, ScrollArea } from '@dxos/react-ui';
|
|
17
17
|
import { ViewEditor, translations as formTranslations } from '@dxos/react-ui-form';
|
|
18
18
|
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
19
|
-
import {
|
|
19
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
20
|
+
import { ViewModel, getSchemaFromPropertyDefinitions, getTypenameFromQuery } from '@dxos/schema';
|
|
20
21
|
import { TestSchema, createObjectFactory } from '@dxos/schema/testing';
|
|
22
|
+
import { withRegistry } from '@dxos/storybook-utils';
|
|
21
23
|
|
|
22
24
|
import { useTestTableModel } from '../../testing';
|
|
23
25
|
import { translations } from '../../translations';
|
|
24
26
|
import { Table } from '../../types';
|
|
25
|
-
import { TableToolbar } from '../TableToolbar';
|
|
26
|
-
|
|
27
27
|
import { Table as TableComponent } from './Table';
|
|
28
28
|
|
|
29
29
|
const Example = Schema.Struct({
|
|
@@ -47,11 +47,11 @@ const Example = Schema.Struct({
|
|
|
47
47
|
}),
|
|
48
48
|
),
|
|
49
49
|
description: Schema.optional(Schema.String).annotations({ title: 'Description' }),
|
|
50
|
-
parent: Schema.optional(Schema.suspend(():
|
|
50
|
+
parent: Schema.optional(Schema.suspend((): Ref.RefSchema<Example> => Ref.Ref(Example))).annotations({
|
|
51
51
|
title: 'Parent',
|
|
52
52
|
}),
|
|
53
53
|
}).pipe(
|
|
54
|
-
Type.
|
|
54
|
+
Type.object({ typename: `com.example.type.${PublicKey.random().truncate()}`, version: '0.1.0' }),
|
|
55
55
|
Annotation.LabelAnnotation.set(['name']),
|
|
56
56
|
);
|
|
57
57
|
interface Example extends Schema.Schema.Type<typeof Example> {}
|
|
@@ -59,12 +59,12 @@ interface Example extends Schema.Schema.Type<typeof Example> {}
|
|
|
59
59
|
const StoryViewEditor = ({
|
|
60
60
|
view,
|
|
61
61
|
schema,
|
|
62
|
-
|
|
62
|
+
db,
|
|
63
63
|
handleDeleteColumn,
|
|
64
64
|
}: {
|
|
65
65
|
view?: View.View;
|
|
66
66
|
schema?: Schema.Schema.AnyNoContext;
|
|
67
|
-
|
|
67
|
+
db?: Database.Database;
|
|
68
68
|
handleDeleteColumn: (fieldId: string) => void;
|
|
69
69
|
}) => {
|
|
70
70
|
const handleQueryChanged = useCallback(
|
|
@@ -73,7 +73,9 @@ const StoryViewEditor = ({
|
|
|
73
73
|
invariant(Type.isMutable(schema));
|
|
74
74
|
schema.updateTypename(getTypenameFromQuery(newQuery));
|
|
75
75
|
invariant(view);
|
|
76
|
-
view
|
|
76
|
+
Obj.change(view, (obj) => {
|
|
77
|
+
obj.query.ast = newQuery as Mutable<typeof newQuery>;
|
|
78
|
+
});
|
|
77
79
|
},
|
|
78
80
|
[schema, view],
|
|
79
81
|
);
|
|
@@ -84,7 +86,7 @@ const StoryViewEditor = ({
|
|
|
84
86
|
|
|
85
87
|
return (
|
|
86
88
|
<ViewEditor
|
|
87
|
-
registry={
|
|
89
|
+
registry={db?.schemaRegistry}
|
|
88
90
|
schema={schema}
|
|
89
91
|
view={view}
|
|
90
92
|
onQueryChanged={handleQueryChanged}
|
|
@@ -98,18 +100,17 @@ const StoryViewEditor = ({
|
|
|
98
100
|
//
|
|
99
101
|
|
|
100
102
|
const DefaultStory = () => {
|
|
101
|
-
const {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
} = useTestTableModel();
|
|
103
|
+
const { db, schema, table, tableRef, model, presentation, handleInsertRow, handleSaveView, handleDeleteColumn } =
|
|
104
|
+
useTestTableModel();
|
|
105
|
+
|
|
106
|
+
const handleRowClick = useCallback(
|
|
107
|
+
(row: any) => {
|
|
108
|
+
if (model?.getDraftRowCount() === 0 && ['frozenRowsEnd', 'fixedEndStart', 'fixedEndEnd'].includes(row?.plane)) {
|
|
109
|
+
handleInsertRow();
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
[model, handleInsertRow],
|
|
113
|
+
);
|
|
113
114
|
|
|
114
115
|
if (!schema || !table?.view.target) {
|
|
115
116
|
return <div />;
|
|
@@ -117,68 +118,76 @@ const DefaultStory = () => {
|
|
|
117
118
|
|
|
118
119
|
return (
|
|
119
120
|
<div className='grow grid grid-cols-[1fr_350px]'>
|
|
120
|
-
<
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
121
|
+
<TableComponent.Root ref={tableRef}>
|
|
122
|
+
<Panel.Root>
|
|
123
|
+
<Panel.Toolbar asChild>
|
|
124
|
+
<TableComponent.Toolbar
|
|
125
|
+
classNames='border-b border-subdued-separator'
|
|
126
|
+
onAdd={handleInsertRow}
|
|
127
|
+
onSave={handleSaveView}
|
|
128
|
+
/>
|
|
129
|
+
</Panel.Toolbar>
|
|
130
|
+
<Panel.Content asChild>
|
|
131
|
+
<TableComponent.Content
|
|
132
|
+
schema={schema}
|
|
133
|
+
model={model}
|
|
134
|
+
presentation={presentation}
|
|
135
|
+
onRowClick={handleRowClick}
|
|
136
|
+
ignoreAttention
|
|
137
|
+
/>
|
|
138
|
+
</Panel.Content>
|
|
139
|
+
</Panel.Root>
|
|
140
|
+
</TableComponent.Root>
|
|
141
|
+
<ScrollArea.Root orientation='vertical' classNames='border-l border-separator'>
|
|
142
|
+
<ScrollArea.Viewport>
|
|
143
|
+
<StoryViewEditor view={table.view.target} schema={schema} db={db} handleDeleteColumn={handleDeleteColumn} />
|
|
144
|
+
<SyntaxHighlighter language='json' className='text-xs'>
|
|
145
|
+
{JSON.stringify({ view: table.view.target, schema }, null, 2)}
|
|
146
|
+
</SyntaxHighlighter>
|
|
147
|
+
</ScrollArea.Viewport>
|
|
148
|
+
</ScrollArea.Root>
|
|
144
149
|
</div>
|
|
145
150
|
);
|
|
146
151
|
};
|
|
147
152
|
|
|
148
|
-
type
|
|
153
|
+
type DefaultStoryProps = { rows?: number };
|
|
149
154
|
|
|
150
155
|
//
|
|
151
156
|
// Story definitions.
|
|
152
157
|
//
|
|
153
158
|
|
|
154
|
-
// TODO(burdon): Need
|
|
159
|
+
// TODO(burdon): Need simpler story.
|
|
155
160
|
|
|
156
161
|
const meta = {
|
|
157
162
|
title: 'ui/react-ui-table/Table',
|
|
158
163
|
render: DefaultStory,
|
|
159
164
|
decorators: [
|
|
160
|
-
withTheme,
|
|
165
|
+
withTheme(),
|
|
166
|
+
withLayout({ layout: 'fullscreen' }),
|
|
167
|
+
withRegistry,
|
|
161
168
|
withClientProvider({
|
|
162
169
|
types: [View.View, Table.Table],
|
|
163
170
|
createIdentity: true,
|
|
164
171
|
createSpace: true,
|
|
165
|
-
onCreateSpace: async ({
|
|
172
|
+
onCreateSpace: async ({ space }) => {
|
|
166
173
|
const [schema] = await space.db.schemaRegistry.register([Example]);
|
|
167
|
-
const { view, jsonSchema } = await
|
|
174
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename: schema.typename });
|
|
168
175
|
const table = Table.make({ view, jsonSchema });
|
|
169
|
-
view
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
Obj.change(view, (obj) => {
|
|
177
|
+
obj.projection.fields = [
|
|
178
|
+
obj.projection.fields.find((field) => field.path === 'name')!,
|
|
179
|
+
...obj.projection.fields.filter((field) => field.path !== 'name'),
|
|
180
|
+
];
|
|
181
|
+
});
|
|
173
182
|
|
|
174
183
|
space.db.add(table);
|
|
175
184
|
|
|
176
185
|
Array.from({ length: 10 }).map(() => {
|
|
177
186
|
return space.db.add(
|
|
178
187
|
Obj.make(schema, {
|
|
179
|
-
name:
|
|
180
|
-
status:
|
|
181
|
-
description:
|
|
188
|
+
name: random.lorem.sentence(),
|
|
189
|
+
status: random.helpers.arrayElement(['todo', 'in-progress', 'done'] as const),
|
|
190
|
+
description: random.lorem.paragraph(),
|
|
182
191
|
}),
|
|
183
192
|
);
|
|
184
193
|
});
|
|
@@ -207,12 +216,15 @@ export const StaticSchema: StoryObj = {
|
|
|
207
216
|
types: [View.View, Table.Table],
|
|
208
217
|
createIdentity: true,
|
|
209
218
|
createSpace: true,
|
|
210
|
-
onCreateSpace: async ({
|
|
211
|
-
const { view, jsonSchema } = await
|
|
219
|
+
onCreateSpace: async ({ space }) => {
|
|
220
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({
|
|
221
|
+
db: space.db,
|
|
222
|
+
typename: TestSchema.Person.typename,
|
|
223
|
+
});
|
|
212
224
|
const table = Table.make({ view, jsonSchema });
|
|
213
225
|
space.db.add(table);
|
|
214
226
|
|
|
215
|
-
const factory = createObjectFactory(space.db,
|
|
227
|
+
const factory = createObjectFactory(space.db, random as any);
|
|
216
228
|
await factory([
|
|
217
229
|
{ type: TestSchema.Person, count: 10 },
|
|
218
230
|
// { type: TestSchema.Organization, count: 1 },
|
|
@@ -237,8 +249,8 @@ const ContactWithArrayOfEmails = Schema.Struct({
|
|
|
237
249
|
),
|
|
238
250
|
),
|
|
239
251
|
}).pipe(
|
|
240
|
-
Type.
|
|
241
|
-
typename: 'dxos.
|
|
252
|
+
Type.object({
|
|
253
|
+
typename: 'org.dxos.type.contactWithArrayOfEmails',
|
|
242
254
|
version: '0.1.0',
|
|
243
255
|
}),
|
|
244
256
|
);
|
|
@@ -250,16 +262,15 @@ export const ArrayOfObjects: StoryObj = {
|
|
|
250
262
|
types: [View.View, Table.Table, TestSchema.Person, TestSchema.Organization, ContactWithArrayOfEmails],
|
|
251
263
|
createIdentity: true,
|
|
252
264
|
createSpace: true,
|
|
253
|
-
onCreateSpace: async ({
|
|
254
|
-
const { view, jsonSchema } = await
|
|
255
|
-
|
|
256
|
-
space,
|
|
265
|
+
onCreateSpace: async ({ space }) => {
|
|
266
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({
|
|
267
|
+
db: space.db,
|
|
257
268
|
typename: ContactWithArrayOfEmails.typename,
|
|
258
269
|
});
|
|
259
270
|
const table = Table.make({ view, jsonSchema });
|
|
260
271
|
space.db.add(table);
|
|
261
272
|
|
|
262
|
-
const factory = createObjectFactory(space.db,
|
|
273
|
+
const factory = createObjectFactory(space.db, random as any);
|
|
263
274
|
await factory([
|
|
264
275
|
// { type: TestSchema.Person, count: 10 },
|
|
265
276
|
// { type: TestSchema.Organization, count: 1 },
|
|
@@ -274,7 +285,7 @@ export const ArrayOfObjects: StoryObj = {
|
|
|
274
285
|
},
|
|
275
286
|
};
|
|
276
287
|
|
|
277
|
-
export const Tags: Meta<
|
|
288
|
+
export const Tags: Meta<DefaultStoryProps> = {
|
|
278
289
|
title: 'ui/react-ui-table/Table',
|
|
279
290
|
render: DefaultStory,
|
|
280
291
|
decorators: [
|
|
@@ -282,9 +293,9 @@ export const Tags: Meta<StoryProps> = {
|
|
|
282
293
|
types: [View.View, Table.Table],
|
|
283
294
|
createIdentity: true,
|
|
284
295
|
createSpace: true,
|
|
285
|
-
onCreateSpace: async ({
|
|
296
|
+
onCreateSpace: async ({ space }) => {
|
|
286
297
|
// Configure schema.
|
|
287
|
-
const typename = 'example.
|
|
298
|
+
const typename = 'com.example.type.single-select';
|
|
288
299
|
const selectOptions = [
|
|
289
300
|
{ id: 'one', title: 'One', color: 'emerald' },
|
|
290
301
|
{ id: 'two', title: 'Two', color: 'blue' },
|
|
@@ -310,7 +321,7 @@ export const Tags: Meta<StoryProps> = {
|
|
|
310
321
|
const [storedSchema] = await space.db.schemaRegistry.register([schema]);
|
|
311
322
|
|
|
312
323
|
// Initialize table.
|
|
313
|
-
const { view, jsonSchema } = await
|
|
324
|
+
const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename });
|
|
314
325
|
const table = Table.make({ view, jsonSchema });
|
|
315
326
|
space.db.add(table);
|
|
316
327
|
|
|
@@ -318,8 +329,8 @@ export const Tags: Meta<StoryProps> = {
|
|
|
318
329
|
Array.from({ length: 10 }).map(() => {
|
|
319
330
|
return space.db.add(
|
|
320
331
|
Obj.make(storedSchema, {
|
|
321
|
-
single:
|
|
322
|
-
multiple:
|
|
332
|
+
single: random.helpers.arrayElement([...selectOptionIds, undefined]),
|
|
333
|
+
multiple: random.helpers.randomSubset(selectOptionIds),
|
|
323
334
|
}),
|
|
324
335
|
);
|
|
325
336
|
});
|