@dxos/react-ui-table 0.8.2-main.fbd8ed0 → 0.8.2-staging.7ac8446
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-PFFO5LYM.mjs → chunk-YWNRUF4J.mjs} +6 -7
- package/dist/lib/browser/chunk-YWNRUF4J.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +181 -330
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node/{chunk-VREQOYRW.cjs → chunk-TGG6OZ54.cjs} +8 -9
- package/dist/lib/node/chunk-TGG6OZ54.cjs.map +7 -0
- package/dist/lib/node/index.cjs +160 -306
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +3 -3
- package/dist/lib/node/types/index.cjs.map +1 -1
- package/dist/lib/node-esm/{chunk-34JG3SDI.mjs → chunk-KKLP54L3.mjs} +6 -7
- package/dist/lib/node-esm/chunk-KKLP54L3.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +181 -330
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/types/index.mjs +1 -1
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts +4 -3
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/RefPanel.d.ts +9 -0
- package/dist/types/src/components/Table/RefPanel.d.ts.map +1 -0
- package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +0 -2
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +0 -1
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +0 -3
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/extension.d.ts.map +1 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +2 -2
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +40 -40
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useTableModel.d.ts +2 -2
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/modal-controller.d.ts +3 -3
- package/dist/types/src/model/modal-controller.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/types/table.d.ts +43 -44
- package/dist/types/src/types/table.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/index.d.ts +0 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/signals.d.ts.map +1 -1
- package/dist/types/src/util/table-buttons.d.ts +14 -0
- package/dist/types/src/util/table-buttons.d.ts.map +1 -1
- package/dist/types/src/util/table-controls.d.ts.map +1 -1
- package/dist/types/src/util/table.d.ts +2 -2
- package/dist/types/src/util/table.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +33 -34
- package/src/components/Table/CreateRefPanel.tsx +5 -5
- package/src/components/Table/DynamicTable.stories.tsx +4 -4
- package/src/components/Table/DynamicTable.tsx +5 -4
- package/src/components/Table/RefPanel.tsx +52 -0
- package/src/components/Table/Table.stories.tsx +27 -73
- package/src/components/Table/Table.tsx +28 -25
- package/src/components/Table/relations.stories.tsx +31 -38
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +10 -11
- package/src/components/TableCellEditor/TableCellEditor.tsx +4 -45
- package/src/components/TableToolbar/TableToolbar.tsx +13 -12
- package/src/components/testing.ts +9 -10
- package/src/hooks/useTableModel.ts +2 -2
- package/src/model/modal-controller.ts +3 -3
- package/src/model/table-model.test.ts +6 -7
- package/src/model/table-model.ts +2 -19
- package/src/model/table-presentation.test.ts +6 -7
- package/src/model/table-presentation.ts +10 -54
- package/src/types/table.ts +7 -15
- package/src/util/dynamic-table.ts +6 -9
- package/src/util/index.ts +0 -1
- package/src/util/table-buttons.ts +23 -0
- package/src/util/table.ts +16 -13
- package/dist/lib/browser/chunk-PFFO5LYM.mjs.map +0 -7
- package/dist/lib/node/chunk-VREQOYRW.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-34JG3SDI.mjs.map +0 -7
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +0 -13
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +0 -1
- package/dist/types/src/util/schema.d.ts +0 -12
- package/dist/types/src/util/schema.d.ts.map +0 -1
- package/dist/types/src/util/tag.d.ts +0 -11
- package/dist/types/src/util/tag.d.ts.map +0 -1
- package/src/components/TableCellEditor/FormCellEditor.tsx +0 -94
- package/src/util/schema.ts +0 -36
- package/src/util/tag.ts +0 -33
|
@@ -5,22 +5,14 @@
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
7
|
import { type StoryObj, type Meta } from '@storybook/react';
|
|
8
|
-
import { Schema } from 'effect';
|
|
9
8
|
import React, { useCallback, useMemo, useRef } from 'react';
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
assertEchoSchema,
|
|
13
|
-
FormatEnum,
|
|
14
|
-
isMutable,
|
|
15
|
-
toJsonSchema,
|
|
16
|
-
EchoObject,
|
|
17
|
-
GeneratorAnnotationId,
|
|
18
|
-
} from '@dxos/echo-schema';
|
|
10
|
+
import { FormatEnum, ImmutableSchema } from '@dxos/echo-schema';
|
|
19
11
|
import { invariant } from '@dxos/invariant';
|
|
20
12
|
import { useGlobalFilteredObjects } from '@dxos/plugin-search';
|
|
21
13
|
import { faker } from '@dxos/random';
|
|
22
14
|
import { useClient } from '@dxos/react-client';
|
|
23
|
-
import { Filter, useQuery, useSchema,
|
|
15
|
+
import { Filter, useQuery, useSchema, create } from '@dxos/react-client/echo';
|
|
24
16
|
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
25
17
|
import { ViewEditor } from '@dxos/react-ui-form';
|
|
26
18
|
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
@@ -36,7 +28,8 @@ import { TableType } from '../../types';
|
|
|
36
28
|
import { initializeTable } from '../../util';
|
|
37
29
|
import { TableToolbar } from '../TableToolbar';
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
// NOTE(ZaymonFC): We rely on this seed being 0 in the smoke tests.
|
|
32
|
+
faker.seed(0);
|
|
40
33
|
|
|
41
34
|
/**
|
|
42
35
|
* Custom hook to create and manage a test table model for storybook demonstrations.
|
|
@@ -46,14 +39,14 @@ const useTestTableModel = () => {
|
|
|
46
39
|
const client = useClient();
|
|
47
40
|
const { space } = useClientProvider();
|
|
48
41
|
|
|
49
|
-
const filter = useMemo(() => Filter.
|
|
42
|
+
const filter = useMemo(() => Filter.schema(TableType), []);
|
|
50
43
|
const tables = useQuery(space, filter);
|
|
51
44
|
const table = useMemo(() => tables.at(0), [tables]);
|
|
52
45
|
const schema = useSchema(client, space, table?.view?.target?.query.typename);
|
|
53
46
|
|
|
54
47
|
const projection = useMemo(() => {
|
|
55
48
|
if (schema && table?.view?.target) {
|
|
56
|
-
return new ViewProjection(
|
|
49
|
+
return new ViewProjection(schema.jsonSchema, table.view.target);
|
|
57
50
|
}
|
|
58
51
|
}, [schema, table?.view?.target]);
|
|
59
52
|
|
|
@@ -61,12 +54,12 @@ const useTestTableModel = () => {
|
|
|
61
54
|
() => ({
|
|
62
55
|
selection: { enabled: true, mode: 'multiple' as const },
|
|
63
56
|
dataEditable: true,
|
|
64
|
-
schemaEditable: schema
|
|
57
|
+
schemaEditable: !(schema instanceof ImmutableSchema),
|
|
65
58
|
}),
|
|
66
59
|
[schema],
|
|
67
60
|
);
|
|
68
61
|
|
|
69
|
-
const objects = useQuery(space, schema ? Filter.
|
|
62
|
+
const objects = useQuery(space, schema ? Filter.schema(schema) : Filter.nothing());
|
|
70
63
|
const filteredObjects = useGlobalFilteredObjects(objects);
|
|
71
64
|
|
|
72
65
|
const tableRef = useRef<TableController>(null);
|
|
@@ -80,7 +73,7 @@ const useTestTableModel = () => {
|
|
|
80
73
|
|
|
81
74
|
const handleInsertRow = useCallback(() => {
|
|
82
75
|
if (space && schema) {
|
|
83
|
-
space.db.add(
|
|
76
|
+
space.db.add(create(schema, {}));
|
|
84
77
|
}
|
|
85
78
|
}, [space, schema]);
|
|
86
79
|
|
|
@@ -158,10 +151,11 @@ const StoryViewEditor = () => {
|
|
|
158
151
|
|
|
159
152
|
const handleTypenameChanged = useCallback(
|
|
160
153
|
(typename: string) => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
if (table?.view?.target) {
|
|
155
|
+
invariant(schema);
|
|
156
|
+
schema.mutable.updateTypename(typename);
|
|
157
|
+
table.view.target.query.typename = typename;
|
|
158
|
+
}
|
|
165
159
|
},
|
|
166
160
|
[schema, table?.view?.target],
|
|
167
161
|
);
|
|
@@ -197,7 +191,7 @@ const DefaultStory = () => {
|
|
|
197
191
|
<div className='grid grid-rows-[min-content_1fr] min-bs-0 overflow-hidden'>
|
|
198
192
|
<TableToolbar classNames='border-be border-separator' onAction={handleToolbarAction} />
|
|
199
193
|
<Table.Root>
|
|
200
|
-
<Table.Main ref={tableRef} model={model} presentation={presentation}
|
|
194
|
+
<Table.Main ref={tableRef} model={model} presentation={presentation} ignoreAttention />
|
|
201
195
|
</Table.Root>
|
|
202
196
|
</div>
|
|
203
197
|
<div className='flex flex-col h-full border-l border-separator overflow-y-auto'>
|
|
@@ -228,19 +222,19 @@ const meta: Meta<StoryProps> = {
|
|
|
228
222
|
createIdentity: true,
|
|
229
223
|
createSpace: true,
|
|
230
224
|
onSpaceCreated: async ({ client, space }) => {
|
|
231
|
-
const table = space.db.add(
|
|
225
|
+
const table = space.db.add(create(TableType, {}));
|
|
232
226
|
const schema = await initializeTable({ client, space, table, initialRow: false });
|
|
233
227
|
Array.from({ length: 10 }).map(() => {
|
|
234
228
|
return space.db.add(
|
|
235
|
-
|
|
229
|
+
create(schema, {
|
|
236
230
|
name: faker.person.fullName(),
|
|
237
231
|
}),
|
|
238
232
|
);
|
|
239
233
|
});
|
|
240
234
|
},
|
|
241
235
|
}),
|
|
242
|
-
withLayout({ fullscreen: true }),
|
|
243
236
|
withTheme,
|
|
237
|
+
withLayout({ fullscreen: true, tooltips: true }),
|
|
244
238
|
],
|
|
245
239
|
};
|
|
246
240
|
|
|
@@ -253,62 +247,22 @@ export const StaticSchema: StoryObj = {
|
|
|
253
247
|
parameters: { translations },
|
|
254
248
|
decorators: [
|
|
255
249
|
withClientProvider({
|
|
256
|
-
types: [TableType, ViewType, Testing.Contact, Testing.
|
|
257
|
-
createIdentity: true,
|
|
258
|
-
createSpace: true,
|
|
259
|
-
onSpaceCreated: async ({ client, space }) => {
|
|
260
|
-
const table = space.db.add(live(TableType, {}));
|
|
261
|
-
await initializeTable({ client, space, table, typename: Testing.Organization.typename });
|
|
262
|
-
|
|
263
|
-
const factory = createObjectFactory(space.db, faker as any);
|
|
264
|
-
await factory([
|
|
265
|
-
// { type: Testing.Contact, count: 10 },
|
|
266
|
-
// { type: Testing.Organization, count: 1 },
|
|
267
|
-
{ type: ContactWithArrayOfEmails, count: 10 },
|
|
268
|
-
]);
|
|
269
|
-
},
|
|
270
|
-
}),
|
|
271
|
-
withLayout({ fullscreen: true }),
|
|
272
|
-
withTheme,
|
|
273
|
-
],
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const ContactWithArrayOfEmails = Schema.Struct({
|
|
277
|
-
name: Schema.String.annotations({
|
|
278
|
-
[GeneratorAnnotationId]: 'person.fullName',
|
|
279
|
-
}),
|
|
280
|
-
emails: Schema.optional(
|
|
281
|
-
Schema.Array(
|
|
282
|
-
Schema.Struct({
|
|
283
|
-
value: Schema.String,
|
|
284
|
-
label: Schema.String.pipe(Schema.optional),
|
|
285
|
-
}),
|
|
286
|
-
),
|
|
287
|
-
),
|
|
288
|
-
}).pipe(EchoObject({ typename: 'dxos.org/type/ContactWithArrayOfEmails', version: '0.1.0' }));
|
|
289
|
-
|
|
290
|
-
export const ArrayOfObjects: StoryObj = {
|
|
291
|
-
render: DefaultStory,
|
|
292
|
-
parameters: { translations },
|
|
293
|
-
decorators: [
|
|
294
|
-
withClientProvider({
|
|
295
|
-
types: [TableType, ViewType, Testing.Contact, Testing.Organization, ContactWithArrayOfEmails],
|
|
250
|
+
types: [TableType, ViewType, Testing.Contact, Testing.Org],
|
|
296
251
|
createIdentity: true,
|
|
297
252
|
createSpace: true,
|
|
298
253
|
onSpaceCreated: async ({ client, space }) => {
|
|
299
|
-
const table = space.db.add(
|
|
300
|
-
await initializeTable({ client, space, table, typename:
|
|
254
|
+
const table = space.db.add(create(TableType, {}));
|
|
255
|
+
await initializeTable({ client, space, table, typename: Testing.Contact.typename });
|
|
301
256
|
|
|
302
257
|
const factory = createObjectFactory(space.db, faker as any);
|
|
303
258
|
await factory([
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
{ type: ContactWithArrayOfEmails, count: 10 },
|
|
259
|
+
{ type: Testing.Contact, count: 10 },
|
|
260
|
+
{ type: Testing.Org, count: 1 },
|
|
307
261
|
]);
|
|
308
262
|
},
|
|
309
263
|
}),
|
|
310
|
-
withLayout({ fullscreen: true }),
|
|
311
264
|
withTheme,
|
|
265
|
+
withLayout({ fullscreen: true, tooltips: true }),
|
|
312
266
|
],
|
|
313
267
|
};
|
|
314
268
|
|
|
@@ -349,13 +303,13 @@ export const Tags: Meta<StoryProps> = {
|
|
|
349
303
|
const [storedSchema] = await space.db.schemaRegistry.register([schema]);
|
|
350
304
|
|
|
351
305
|
// Initialize table.
|
|
352
|
-
const table = space.db.add(
|
|
306
|
+
const table = space.db.add(create(TableType, {}));
|
|
353
307
|
await initializeTable({ client, space, table, initialRow: false, typename });
|
|
354
308
|
|
|
355
309
|
// Populate.
|
|
356
310
|
Array.from({ length: 10 }).map(() => {
|
|
357
311
|
return space.db.add(
|
|
358
|
-
|
|
312
|
+
create(storedSchema, {
|
|
359
313
|
single: faker.helpers.arrayElement([...selectOptionIds, undefined]),
|
|
360
314
|
multiple: faker.helpers.randomSubset(selectOptionIds),
|
|
361
315
|
}),
|
|
@@ -363,7 +317,7 @@ export const Tags: Meta<StoryProps> = {
|
|
|
363
317
|
});
|
|
364
318
|
},
|
|
365
319
|
}),
|
|
366
|
-
withLayout({ fullscreen: true }),
|
|
367
320
|
withTheme,
|
|
321
|
+
withLayout({ fullscreen: true, tooltips: true }),
|
|
368
322
|
],
|
|
369
323
|
};
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Schema } from 'effect/Schema';
|
|
6
5
|
import React, {
|
|
7
6
|
type MouseEvent,
|
|
8
7
|
type PropsWithChildren,
|
|
@@ -20,28 +19,26 @@ import { invariant } from '@dxos/invariant';
|
|
|
20
19
|
import { Filter } from '@dxos/react-client/echo';
|
|
21
20
|
import { useTranslation } from '@dxos/react-ui';
|
|
22
21
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
23
|
-
import {
|
|
24
|
-
closestCell,
|
|
25
|
-
type DxGridElement,
|
|
26
|
-
type DxGridPosition,
|
|
27
|
-
type GridContentProps,
|
|
28
|
-
Grid,
|
|
29
|
-
type DxGridPlane,
|
|
30
|
-
type DxGridPlaneRange,
|
|
31
|
-
gridSeparatorInlineEnd,
|
|
32
|
-
gridSeparatorBlockEnd,
|
|
33
|
-
} from '@dxos/react-ui-grid';
|
|
22
|
+
import { closestCell, type DxGridElement, type DxGridPosition, type GridContentProps, Grid } from '@dxos/react-ui-grid';
|
|
34
23
|
import { mx } from '@dxos/react-ui-theme';
|
|
35
24
|
import { isNotFalsy, safeParseInt } from '@dxos/util';
|
|
36
25
|
|
|
37
26
|
import { ColumnActionsMenu } from './ColumnActionsMenu';
|
|
38
27
|
import { ColumnSettings } from './ColumnSettings';
|
|
39
28
|
import { CreateRefPanel } from './CreateRefPanel';
|
|
29
|
+
import { RefPanel } from './RefPanel';
|
|
40
30
|
import { RowActionsMenu } from './RowActionsMenu';
|
|
41
31
|
import { ModalController, type TableModel, type TablePresentation } from '../../model';
|
|
42
32
|
import { translationKey } from '../../translations';
|
|
43
33
|
import { tableButtons, tableControls } from '../../util';
|
|
44
|
-
import { createOption,
|
|
34
|
+
import { createOption, TableCellEditor, type TableCellEditorProps } from '../TableCellEditor';
|
|
35
|
+
|
|
36
|
+
// NOTE(Zan): These fragments add border to inline-end and block-end of the grid using pseudo-elements.
|
|
37
|
+
// These are offset by 1px to avoid double borders in planks.
|
|
38
|
+
const inlineEndLine =
|
|
39
|
+
'[&>.dx-grid]:relative [&>.dx-grid]:after:absolute [&>.dx-grid]:after:inset-block-0 [&>.dx-grid]:after:-inline-end-px [&>.dx-grid]:after:is-px [&>.dx-grid]:after:bg-separator';
|
|
40
|
+
const blockEndLine =
|
|
41
|
+
'[&>.dx-grid]:before:absolute [&>.dx-grid]:before:inset-inline-0 [&>.dx-grid]:before:-block-end-px [&>.dx-grid]:before:bs-px [&>.dx-grid]:before:bg-separator';
|
|
45
42
|
|
|
46
43
|
//
|
|
47
44
|
// Table.Root
|
|
@@ -76,14 +73,13 @@ export type TableController = {
|
|
|
76
73
|
export type TableMainProps = {
|
|
77
74
|
model?: TableModel;
|
|
78
75
|
presentation?: TablePresentation;
|
|
79
|
-
schema?: Schema.AnyNoContext;
|
|
80
76
|
// TODO(burdon): Rename since attention isn't a useful concept here? Standardize across other components. Pass property into useAttention.
|
|
81
77
|
ignoreAttention?: boolean;
|
|
82
78
|
onRowClick?: (row: any) => void;
|
|
83
79
|
};
|
|
84
80
|
|
|
85
81
|
const TableMain = forwardRef<TableController, TableMainProps>(
|
|
86
|
-
({ model, presentation, ignoreAttention,
|
|
82
|
+
({ model, presentation, ignoreAttention, onRowClick }, forwardedRef) => {
|
|
87
83
|
const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
|
|
88
84
|
const { hasAttention } = useAttention(model?.id ?? 'table');
|
|
89
85
|
const { t } = useTranslation(translationKey);
|
|
@@ -102,17 +98,20 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
102
98
|
};
|
|
103
99
|
}, [model]);
|
|
104
100
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
// TODO(burdon): Replace useEffect below.
|
|
102
|
+
// const getCells = useCallback<GridContentProps['getCells']>(
|
|
103
|
+
// (range: DxGridRange, plane: DxGridPlane) => presentation?.getCells(range, plane) ?? {},
|
|
104
|
+
// [presentation],
|
|
105
|
+
// );
|
|
109
106
|
|
|
110
107
|
useEffect(() => {
|
|
111
108
|
if (!presentation || !dxGrid) {
|
|
112
109
|
return;
|
|
113
110
|
}
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
|
|
112
|
+
// TODO(burdon): Pass to Grid.Content?
|
|
113
|
+
dxGrid.getCells = (range, plane) => presentation.getCells(range, plane);
|
|
114
|
+
}, [presentation, dxGrid]);
|
|
116
115
|
|
|
117
116
|
/**
|
|
118
117
|
* Provides an external controller that can be called to repaint the table.
|
|
@@ -182,6 +181,10 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
182
181
|
modals.showColumnCreator();
|
|
183
182
|
break;
|
|
184
183
|
}
|
|
184
|
+
case 'referencedCell': {
|
|
185
|
+
modals.showReferencePanel(data.targetId, data.schemaId);
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
185
188
|
case 'sort': {
|
|
186
189
|
model?.sorting?.toggleSort(data.fieldId);
|
|
187
190
|
break;
|
|
@@ -309,7 +312,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
309
312
|
invariant(space);
|
|
310
313
|
const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
|
|
311
314
|
if (schema) {
|
|
312
|
-
const { objects } = await space.db.query(Filter.
|
|
315
|
+
const { objects } = await space.db.query(Filter.schema(schema)).run();
|
|
313
316
|
const options = objects
|
|
314
317
|
.map((obj) => {
|
|
315
318
|
const value = getValue(obj, field.referencePath!);
|
|
@@ -345,16 +348,15 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
345
348
|
|
|
346
349
|
return (
|
|
347
350
|
<Grid.Root id={model.id ?? 'table-grid'}>
|
|
348
|
-
<
|
|
351
|
+
<TableCellEditor
|
|
349
352
|
model={model}
|
|
350
353
|
modals={modals}
|
|
351
|
-
schema={schema}
|
|
352
354
|
onEnter={handleEnter}
|
|
353
355
|
onFocus={handleFocus}
|
|
354
356
|
onQuery={handleQuery}
|
|
355
357
|
/>
|
|
356
358
|
<Grid.Content
|
|
357
|
-
className={mx('[--dx-grid-base:var(--
|
|
359
|
+
className={mx('[--dx-grid-base:var(--surface-bg)]', inlineEndLine, blockEndLine)}
|
|
358
360
|
frozen={frozen}
|
|
359
361
|
// getCells={getCells}
|
|
360
362
|
columns={model.columnMeta.value}
|
|
@@ -371,6 +373,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
371
373
|
<ColumnActionsMenu model={model} modals={modals} />
|
|
372
374
|
<ColumnSettings model={model} modals={modals} onNewColumn={handleNewColumn} />
|
|
373
375
|
<CreateRefPanel model={model} modals={modals} />
|
|
376
|
+
<RefPanel model={model} modals={modals} />
|
|
374
377
|
</Grid.Root>
|
|
375
378
|
);
|
|
376
379
|
},
|
|
@@ -5,23 +5,20 @@
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
7
|
import { type StoryObj, type Meta } from '@storybook/react';
|
|
8
|
-
import { type Schema } from 'effect';
|
|
9
|
-
import { SchemaAST } from 'effect';
|
|
10
8
|
import React, { useEffect, useMemo } from 'react';
|
|
11
9
|
|
|
12
|
-
import { type BaseObject,
|
|
10
|
+
import { AST, type BaseObject, ImmutableSchema, type BaseSchema, type HasId } from '@dxos/echo-schema';
|
|
13
11
|
import { getAnnotation } from '@dxos/effect';
|
|
14
|
-
import { invariant } from '@dxos/invariant';
|
|
15
12
|
import { faker } from '@dxos/random';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
13
|
+
import { create, makeRef, type ReactiveObject } from '@dxos/react-client/echo';
|
|
14
|
+
import { withClientProvider } from '@dxos/react-client/testing';
|
|
15
|
+
import { createView, ViewProjection, ViewType } from '@dxos/schema';
|
|
16
|
+
import { createGenerator, Testing, type ValueGenerator } from '@dxos/schema/testing';
|
|
20
17
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
21
18
|
|
|
22
19
|
import { Table } from './Table';
|
|
23
20
|
import { useTableModel } from '../../hooks';
|
|
24
|
-
import {
|
|
21
|
+
import { TablePresentation } from '../../model';
|
|
25
22
|
import translations from '../../translations';
|
|
26
23
|
import { TableType } from '../../types';
|
|
27
24
|
|
|
@@ -32,16 +29,13 @@ const generator: ValueGenerator = faker as any;
|
|
|
32
29
|
// TODO(burdon): Mutable and immutable views.
|
|
33
30
|
// TODO(burdon): Reconcile schemas types and utils (see API PR).
|
|
34
31
|
// TODO(burdon): Base type for T (with id); see ECHO API PR?
|
|
35
|
-
const useTestModel = <T extends BaseObject & HasId>(schema:
|
|
36
|
-
const { space } = useClientProvider();
|
|
37
|
-
|
|
38
|
-
const jsonSchema = useMemo(() => toJsonSchema(schema), [schema]);
|
|
32
|
+
const useTestModel = <T extends BaseObject & HasId>(schema: BaseSchema<T>, count: number) => {
|
|
39
33
|
const table = useMemo(() => {
|
|
40
|
-
const typename =
|
|
41
|
-
|
|
42
|
-
const name = getAnnotation<string>(
|
|
43
|
-
const view = createView({ name, typename, jsonSchema });
|
|
44
|
-
return
|
|
34
|
+
// const { typename } = pipe(schema.ast, AST.getAnnotation<TypeAnnotation>(TypeAnnotationId), Option.getOrThrow);
|
|
35
|
+
const typename = schema.typename;
|
|
36
|
+
const name = getAnnotation<string>(AST.TitleAnnotationId)(schema.ast) ?? typename;
|
|
37
|
+
const view = createView({ name, typename, jsonSchema: schema.jsonSchema });
|
|
38
|
+
return create(TableType, { view: makeRef(view) });
|
|
45
39
|
}, [schema]);
|
|
46
40
|
|
|
47
41
|
const projection = useMemo(() => {
|
|
@@ -50,25 +44,19 @@ const useTestModel = <T extends BaseObject & HasId>(schema: Schema.Schema<T>, co
|
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
// TODO(burdon): Just pass in view? Reuse same jsonSchema instance? View determines if mutable, etc.
|
|
53
|
-
return new ViewProjection(jsonSchema, table.view.target);
|
|
47
|
+
return new ViewProjection(schema.jsonSchema, table.view.target);
|
|
54
48
|
}, [schema, table]);
|
|
55
49
|
|
|
56
|
-
const
|
|
57
|
-
() => ({ schemaEditable: false, dataEditable: true, selection: { enabled: false } }),
|
|
58
|
-
[],
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
const model = useTableModel<TableRow>({ table, projection, rows: [], features });
|
|
50
|
+
const model = useTableModel({ table, projection, rows: [] });
|
|
62
51
|
useEffect(() => {
|
|
63
|
-
if (!model
|
|
52
|
+
if (!model) {
|
|
64
53
|
return;
|
|
65
54
|
}
|
|
66
55
|
|
|
67
|
-
const objectGenerator =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}, [model, space]);
|
|
56
|
+
const objectGenerator = createGenerator(generator, schema, { optional: true });
|
|
57
|
+
const objects: ReactiveObject<T>[] = Array.from({ length: count }).map(() => objectGenerator.createObject());
|
|
58
|
+
model.setRows(objects);
|
|
59
|
+
}, [model]);
|
|
72
60
|
|
|
73
61
|
const presentation = useMemo(() => {
|
|
74
62
|
if (!model) {
|
|
@@ -82,17 +70,22 @@ const useTestModel = <T extends BaseObject & HasId>(schema: Schema.Schema<T>, co
|
|
|
82
70
|
};
|
|
83
71
|
|
|
84
72
|
const DefaultStory = () => {
|
|
85
|
-
|
|
73
|
+
// TODO(burdon): Remove need for ImmutableSchema wrapper at API-level.
|
|
74
|
+
const orgSchema = useMemo(() => new ImmutableSchema(Testing.Org), []);
|
|
75
|
+
const { model: orgModel, presentation: orgPresentation } = useTestModel<Testing.Org>(orgSchema, 50);
|
|
76
|
+
|
|
86
77
|
// TODO(burdon): Generate links with references.
|
|
87
|
-
const
|
|
78
|
+
const contactSchema = useMemo(() => new ImmutableSchema(Testing.Contact), []);
|
|
79
|
+
const { model: contactModel, presentation: contactPresentation } = useTestModel<Testing.Contact>(contactSchema, 50);
|
|
88
80
|
|
|
81
|
+
// TODO(burdon): Scrolling isn't working.
|
|
89
82
|
return (
|
|
90
|
-
<div className='
|
|
83
|
+
<div className='grow grid grid-cols-2 divide-x divide-separator'>
|
|
91
84
|
<Table.Root>
|
|
92
|
-
<Table.Main model={orgModel} presentation={orgPresentation}
|
|
85
|
+
<Table.Main model={orgModel} presentation={orgPresentation} />
|
|
93
86
|
</Table.Root>
|
|
94
87
|
<Table.Root>
|
|
95
|
-
<Table.Main model={contactModel} presentation={contactPresentation}
|
|
88
|
+
<Table.Main model={contactModel} presentation={contactPresentation} />
|
|
96
89
|
</Table.Root>
|
|
97
90
|
</div>
|
|
98
91
|
);
|
|
@@ -104,12 +97,12 @@ const meta: Meta<typeof DefaultStory> = {
|
|
|
104
97
|
parameters: { translations },
|
|
105
98
|
decorators: [
|
|
106
99
|
withClientProvider({
|
|
107
|
-
types: [TableType, ViewType,
|
|
100
|
+
types: [TableType, ViewType, Testing.Org, Testing.Contact],
|
|
108
101
|
createIdentity: true,
|
|
109
102
|
createSpace: true,
|
|
110
103
|
}),
|
|
111
104
|
withTheme,
|
|
112
|
-
withLayout({ fullscreen: true }),
|
|
105
|
+
withLayout({ fullscreen: true, tooltips: true }),
|
|
113
106
|
],
|
|
114
107
|
};
|
|
115
108
|
|
|
@@ -7,12 +7,12 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type Meta, type StoryObj } from '@storybook/react';
|
|
8
8
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
9
9
|
|
|
10
|
-
import { type EchoSchema
|
|
10
|
+
import { ImmutableSchema, type EchoSchema } from '@dxos/echo-schema';
|
|
11
11
|
import { invariant } from '@dxos/invariant';
|
|
12
12
|
import { faker } from '@dxos/random';
|
|
13
|
-
import { Filter, useQuery,
|
|
13
|
+
import { Filter, useQuery, create } from '@dxos/react-client/echo';
|
|
14
14
|
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
15
|
-
import {
|
|
15
|
+
import { defaultSizeRow, Grid, type GridEditing } from '@dxos/react-ui-grid';
|
|
16
16
|
import { ViewProjection, ViewType } from '@dxos/schema';
|
|
17
17
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
18
18
|
|
|
@@ -31,7 +31,7 @@ const DefaultStory = ({ editing }: StoryProps) => {
|
|
|
31
31
|
const { space } = useClientProvider();
|
|
32
32
|
invariant(space);
|
|
33
33
|
|
|
34
|
-
const tables = useQuery(space, Filter.
|
|
34
|
+
const tables = useQuery(space, Filter.schema(TableType));
|
|
35
35
|
const [table, setTable] = useState<TableType>();
|
|
36
36
|
const [schema, setSchema] = useState<EchoSchema>();
|
|
37
37
|
useEffect(() => {
|
|
@@ -53,9 +53,9 @@ const DefaultStory = ({ editing }: StoryProps) => {
|
|
|
53
53
|
() => ({
|
|
54
54
|
selection: { enabled: true, mode: 'multiple' },
|
|
55
55
|
dataEditable: true,
|
|
56
|
-
schemaEditable: schema
|
|
56
|
+
schemaEditable: !(schema instanceof ImmutableSchema),
|
|
57
57
|
}),
|
|
58
|
-
[
|
|
58
|
+
[],
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
const model = useTableModel({ table, projection, features });
|
|
@@ -76,7 +76,7 @@ const DefaultStory = ({ editing }: StoryProps) => {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
return (
|
|
79
|
-
<div className='flex w-[300px] border border-separator' style={{ height:
|
|
79
|
+
<div className='flex w-[300px] border border-separator' style={{ height: defaultSizeRow }}>
|
|
80
80
|
<Grid.Root id='test' editing={editing}>
|
|
81
81
|
<TableCellEditor model={model} onQuery={handleQuery} />
|
|
82
82
|
</Grid.Root>
|
|
@@ -95,11 +95,11 @@ const meta: Meta<StoryProps> = {
|
|
|
95
95
|
createIdentity: true,
|
|
96
96
|
createSpace: true,
|
|
97
97
|
onSpaceCreated: async ({ client, space }) => {
|
|
98
|
-
const table = space.db.add(
|
|
98
|
+
const table = space.db.add(create(TableType, {}));
|
|
99
99
|
const schema = await initializeTable({ client, space, table });
|
|
100
100
|
Array.from({ length: 10 }).forEach(() => {
|
|
101
101
|
space.db.add(
|
|
102
|
-
|
|
102
|
+
create(schema, {
|
|
103
103
|
name: faker.person.fullName(),
|
|
104
104
|
}),
|
|
105
105
|
);
|
|
@@ -107,7 +107,7 @@ const meta: Meta<StoryProps> = {
|
|
|
107
107
|
},
|
|
108
108
|
}),
|
|
109
109
|
withTheme,
|
|
110
|
-
withLayout(),
|
|
110
|
+
withLayout({ tooltips: true }),
|
|
111
111
|
],
|
|
112
112
|
};
|
|
113
113
|
|
|
@@ -120,7 +120,6 @@ export const Default: Story = {
|
|
|
120
120
|
editing: {
|
|
121
121
|
index: 'grid,0,3',
|
|
122
122
|
initialContent: 'Test',
|
|
123
|
-
cellElement: null,
|
|
124
123
|
},
|
|
125
124
|
},
|
|
126
125
|
};
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Copyright
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Completion } from '@codemirror/autocomplete';
|
|
6
|
-
import { type Schema } from 'effect/Schema';
|
|
7
6
|
import React, { useCallback, useMemo, useRef } from 'react';
|
|
8
7
|
|
|
9
|
-
import { FormatEnum
|
|
8
|
+
import { FormatEnum } from '@dxos/echo-schema';
|
|
10
9
|
import { invariant } from '@dxos/invariant';
|
|
11
10
|
import { type DxGrid } from '@dxos/lit-grid';
|
|
12
11
|
import { useThemeContext } from '@dxos/react-ui';
|
|
@@ -27,7 +26,6 @@ import {
|
|
|
27
26
|
import { tagPickerExtension, createLinks } from '@dxos/react-ui-tag-picker';
|
|
28
27
|
import { type FieldProjection } from '@dxos/schema';
|
|
29
28
|
|
|
30
|
-
import { FormCellEditor } from './FormCellEditor';
|
|
31
29
|
import { completion } from './extension';
|
|
32
30
|
import { type TableModel, type ModalController } from '../../model';
|
|
33
31
|
|
|
@@ -45,52 +43,11 @@ export type QueryResult = Pick<Completion, 'label'> & { data: any };
|
|
|
45
43
|
export type TableCellEditorProps = {
|
|
46
44
|
model?: TableModel;
|
|
47
45
|
modals?: ModalController;
|
|
48
|
-
schema?: Schema.AnyNoContext;
|
|
49
46
|
onEnter?: (cell: DxGridPlanePosition) => void;
|
|
50
47
|
onFocus?: DxGrid['refocus'];
|
|
51
48
|
onQuery?: (field: FieldProjection, text: string) => Promise<QueryResult[]>;
|
|
52
49
|
};
|
|
53
50
|
|
|
54
|
-
export const TableValueEditor = ({
|
|
55
|
-
model,
|
|
56
|
-
modals,
|
|
57
|
-
schema,
|
|
58
|
-
onEnter,
|
|
59
|
-
onFocus,
|
|
60
|
-
onQuery,
|
|
61
|
-
__gridScope,
|
|
62
|
-
}: GridScopedProps<TableCellEditorProps>) => {
|
|
63
|
-
const { editing } = useGridContext('TableValueEditor', __gridScope);
|
|
64
|
-
|
|
65
|
-
const fieldProjection = useMemo<FieldProjection | undefined>(() => {
|
|
66
|
-
if (!model || !editing) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const { col } = parseCellIndex(editing.index);
|
|
71
|
-
const field = model.projection.view.fields[col];
|
|
72
|
-
const fieldProjection = model.projection.getFieldProjection(field.id);
|
|
73
|
-
invariant(fieldProjection);
|
|
74
|
-
return fieldProjection;
|
|
75
|
-
}, [model, editing]);
|
|
76
|
-
|
|
77
|
-
if (fieldProjection?.props.type === TypeEnum.Array) {
|
|
78
|
-
return <FormCellEditor fieldProjection={fieldProjection} model={model} schema={schema} __gridScope={__gridScope} />;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// For all other types, use the existing cell editor
|
|
82
|
-
return (
|
|
83
|
-
<TableCellEditor
|
|
84
|
-
model={model}
|
|
85
|
-
modals={modals}
|
|
86
|
-
onEnter={onEnter}
|
|
87
|
-
onFocus={onFocus}
|
|
88
|
-
onQuery={onQuery}
|
|
89
|
-
__gridScope={__gridScope}
|
|
90
|
-
/>
|
|
91
|
-
);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
51
|
export const TableCellEditor = ({
|
|
95
52
|
model,
|
|
96
53
|
modals,
|
|
@@ -304,9 +261,11 @@ export const TableCellEditor = ({
|
|
|
304
261
|
}
|
|
305
262
|
}
|
|
306
263
|
|
|
264
|
+
// Return empty string if no value
|
|
307
265
|
return '';
|
|
308
266
|
}
|
|
309
267
|
|
|
268
|
+
// Default behavior for other formats
|
|
310
269
|
const value = model.getCellData(cell);
|
|
311
270
|
return value !== undefined ? String(value) : '';
|
|
312
271
|
}
|