@dxos/react-ui-table 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5
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-BF54SSNL.mjs +70 -0
- package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
- package/dist/lib/browser/{chunk-ZAOSIG3L.mjs → chunk-F7Y374KL.mjs} +739 -802
- package/dist/lib/browser/chunk-F7Y374KL.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1208 -1158
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +34 -43
- 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-ZOFFI3JJ.mjs → chunk-CCJ4LOVM.mjs} +739 -801
- package/dist/lib/node-esm/chunk-CCJ4LOVM.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs +71 -0
- package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1208 -1158
- 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 +34 -43
- 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 +35 -3
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +106 -5
- 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 +21 -19
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +108 -5
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableContent.d.ts +17 -0
- package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts +21 -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 +13 -9
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +7 -14
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +38 -5
- 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/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +23 -16
- 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 +6 -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 -8
- 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 +110 -29
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +4 -2
- 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 -34
- 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 +26 -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 -12
- 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 -1
- 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/schema.d.ts +1 -1
- package/dist/types/src/util/schema.d.ts.map +1 -1
- package/dist/types/src/util/sort.d.ts +12 -0
- package/dist/types/src/util/sort.d.ts.map +1 -0
- package/dist/types/src/util/table-buttons.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +58 -57
- package/src/components/Table/ColumnActionsMenu.tsx +15 -11
- package/src/components/Table/ColumnSettings.tsx +8 -9
- package/src/components/Table/DynamicTable.stories.tsx +36 -34
- package/src/components/Table/DynamicTable.tsx +33 -36
- package/src/components/Table/Relations.stories.tsx +180 -59
- package/src/components/Table/RowActionsMenu.tsx +24 -15
- package/src/components/Table/Table.stories.tsx +152 -129
- package/src/components/Table/Table.tsx +46 -391
- package/src/components/Table/TableContent.tsx +421 -0
- package/src/components/Table/TableToolbar.tsx +111 -0
- package/src/components/TableCellEditor/CellValidationMessage.tsx +5 -5
- package/src/components/TableCellEditor/FormCellEditor.tsx +134 -40
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +35 -72
- package/src/components/TableCellEditor/TableCellEditor.tsx +80 -224
- package/src/components/TableCellEditor/index.ts +1 -0
- package/src/components/index.ts +0 -1
- package/src/components/testing.ts +44 -18
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useAddRow.ts +14 -14
- package/src/hooks/useProjectionModel.ts +39 -0
- package/src/hooks/useTableModel.ts +36 -34
- package/src/model/modal-controller.ts +23 -40
- package/src/model/selection-model.ts +75 -44
- package/src/model/table-model.test.ts +91 -56
- package/src/model/table-model.ts +447 -172
- package/src/model/table-presentation.test.ts +68 -58
- package/src/model/table-presentation.ts +97 -73
- package/src/playwright/TableManager.ts +13 -6
- package/src/playwright/playwright.config.ts +1 -1
- package/src/playwright/smoke.spec.ts +92 -46
- package/src/testing/useTestTableModel.ts +50 -40
- package/src/translations.ts +20 -22
- package/src/types/Table.ts +79 -0
- package/src/types/index.ts +1 -1
- package/src/util/dynamic-table.test.ts +70 -0
- package/src/util/dynamic-table.ts +45 -32
- package/src/util/index.ts +2 -1
- package/src/util/query-ast.ts +22 -0
- package/src/util/schema.ts +4 -4
- package/src/util/sort.ts +90 -0
- package/src/util/table-buttons.ts +3 -3
- package/src/util/table-controls.ts +2 -2
- package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
- package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZAOSIG3L.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +0 -20
- package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ZOFFI3JJ.mjs.map +0 -7
- package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
- package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
- package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
- package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
- 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 -53
- package/dist/types/src/model/table-sorting.d.ts.map +0 -1
- package/dist/types/src/types/schema.d.ts +0 -8
- package/dist/types/src/types/schema.d.ts.map +0 -1
- package/dist/types/src/util/table.d.ts +0 -12
- package/dist/types/src/util/table.d.ts.map +0 -1
- package/src/components/Table/CreateRefPanel.tsx +0 -86
- package/src/components/TableCellEditor/extension.ts +0 -61
- package/src/components/TableToolbar/TableToolbar.tsx +0 -102
- package/src/components/TableToolbar/index.ts +0 -5
- package/src/model/table-sorting.ts +0 -216
- package/src/types/schema.ts +0 -16
- package/src/util/table.ts +0 -53
|
@@ -2,66 +2,62 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
6
|
-
|
|
5
|
+
import { RegistryContext } from '@effect-atom/atom-react';
|
|
7
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
7
|
+
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
8
|
+
import { expect, userEvent, waitFor, within } from 'storybook/test';
|
|
9
|
+
|
|
10
|
+
import { Obj, Type } from '@dxos/echo';
|
|
11
|
+
import { View } from '@dxos/echo';
|
|
12
|
+
import { invariant } from '@dxos/invariant';
|
|
13
|
+
import { type DxGrid } from '@dxos/lit-grid';
|
|
14
|
+
import { random } from '@dxos/random';
|
|
15
|
+
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
16
|
+
import { useAsyncEffect } from '@dxos/react-ui';
|
|
17
|
+
import { translations as formTranslations } from '@dxos/react-ui-form';
|
|
18
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
19
|
+
import { ViewModel } from '@dxos/schema';
|
|
16
20
|
import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
|
|
17
|
-
import {
|
|
21
|
+
import { withRegistry } from '@dxos/storybook-utils';
|
|
22
|
+
import { Organization, Person } from '@dxos/types';
|
|
23
|
+
import '@dxos/lit-ui/dx-tag-picker.pcss';
|
|
18
24
|
|
|
19
|
-
import { useTableModel } from '../../hooks';
|
|
25
|
+
import { useProjectionModel, useTableModel } from '../../hooks';
|
|
20
26
|
import { type TableFeatures, TablePresentation, type TableRow } from '../../model';
|
|
21
27
|
import { translations } from '../../translations';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
import { Table } from './Table';
|
|
28
|
+
import { Table } from '../../types';
|
|
29
|
+
import { Table as TableComponent } from './Table';
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
const generator: ValueGenerator =
|
|
31
|
+
random.seed(1);
|
|
32
|
+
const generator: ValueGenerator = random as any;
|
|
29
33
|
|
|
30
34
|
// TODO(burdon): Many-to-many relations.
|
|
31
35
|
// TODO(burdon): Mutable and immutable views.
|
|
32
36
|
// TODO(burdon): Reconcile schemas types and utils (see API PR).
|
|
33
37
|
// TODO(burdon): Base type for T (with id); see ECHO API PR?
|
|
34
|
-
const useTestModel = <S extends Type.
|
|
35
|
-
const
|
|
36
|
-
const { space } =
|
|
37
|
-
const [
|
|
38
|
-
const [jsonSchema, setJsonSchema] = useState<JsonSchemaType>();
|
|
38
|
+
const useTestModel = <S extends Type.AnyObj>(schema: S, count: number) => {
|
|
39
|
+
const registry = useContext(RegistryContext);
|
|
40
|
+
const { space } = useClientStory();
|
|
41
|
+
const [object, setObject] = useState<Table.Table>();
|
|
39
42
|
|
|
40
43
|
const features = useMemo<TableFeatures>(
|
|
41
44
|
() => ({ schemaEditable: false, dataEditable: true, selection: { enabled: false } }),
|
|
42
45
|
[],
|
|
43
46
|
);
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
useAsyncEffect(async () => {
|
|
46
49
|
if (!space) {
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} = await createTable({ client, space, typename: Type.getTypename(schema) });
|
|
56
|
-
setJsonSchema(jsonSchema);
|
|
57
|
-
setView(view);
|
|
58
|
-
space.db.add(view);
|
|
59
|
-
await space.db.schemaRegistry.register([effectSchema]);
|
|
60
|
-
});
|
|
61
|
-
return () => clearTimeout(timeout);
|
|
62
|
-
}, [client, space, schema]);
|
|
53
|
+
const { view, jsonSchema } = await ViewModel.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,46 +75,171 @@ 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 {
|
|
85
|
+
const { model: orgModel, presentation: orgPresentation } = useTestModel(Organization.Organization, 50);
|
|
86
|
+
const { model: contactModel, presentation: contactPresentation } = useTestModel(Person.Person, 50);
|
|
87
|
+
const { space } = useClientStory();
|
|
88
|
+
|
|
89
|
+
const handleCreate = useCallback(
|
|
90
|
+
(schema: Type.AnyEntity, values: any) => {
|
|
91
|
+
invariant(Type.isObjectSchema(schema));
|
|
92
|
+
invariant(space);
|
|
93
|
+
return space.db.add(Obj.make(schema, values));
|
|
94
|
+
},
|
|
95
|
+
[space],
|
|
96
|
+
);
|
|
92
97
|
|
|
93
98
|
return (
|
|
94
|
-
<div className='
|
|
95
|
-
<
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
<div className='dx-expander grid grid-cols-2 divide-x divide-separator'>
|
|
100
|
+
<TableComponent.Root>
|
|
101
|
+
<TableComponent.Content
|
|
102
|
+
model={orgModel}
|
|
103
|
+
schema={Organization.Organization}
|
|
104
|
+
presentation={orgPresentation}
|
|
105
|
+
onCreate={handleCreate}
|
|
106
|
+
ignoreAttention
|
|
107
|
+
testId='relations-0'
|
|
108
|
+
/>
|
|
109
|
+
</TableComponent.Root>
|
|
110
|
+
<TableComponent.Root>
|
|
111
|
+
<TableComponent.Content
|
|
112
|
+
model={contactModel}
|
|
113
|
+
schema={Person.Person}
|
|
114
|
+
presentation={contactPresentation}
|
|
115
|
+
onCreate={handleCreate}
|
|
116
|
+
ignoreAttention
|
|
117
|
+
testId='relations-1'
|
|
118
|
+
/>
|
|
119
|
+
</TableComponent.Root>
|
|
101
120
|
</div>
|
|
102
121
|
);
|
|
103
122
|
};
|
|
104
123
|
|
|
105
|
-
const meta
|
|
106
|
-
title: 'ui/react-ui-table/
|
|
124
|
+
const meta = {
|
|
125
|
+
title: 'ui/react-ui-table/Relations',
|
|
107
126
|
render: DefaultStory,
|
|
108
|
-
parameters: { translations, controls: { disable: true } },
|
|
109
127
|
decorators: [
|
|
128
|
+
withTheme(),
|
|
129
|
+
withRegistry,
|
|
130
|
+
// TODO(thure): Shouldn't `layout: 'fullscreen'` below make this unnecessary?
|
|
131
|
+
withLayout({ classNames: 'fixed inset-0' }),
|
|
110
132
|
withClientProvider({
|
|
111
|
-
types: [
|
|
133
|
+
types: [View.View, Organization.Organization, Person.Person, Table.Table],
|
|
112
134
|
createIdentity: true,
|
|
113
135
|
createSpace: true,
|
|
114
136
|
}),
|
|
115
|
-
withTheme,
|
|
116
|
-
withLayout({ fullscreen: true }),
|
|
117
137
|
],
|
|
118
|
-
|
|
138
|
+
parameters: {
|
|
139
|
+
layout: 'fullscreen',
|
|
140
|
+
controls: { disable: true },
|
|
141
|
+
translations: [...translations, ...formTranslations],
|
|
142
|
+
},
|
|
143
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
119
144
|
|
|
120
145
|
export default meta;
|
|
121
146
|
|
|
122
|
-
type Story = StoryObj<typeof
|
|
147
|
+
type Story = StoryObj<typeof meta>;
|
|
148
|
+
|
|
149
|
+
export const Default: Story = {
|
|
150
|
+
play: async ({ canvasElement }) => {
|
|
151
|
+
const canvas = within(canvasElement);
|
|
152
|
+
const body = within(document.body);
|
|
153
|
+
|
|
154
|
+
// Get all dx-grid elements (should have 2 - one for each table)
|
|
155
|
+
const firstGrid = await canvas.findByTestId('relations-0', undefined, { timeout: 30_000 });
|
|
156
|
+
const secondGrid = await canvas.findByTestId('relations-1', undefined, { timeout: 30_000 });
|
|
157
|
+
|
|
158
|
+
// Focus on the second table (Person/contacts table)
|
|
159
|
+
await expect(secondGrid).toBeVisible();
|
|
160
|
+
|
|
161
|
+
// Scroll to the relations column (column 4) - this mimics the scrollToColumn call
|
|
162
|
+
(secondGrid.closest('dx-grid') as DxGrid).scrollToColumn(4);
|
|
163
|
+
|
|
164
|
+
// Find and click the target cell (first row, relations column)
|
|
165
|
+
const targetCell = await within(secondGrid).findByTestId('grid.4.0', undefined, { timeout: 10_000 });
|
|
166
|
+
await expect(targetCell).toBeVisible();
|
|
167
|
+
|
|
168
|
+
// Click to focus the cell
|
|
169
|
+
await userEvent.click(targetCell as HTMLElement);
|
|
170
|
+
await expect(targetCell).toHaveFocus();
|
|
171
|
+
await userEvent.keyboard('{Enter}');
|
|
172
|
+
|
|
173
|
+
// Look for the combobox that should appear in edit mode
|
|
174
|
+
const combobox = await body.findByRole('combobox', undefined, { timeout: 5000 });
|
|
175
|
+
await userEvent.click(combobox);
|
|
176
|
+
|
|
177
|
+
const searchField = await body.findByPlaceholderText('Search…');
|
|
178
|
+
await userEvent.click(searchField);
|
|
179
|
+
|
|
180
|
+
// Get the first organization name from the first table to search for
|
|
181
|
+
const orgCell = await within(firstGrid).findByTestId('grid.0.0', undefined, { timeout: 10_000 });
|
|
123
182
|
|
|
124
|
-
|
|
183
|
+
const orgName = (orgCell.querySelector('.dx-grid__cell__content') as HTMLElement).textContent;
|
|
184
|
+
// Type the first 4 characters to search
|
|
185
|
+
await userEvent.type(searchField, orgName.substring(0, 4));
|
|
186
|
+
|
|
187
|
+
// Look for an option to select
|
|
188
|
+
const option = await body.findAllByRole('option');
|
|
189
|
+
await expect(option[0]).toBeVisible();
|
|
190
|
+
|
|
191
|
+
// Press Enter to select
|
|
192
|
+
await userEvent.keyboard('{Enter}');
|
|
193
|
+
|
|
194
|
+
// Look for and click save button
|
|
195
|
+
const saveButton = await body.findByTestId('save-button');
|
|
196
|
+
await userEvent.click(saveButton);
|
|
197
|
+
|
|
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
|
+
);
|
|
207
|
+
|
|
208
|
+
// Test object creation (new relations) - equivalent to "new relations work as expected" test
|
|
209
|
+
// Find a different cell to test object creation (second row, relations column)
|
|
210
|
+
const newTargetCell = await within(secondGrid).findByTestId('grid.4.1', undefined, { timeout: 10_000 });
|
|
211
|
+
await expect(newTargetCell).toBeTruthy();
|
|
212
|
+
|
|
213
|
+
// Click to focus the cell
|
|
214
|
+
await userEvent.click(newTargetCell as Element);
|
|
215
|
+
|
|
216
|
+
await userEvent.keyboard('{Enter}');
|
|
217
|
+
|
|
218
|
+
// Look for the combobox that should appear in edit mode
|
|
219
|
+
const newCombobox = await body.findByRole('combobox');
|
|
220
|
+
await userEvent.click(newCombobox);
|
|
221
|
+
|
|
222
|
+
const newSearchField = await body.findByPlaceholderText('Search…');
|
|
223
|
+
await userEvent.click(newSearchField);
|
|
224
|
+
|
|
225
|
+
// Type a new object name (this will create a new object).
|
|
226
|
+
const newOrgName = 'Salieri LLC';
|
|
227
|
+
await userEvent.type(newSearchField, newOrgName);
|
|
228
|
+
|
|
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);
|
|
232
|
+
|
|
233
|
+
// Look for and click save button.
|
|
234
|
+
const createReferencedObjectForm = await body.findByTestId('create-referenced-object-form', undefined, {
|
|
235
|
+
timeout: 2000,
|
|
236
|
+
});
|
|
237
|
+
const saveObjectButton = await within(createReferencedObjectForm).findByTestId('save-button');
|
|
238
|
+
await expect(saveObjectButton).not.toBeDisabled();
|
|
239
|
+
await userEvent.click(saveObjectButton);
|
|
240
|
+
|
|
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();
|
|
244
|
+
},
|
|
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
|
}
|
|
@@ -23,24 +24,32 @@ export const RowActionsMenu = ({ model, modals }: RowActionsMenuProps) => {
|
|
|
23
24
|
<DropdownMenu.VirtualTrigger virtualRef={modals.trigger} />
|
|
24
25
|
<DropdownMenu.Content>
|
|
25
26
|
<DropdownMenu.Viewport>
|
|
27
|
+
{/* Custom actions */}
|
|
28
|
+
{model.rowActions?.length > 0 && (
|
|
29
|
+
<>
|
|
30
|
+
<DropdownMenu.Group>
|
|
31
|
+
{model.rowActions?.map((action) => (
|
|
32
|
+
<DropdownMenu.Item
|
|
33
|
+
key={action.id}
|
|
34
|
+
data-testid={`row-action-${action.id}`}
|
|
35
|
+
onClick={() => {
|
|
36
|
+
modals.close();
|
|
37
|
+
model.handleRowAction(action.id, state.rowIndex);
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
{toLocalizedString(action.label, t)}
|
|
41
|
+
</DropdownMenu.Item>
|
|
42
|
+
))}
|
|
43
|
+
</DropdownMenu.Group>
|
|
44
|
+
<DropdownMenu.Separator />
|
|
45
|
+
</>
|
|
46
|
+
)}
|
|
47
|
+
{/* Default actions */}
|
|
26
48
|
{model.features.dataEditable !== false && (
|
|
27
49
|
<DropdownMenu.Item data-testid='row-menu-delete' onClick={() => model.deleteRow(state.rowIndex)}>
|
|
28
50
|
{t(hasSelection ? 'bulk delete row label' : 'delete row label')}
|
|
29
51
|
</DropdownMenu.Item>
|
|
30
52
|
)}
|
|
31
|
-
{/* Custom actions */}
|
|
32
|
-
{model.rowActions?.map((action) => (
|
|
33
|
-
<DropdownMenu.Item
|
|
34
|
-
key={action.id}
|
|
35
|
-
data-testid={`row-action-${action.id}`}
|
|
36
|
-
onClick={() => {
|
|
37
|
-
modals.close();
|
|
38
|
-
model.handleRowAction(action.id, state.rowIndex);
|
|
39
|
-
}}
|
|
40
|
-
>
|
|
41
|
-
{toLocalizedString(action.label, t)}
|
|
42
|
-
</DropdownMenu.Item>
|
|
43
|
-
))}
|
|
44
53
|
</DropdownMenu.Viewport>
|
|
45
54
|
<DropdownMenu.Arrow />
|
|
46
55
|
</DropdownMenu.Content>
|