@dxos/react-ui-table 0.8.1-main.ba2dec9 → 0.8.1-staging.5be625a
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-3FR6NHPD.mjs → chunk-5MKYB7NF.mjs} +5 -7
- package/dist/lib/browser/chunk-5MKYB7NF.mjs.map +7 -0
- package/dist/lib/browser/{_deprecated → deprecated}/index.mjs +26 -26
- package/dist/lib/{node-esm/_deprecated → browser/deprecated}/index.mjs.map +4 -4
- package/dist/lib/browser/index.mjs +394 -192
- 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-NB3SFHGA.cjs → chunk-NRFKBRPV.cjs} +7 -9
- package/dist/lib/node/chunk-NRFKBRPV.cjs.map +7 -0
- package/dist/lib/node/{_deprecated → deprecated}/index.cjs +5 -5
- package/dist/lib/node/{_deprecated → deprecated}/index.cjs.map +4 -4
- package/dist/lib/node/index.cjs +386 -188
- 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-RLVVOZW5.mjs → chunk-SU4D55KI.mjs} +5 -7
- package/dist/lib/node-esm/chunk-SU4D55KI.mjs.map +7 -0
- package/dist/lib/node-esm/{_deprecated → deprecated}/index.mjs +26 -26
- package/dist/lib/node-esm/deprecated/index.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +394 -192
- 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/DynamicTable.d.ts +19 -0
- package/dist/types/src/components/Table/DynamicTable.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 +1 -0
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +3 -1
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/index.d.ts +1 -0
- package/dist/types/src/components/Table/index.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +7 -7
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/deprecated/components/Cell/Cell.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Cell/CellCombobox.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Cell/index.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/ColumnMenu/index.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/Table.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/Table.stories.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/TableBody.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/TableContext.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/TableHead.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/TableRootContext.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/index.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/Table/props.d.ts.map +1 -0
- package/dist/types/src/deprecated/components/index.d.ts.map +1 -0
- package/dist/types/src/deprecated/helpers.d.ts.map +1 -0
- package/dist/types/src/deprecated/hooks/index.d.ts.map +1 -0
- package/dist/types/src/deprecated/hooks/useColumnSizing.d.ts.map +1 -0
- package/dist/types/src/deprecated/hooks/useColumnSorting.d.ts.map +1 -0
- package/dist/types/src/deprecated/hooks/usePinLastRow.d.ts.map +1 -0
- package/dist/types/src/deprecated/hooks/useRowSelection.d.ts.map +1 -0
- package/dist/types/src/deprecated/index.d.ts.map +1 -0
- package/dist/types/src/deprecated/schema/Schema.stories.d.ts.map +1 -0
- package/dist/types/src/deprecated/schema/column-utils.d.ts.map +1 -0
- package/dist/types/src/deprecated/schema/index.d.ts.map +1 -0
- package/dist/types/src/deprecated/schema/types.d.ts.map +1 -0
- package/dist/types/src/deprecated/theme.d.ts.map +1 -0
- package/dist/types/src/deprecated/translations.d.ts.map +1 -0
- package/dist/types/src/deprecated/types.d.ts.map +1 -0
- package/dist/types/src/hooks/useTableModel.d.ts +6 -3
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +34 -7
- 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/model/table-sorting.d.ts.map +1 -1
- package/dist/types/src/types/table.d.ts +7 -33
- package/dist/types/src/types/table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +40 -0
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +1 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/table.d.ts +5 -3
- package/dist/types/src/util/table.d.ts.map +1 -1
- package/package.json +35 -35
- package/src/components/Table/ColumnActionsMenu.tsx +6 -4
- package/src/components/Table/ColumnSettings.tsx +5 -6
- package/src/components/Table/CreateRefPanel.tsx +3 -3
- package/src/components/Table/DynamicTable.tsx +86 -0
- package/src/components/Table/RefPanel.tsx +3 -3
- package/src/components/Table/RowActionsMenu.tsx +18 -3
- package/src/components/Table/Table.stories.tsx +71 -20
- package/src/components/Table/Table.tsx +30 -10
- package/src/components/Table/index.ts +1 -0
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +9 -4
- package/src/components/testing.ts +1 -0
- package/src/{_deprecated → deprecated}/components/Cell/Cell.tsx +2 -2
- package/src/{_deprecated → deprecated}/components/Table/TableBody.tsx +2 -2
- package/src/{_deprecated → deprecated}/helpers.tsx +2 -2
- package/src/hooks/useTableModel.ts +28 -7
- package/src/model/table-model.test.ts +1 -1
- package/src/model/table-model.ts +97 -21
- package/src/model/table-presentation.test.ts +1 -1
- package/src/model/table-presentation.ts +30 -12
- package/src/model/table-sorting.ts +1 -0
- package/src/types/table.ts +5 -7
- package/src/util/dynamic-table.ts +71 -0
- package/src/util/index.ts +1 -0
- package/src/util/table.ts +67 -65
- package/dist/lib/browser/_deprecated/index.mjs.map +0 -7
- package/dist/lib/browser/chunk-3FR6NHPD.mjs.map +0 -7
- package/dist/lib/node/chunk-NB3SFHGA.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +0 -7
- package/dist/types/src/_deprecated/components/Cell/Cell.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Cell/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/Table.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableBody.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableContext.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableHead.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/Table/props.d.ts.map +0 -1
- package/dist/types/src/_deprecated/components/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/helpers.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts.map +0 -1
- package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts.map +0 -1
- package/dist/types/src/_deprecated/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/Schema.stories.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/column-utils.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/index.d.ts.map +0 -1
- package/dist/types/src/_deprecated/schema/types.d.ts.map +0 -1
- package/dist/types/src/_deprecated/theme.d.ts.map +0 -1
- package/dist/types/src/_deprecated/translations.d.ts.map +0 -1
- package/dist/types/src/_deprecated/types.d.ts.map +0 -1
- /package/dist/types/src/{_deprecated → deprecated}/components/Cell/Cell.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Cell/CellCombobox.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Cell/index.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.stories.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.stories.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/ColumnMenu/index.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/Table.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/Table.stories.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/TableBody.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/TableContext.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/TableHead.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/TableRootContext.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/index.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/Table/props.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/components/index.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/helpers.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/hooks/index.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/hooks/useColumnSizing.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/hooks/useColumnSorting.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/hooks/usePinLastRow.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/hooks/useRowSelection.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/index.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/schema/Schema.stories.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/schema/column-utils.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/schema/index.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/schema/types.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/theme.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/translations.d.ts +0 -0
- /package/dist/types/src/{_deprecated → deprecated}/types.d.ts +0 -0
- /package/src/{_deprecated → deprecated}/components/Cell/CellCombobox.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/Cell/index.ts +0 -0
- /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.stories.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnMenu.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.stories.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/ColumnMenu/ColumnSettings.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/ColumnMenu/index.ts +0 -0
- /package/src/{_deprecated → deprecated}/components/Table/Table.stories.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/Table/Table.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/Table/TableContext.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/Table/TableHead.tsx +0 -0
- /package/src/{_deprecated → deprecated}/components/Table/TableRootContext.ts +0 -0
- /package/src/{_deprecated → deprecated}/components/Table/index.ts +0 -0
- /package/src/{_deprecated → deprecated}/components/Table/props.ts +0 -0
- /package/src/{_deprecated → deprecated}/components/index.ts +0 -0
- /package/src/{_deprecated → deprecated}/hooks/index.ts +0 -0
- /package/src/{_deprecated → deprecated}/hooks/useColumnSizing.ts +0 -0
- /package/src/{_deprecated → deprecated}/hooks/useColumnSorting.ts +0 -0
- /package/src/{_deprecated → deprecated}/hooks/usePinLastRow.ts +0 -0
- /package/src/{_deprecated → deprecated}/hooks/useRowSelection.ts +0 -0
- /package/src/{_deprecated → deprecated}/index.ts +0 -0
- /package/src/{_deprecated → deprecated}/schema/Schema.stories.tsx +0 -0
- /package/src/{_deprecated → deprecated}/schema/column-utils.ts +0 -0
- /package/src/{_deprecated → deprecated}/schema/index.ts +0 -0
- /package/src/{_deprecated → deprecated}/schema/types.ts +0 -0
- /package/src/{_deprecated → deprecated}/theme.ts +0 -0
- /package/src/{_deprecated → deprecated}/translations.ts +0 -0
- /package/src/{_deprecated → deprecated}/types.ts +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useRef, useMemo, useCallback } from 'react';
|
|
6
|
+
|
|
7
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
8
|
+
|
|
9
|
+
import { Table, type TableController } from './Table';
|
|
10
|
+
import { useTableModel } from '../../hooks';
|
|
11
|
+
import { TablePresentation, type TableRowAction } from '../../model';
|
|
12
|
+
import { makeDynamicTable, type TablePropertyDefinition } from '../../util';
|
|
13
|
+
|
|
14
|
+
type DynamicTableProps = {
|
|
15
|
+
data: any[];
|
|
16
|
+
properties: TablePropertyDefinition[];
|
|
17
|
+
tableName?: string;
|
|
18
|
+
classNames?: string;
|
|
19
|
+
onRowClicked?: (row: any) => void;
|
|
20
|
+
rowActions?: TableRowAction[];
|
|
21
|
+
onRowAction?: (actionId: string, datum: any) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A dynamic table component that renders data using the specified properties.
|
|
26
|
+
* Properties define both the schema and display characteristics of the table columns.
|
|
27
|
+
*/
|
|
28
|
+
export const DynamicTable = ({
|
|
29
|
+
data,
|
|
30
|
+
properties,
|
|
31
|
+
classNames,
|
|
32
|
+
tableName = 'com.example/dynamic_table',
|
|
33
|
+
onRowClicked,
|
|
34
|
+
rowActions,
|
|
35
|
+
onRowAction,
|
|
36
|
+
}: DynamicTableProps) => {
|
|
37
|
+
// TODO(ZaymonFC): Consider allowing the user to supply a schema directly instead of deriving it from
|
|
38
|
+
// the properties array. (Both should be viable).
|
|
39
|
+
const { table, viewProjection } = useMemo(() => {
|
|
40
|
+
return makeDynamicTable(tableName, properties);
|
|
41
|
+
}, [tableName, properties]);
|
|
42
|
+
|
|
43
|
+
const tableRef = useRef<TableController>(null);
|
|
44
|
+
const handleCellUpdate = useCallback((cell: any) => {
|
|
45
|
+
tableRef.current?.update?.(cell);
|
|
46
|
+
}, []);
|
|
47
|
+
|
|
48
|
+
const handleRowOrderChanged = useCallback(() => {
|
|
49
|
+
tableRef.current?.update?.();
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
const features = useMemo(() => ({ selection: false, dataEditable: false }), []);
|
|
53
|
+
|
|
54
|
+
const model = useTableModel({
|
|
55
|
+
table,
|
|
56
|
+
objects: data,
|
|
57
|
+
projection: viewProjection,
|
|
58
|
+
features,
|
|
59
|
+
onCellUpdate: handleCellUpdate,
|
|
60
|
+
onRowOrderChanged: handleRowOrderChanged,
|
|
61
|
+
rowActions,
|
|
62
|
+
onRowAction,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const presentation = useMemo(() => {
|
|
66
|
+
if (model) {
|
|
67
|
+
return new TablePresentation(model);
|
|
68
|
+
}
|
|
69
|
+
}, [model]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className={mx('is-full bs-full grow grid', classNames)}>
|
|
73
|
+
<div className='grid min-bs-0 overflow-hidden'>
|
|
74
|
+
<Table.Root>
|
|
75
|
+
<Table.Main
|
|
76
|
+
ref={tableRef}
|
|
77
|
+
model={model}
|
|
78
|
+
presentation={presentation}
|
|
79
|
+
onRowClicked={onRowClicked}
|
|
80
|
+
ignoreAttention
|
|
81
|
+
/>
|
|
82
|
+
</Table.Root>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
8
8
|
import { Popover } from '@dxos/react-ui';
|
|
9
9
|
import { Form } from '@dxos/react-ui-form';
|
|
10
10
|
|
|
@@ -22,11 +22,11 @@ const getRefTargetObj = (space?: Space, id?: string) => {
|
|
|
22
22
|
|
|
23
23
|
export const RefPanel = ({ model, modals }: RefPanelProps) => {
|
|
24
24
|
const state = modals.state.value;
|
|
25
|
-
const space =
|
|
25
|
+
const space = model?.space;
|
|
26
26
|
const targetObj = getRefTargetObj(space, state?.type === 'refPanel' ? state.targetId : undefined);
|
|
27
27
|
const schema = space && state?.type === 'refPanel' ? space.db.schemaRegistry.getSchema(state.typename) : undefined;
|
|
28
28
|
|
|
29
|
-
if (!model.
|
|
29
|
+
if (!model.view || !model.projection) {
|
|
30
30
|
return null;
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -23,9 +23,24 @@ export const RowActionsMenu = ({ model, modals }: RowActionsMenuProps) => {
|
|
|
23
23
|
<DropdownMenu.VirtualTrigger virtualRef={modals.trigger} />
|
|
24
24
|
<DropdownMenu.Content>
|
|
25
25
|
<DropdownMenu.Viewport>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
{model.features.dataEditable !== false && (
|
|
27
|
+
<DropdownMenu.Item data-testid='row-menu-delete' onClick={() => model.deleteRow(state.rowIndex)}>
|
|
28
|
+
{t(hasSelection ? 'bulk delete row label' : 'delete row label')}
|
|
29
|
+
</DropdownMenu.Item>
|
|
30
|
+
)}
|
|
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
|
+
{t(action.translationKey)}
|
|
42
|
+
</DropdownMenu.Item>
|
|
43
|
+
))}
|
|
29
44
|
</DropdownMenu.Viewport>
|
|
30
45
|
<DropdownMenu.Arrow />
|
|
31
46
|
</DropdownMenu.Content>
|
|
@@ -4,20 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
|
-
import { type Meta } from '@storybook/react';
|
|
8
|
-
import React, { useCallback,
|
|
7
|
+
import { type StoryObj, type Meta } from '@storybook/react';
|
|
8
|
+
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
9
9
|
|
|
10
|
+
import { FormatEnum, ImmutableSchema } from '@dxos/echo-schema';
|
|
10
11
|
import { invariant } from '@dxos/invariant';
|
|
11
12
|
import { useGlobalFilteredObjects } from '@dxos/plugin-search';
|
|
12
13
|
import { faker } from '@dxos/random';
|
|
14
|
+
import { useClient } from '@dxos/react-client';
|
|
13
15
|
import { Filter, useQuery, useSchema, create } from '@dxos/react-client/echo';
|
|
14
16
|
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
15
17
|
import { useDefaultValue } from '@dxos/react-ui';
|
|
16
18
|
import { ViewEditor } from '@dxos/react-ui-form';
|
|
17
19
|
import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
18
|
-
import { ViewProjection, ViewType } from '@dxos/schema';
|
|
20
|
+
import { type SchemaPropertyDefinition, ViewProjection, ViewType } from '@dxos/schema';
|
|
21
|
+
import { Testing, createObjectFactory } from '@dxos/schema/testing';
|
|
19
22
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
20
23
|
|
|
24
|
+
import { DynamicTable as DynamicTableComponent } from './DynamicTable';
|
|
21
25
|
import { Table, type TableController } from './Table';
|
|
22
26
|
import { useTableModel, type UseTableModelParams } from '../../hooks';
|
|
23
27
|
import { TablePresentation } from '../../model';
|
|
@@ -35,20 +39,13 @@ faker.seed(0);
|
|
|
35
39
|
//
|
|
36
40
|
|
|
37
41
|
const DefaultStory = () => {
|
|
42
|
+
const client = useClient();
|
|
38
43
|
const { space } = useClientProvider();
|
|
39
|
-
invariant(space);
|
|
40
44
|
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
if (space && tables.length && !table) {
|
|
47
|
-
const table = tables[0];
|
|
48
|
-
invariant(table.view);
|
|
49
|
-
setTable(table);
|
|
50
|
-
}
|
|
51
|
-
}, [space, tables]);
|
|
45
|
+
const filter = useMemo(() => Filter.schema(TableType), []);
|
|
46
|
+
const tables = useQuery(space, filter);
|
|
47
|
+
const table = useMemo(() => tables.at(0), [tables]);
|
|
48
|
+
const schema = useSchema(client, space, table?.view?.target?.query.typename);
|
|
52
49
|
|
|
53
50
|
const projection = useMemo(() => {
|
|
54
51
|
if (schema && table?.view?.target) {
|
|
@@ -56,6 +53,11 @@ const DefaultStory = () => {
|
|
|
56
53
|
}
|
|
57
54
|
}, [schema, table?.view?.target]);
|
|
58
55
|
|
|
56
|
+
const features = useMemo(
|
|
57
|
+
() => ({ selection: true, dataEditable: true, schemaEditable: !(schema instanceof ImmutableSchema) }),
|
|
58
|
+
[schema],
|
|
59
|
+
);
|
|
60
|
+
|
|
59
61
|
const objects = useQuery(space, schema ? Filter.schema(schema) : Filter.nothing());
|
|
60
62
|
const filteredObjects = useGlobalFilteredObjects(objects);
|
|
61
63
|
|
|
@@ -68,7 +70,7 @@ const DefaultStory = () => {
|
|
|
68
70
|
const handleDeleteRows = useCallback(
|
|
69
71
|
(_: number, objects: any[]) => {
|
|
70
72
|
for (const object of objects) {
|
|
71
|
-
space
|
|
73
|
+
space?.db.remove(object);
|
|
72
74
|
}
|
|
73
75
|
},
|
|
74
76
|
[space],
|
|
@@ -95,6 +97,7 @@ const DefaultStory = () => {
|
|
|
95
97
|
const model = useTableModel({
|
|
96
98
|
table,
|
|
97
99
|
projection,
|
|
100
|
+
features,
|
|
98
101
|
objects: filteredObjects,
|
|
99
102
|
onInsertRow: handleInsertRow,
|
|
100
103
|
onDeleteRows: handleDeleteRows,
|
|
@@ -132,11 +135,12 @@ const DefaultStory = () => {
|
|
|
132
135
|
const onTypenameChanged = useCallback(
|
|
133
136
|
(typename: string) => {
|
|
134
137
|
if (table?.view?.target) {
|
|
135
|
-
schema
|
|
138
|
+
invariant(schema);
|
|
139
|
+
schema.mutable.updateTypename(typename);
|
|
136
140
|
table.view.target.query.typename = typename;
|
|
137
141
|
}
|
|
138
142
|
},
|
|
139
|
-
[table?.view?.target
|
|
143
|
+
[schema, table?.view?.target],
|
|
140
144
|
);
|
|
141
145
|
|
|
142
146
|
if (!schema || !table) {
|
|
@@ -170,6 +174,25 @@ const DefaultStory = () => {
|
|
|
170
174
|
);
|
|
171
175
|
};
|
|
172
176
|
|
|
177
|
+
const DynamicTableStory = () => {
|
|
178
|
+
const properties = useMemo<SchemaPropertyDefinition[]>(
|
|
179
|
+
() => [
|
|
180
|
+
{ name: 'name', format: FormatEnum.String },
|
|
181
|
+
{ name: 'age', format: FormatEnum.Number },
|
|
182
|
+
],
|
|
183
|
+
[],
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const [objects, _setObjects] = useState<any[]>(
|
|
187
|
+
Array.from({ length: 100 }, () => ({
|
|
188
|
+
name: faker.person.fullName(),
|
|
189
|
+
age: faker.number.int({ min: 18, max: 80 }),
|
|
190
|
+
})),
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
return <DynamicTableComponent properties={properties} data={objects} />;
|
|
194
|
+
};
|
|
195
|
+
|
|
173
196
|
type StoryProps = {
|
|
174
197
|
rows?: number;
|
|
175
198
|
} & Pick<SimulatorProps, 'insertInterval' | 'updateInterval'>;
|
|
@@ -228,9 +251,9 @@ const meta: Meta<StoryProps> = {
|
|
|
228
251
|
types: [TableType, ViewType],
|
|
229
252
|
createIdentity: true,
|
|
230
253
|
createSpace: true,
|
|
231
|
-
onSpaceCreated: async ({ space }) => {
|
|
254
|
+
onSpaceCreated: async ({ client, space }) => {
|
|
232
255
|
const table = space.db.add(create(TableType, {}));
|
|
233
|
-
const schema = await initializeTable({ space, table, initialRow: false });
|
|
256
|
+
const schema = await initializeTable({ client, space, table, initialRow: false });
|
|
234
257
|
Array.from({ length: 10 }).map(() => {
|
|
235
258
|
return space.db.add(
|
|
236
259
|
create(schema, {
|
|
@@ -249,6 +272,34 @@ export default meta;
|
|
|
249
272
|
|
|
250
273
|
export const Default = {};
|
|
251
274
|
|
|
275
|
+
export const StaticSchema: StoryObj = {
|
|
276
|
+
render: DefaultStory,
|
|
277
|
+
parameters: { translations },
|
|
278
|
+
decorators: [
|
|
279
|
+
withClientProvider({
|
|
280
|
+
types: [TableType, ViewType, Testing.ContactType, Testing.OrgType],
|
|
281
|
+
createIdentity: true,
|
|
282
|
+
createSpace: true,
|
|
283
|
+
onSpaceCreated: async ({ client, space }) => {
|
|
284
|
+
const table = space.db.add(create(TableType, {}));
|
|
285
|
+
await initializeTable({ client, space, table, typename: Testing.ContactType.typename });
|
|
286
|
+
|
|
287
|
+
const factory = createObjectFactory(space.db, faker as any);
|
|
288
|
+
await factory([
|
|
289
|
+
{ type: Testing.ContactType, count: 10 },
|
|
290
|
+
{ type: Testing.OrgType, count: 1 },
|
|
291
|
+
]);
|
|
292
|
+
},
|
|
293
|
+
}),
|
|
294
|
+
withTheme,
|
|
295
|
+
withLayout({ fullscreen: true, tooltips: true }),
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const DynamicTable: StoryObj = {
|
|
300
|
+
render: DynamicTableStory,
|
|
301
|
+
};
|
|
302
|
+
|
|
252
303
|
// TODO(ZaymonFC): Restore the performance stories.
|
|
253
304
|
// type Story = StoryObj<StoryProps>;
|
|
254
305
|
// export const Mutations: Story = {
|
|
@@ -15,12 +15,12 @@ import React, {
|
|
|
15
15
|
|
|
16
16
|
import { getValue } from '@dxos/echo-schema';
|
|
17
17
|
import { invariant } from '@dxos/invariant';
|
|
18
|
-
import { Filter
|
|
18
|
+
import { Filter } from '@dxos/react-client/echo';
|
|
19
19
|
import { useTranslation } from '@dxos/react-ui';
|
|
20
20
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
21
21
|
import { type DxGridElement, Grid, type GridContentProps, closestCell, type DxGridPosition } from '@dxos/react-ui-grid';
|
|
22
22
|
import { mx } from '@dxos/react-ui-theme';
|
|
23
|
-
import { isNotFalsy } from '@dxos/util';
|
|
23
|
+
import { isNotFalsy, safeParseInt } from '@dxos/util';
|
|
24
24
|
|
|
25
25
|
import { ColumnActionsMenu } from './ColumnActionsMenu';
|
|
26
26
|
import { ColumnSettings } from './ColumnSettings';
|
|
@@ -39,8 +39,6 @@ const inlineEndLine =
|
|
|
39
39
|
const blockEndLine =
|
|
40
40
|
'[&>.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';
|
|
41
41
|
|
|
42
|
-
const frozen = { frozenRowsStart: 1, frozenColsStart: 1, frozenColsEnd: 1 };
|
|
43
|
-
|
|
44
42
|
//
|
|
45
43
|
// Root
|
|
46
44
|
//
|
|
@@ -75,15 +73,21 @@ export type TableMainProps = {
|
|
|
75
73
|
model?: TableModel;
|
|
76
74
|
presentation?: TablePresentation;
|
|
77
75
|
ignoreAttention?: boolean;
|
|
76
|
+
onRowClicked?: (row: any) => void;
|
|
78
77
|
};
|
|
79
78
|
|
|
80
79
|
const TableMain = forwardRef<TableController, TableMainProps>(
|
|
81
|
-
({ model, presentation, ignoreAttention }, forwardedRef) => {
|
|
80
|
+
({ model, presentation, ignoreAttention, onRowClicked }, forwardedRef) => {
|
|
82
81
|
const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
|
|
83
|
-
const { hasAttention } = useAttention(model?.
|
|
82
|
+
const { hasAttention } = useAttention(model?.id ?? 'table');
|
|
84
83
|
const { t } = useTranslation(translationKey);
|
|
85
84
|
const modals = useMemo(() => new ModalController(), []);
|
|
86
85
|
|
|
86
|
+
const frozen = useMemo(
|
|
87
|
+
() => ({ frozenRowsStart: 1, frozenColsStart: model?.features.selection ? 1 : 0, frozenColsEnd: 1 }),
|
|
88
|
+
[model],
|
|
89
|
+
);
|
|
90
|
+
|
|
87
91
|
/**
|
|
88
92
|
* Provides an external controller that can be called to repaint the table.
|
|
89
93
|
*/
|
|
@@ -111,6 +115,14 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
111
115
|
|
|
112
116
|
const handleGridClick = useCallback(
|
|
113
117
|
(event: MouseEvent) => {
|
|
118
|
+
if (onRowClicked) {
|
|
119
|
+
const rowIndex = safeParseInt((event.target as HTMLElement).ariaRowIndex ?? '');
|
|
120
|
+
if (rowIndex != null) {
|
|
121
|
+
const row = model?.getRowAt(rowIndex);
|
|
122
|
+
row && onRowClicked(row);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
114
126
|
if (!modals) {
|
|
115
127
|
return;
|
|
116
128
|
}
|
|
@@ -197,6 +209,10 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
197
209
|
|
|
198
210
|
const handleEnter = useCallback<NonNullable<TableCellEditorProps['onEnter']>>(
|
|
199
211
|
(cell) => {
|
|
212
|
+
if (!model?.features.dataEditable) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
200
216
|
// TODO(burdon): Insert row only if bottom row isn't completely blank already.
|
|
201
217
|
if (model && cell.row === model.getRowCount() - 1) {
|
|
202
218
|
model.insertRow(cell.row);
|
|
@@ -213,6 +229,10 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
213
229
|
|
|
214
230
|
const handleKeyDown = useCallback<NonNullable<GridContentProps['onKeyDown']>>(
|
|
215
231
|
(event) => {
|
|
232
|
+
if (!model?.features.dataEditable) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
216
236
|
const cell = closestCell(event.target);
|
|
217
237
|
if (!model || !cell) {
|
|
218
238
|
return;
|
|
@@ -260,7 +280,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
260
280
|
const handleQuery = useCallback<NonNullable<TableCellEditorProps['onQuery']>>(
|
|
261
281
|
async ({ field, props }, text) => {
|
|
262
282
|
if (model && props.referenceSchema && field.referencePath) {
|
|
263
|
-
const space =
|
|
283
|
+
const space = model.space;
|
|
264
284
|
invariant(space);
|
|
265
285
|
const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
|
|
266
286
|
if (schema) {
|
|
@@ -291,7 +311,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
291
311
|
|
|
292
312
|
return [];
|
|
293
313
|
},
|
|
294
|
-
[model],
|
|
314
|
+
[model, t],
|
|
295
315
|
);
|
|
296
316
|
|
|
297
317
|
if (!model || !modals) {
|
|
@@ -299,7 +319,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
299
319
|
}
|
|
300
320
|
|
|
301
321
|
return (
|
|
302
|
-
<Grid.Root id={model.
|
|
322
|
+
<Grid.Root id={model.id ?? 'table-grid'}>
|
|
303
323
|
<TableCellEditor
|
|
304
324
|
model={model}
|
|
305
325
|
modals={modals}
|
|
@@ -313,7 +333,7 @@ const TableMain = forwardRef<TableController, TableMainProps>(
|
|
|
313
333
|
frozen={frozen}
|
|
314
334
|
columns={model.columnMeta.value}
|
|
315
335
|
limitRows={model.getRowCount() ?? 0}
|
|
316
|
-
limitColumns={model.
|
|
336
|
+
limitColumns={model.view?.fields?.length ?? 0}
|
|
317
337
|
onAxisResize={handleAxisResize}
|
|
318
338
|
onClick={handleGridClick}
|
|
319
339
|
onKeyDown={handleKeyDown}
|
|
@@ -7,7 +7,7 @@ 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 } from '@dxos/echo-schema';
|
|
10
|
+
import { ImmutableSchema, type EchoSchema } from '@dxos/echo-schema';
|
|
11
11
|
import { invariant } from '@dxos/invariant';
|
|
12
12
|
import { faker } from '@dxos/random';
|
|
13
13
|
import { Filter, useQuery, create } from '@dxos/react-client/echo';
|
|
@@ -48,7 +48,12 @@ const DefaultStory = ({ editing }: StoryProps) => {
|
|
|
48
48
|
}
|
|
49
49
|
}, [schema, table?.view]);
|
|
50
50
|
|
|
51
|
-
const
|
|
51
|
+
const features = useMemo(
|
|
52
|
+
() => ({ selection: true, dataEditable: true, schemaEditable: !(schema instanceof ImmutableSchema) }),
|
|
53
|
+
[],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const model = useTableModel({ table, projection, features });
|
|
52
57
|
|
|
53
58
|
const handleQuery: TableCellEditorProps['onQuery'] = async ({ field }) => {
|
|
54
59
|
const { objects } = await space.db.query(schema).run();
|
|
@@ -84,9 +89,9 @@ const meta: Meta<StoryProps> = {
|
|
|
84
89
|
types: [TableType, ViewType],
|
|
85
90
|
createIdentity: true,
|
|
86
91
|
createSpace: true,
|
|
87
|
-
onSpaceCreated: async ({ space }) => {
|
|
92
|
+
onSpaceCreated: async ({ client, space }) => {
|
|
88
93
|
const table = space.db.add(create(TableType, {}));
|
|
89
|
-
const schema = await initializeTable({ space, table });
|
|
94
|
+
const schema = await initializeTable({ client, space, table });
|
|
90
95
|
Array.from({ length: 10 }).forEach(() => {
|
|
91
96
|
space.db.add(
|
|
92
97
|
create(schema, {
|
|
@@ -75,6 +75,7 @@ export const useSimulator = ({ items, table, insertInterval, updateInterval }: S
|
|
|
75
75
|
const rowIdx = Math.floor(Math.random() * items.length);
|
|
76
76
|
const fields = table.view?.target?.fields ?? [];
|
|
77
77
|
const columnIdx = Math.floor(Math.random() * fields.length);
|
|
78
|
+
// TODO(ZaymonFC): ... This is borked.
|
|
78
79
|
const projection: ViewProjection = (table as any)._projection;
|
|
79
80
|
const field = fields[columnIdx];
|
|
80
81
|
const item = items[rowIdx];
|
|
@@ -17,7 +17,7 @@ const CELL_NAME = 'Cell';
|
|
|
17
17
|
|
|
18
18
|
const FocusableCell = <TData extends RowData, TValue>({ cell, children }: CellProps<TData, TValue>) => {
|
|
19
19
|
const tableContext = useTableContext();
|
|
20
|
-
const
|
|
20
|
+
const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
|
|
21
21
|
|
|
22
22
|
const pinned = tableContext.table.getState().rowPinning?.bottom?.includes(cell.row.id);
|
|
23
23
|
const className = tdRoot({ ...tableContext, pinned }, cell.column.columnDef.meta?.cell?.classNames);
|
|
@@ -60,7 +60,7 @@ const FocusableCell = <TData extends RowData, TValue>({ cell, children }: CellPr
|
|
|
60
60
|
}, []);
|
|
61
61
|
|
|
62
62
|
return (
|
|
63
|
-
<td data-testid='table.cell' tabIndex={0} {...
|
|
63
|
+
<td data-testid='table.cell' tabIndex={0} {...focusableGroupAttrs} className={className} onKeyDown={handleKeyDown}>
|
|
64
64
|
{children}
|
|
65
65
|
</td>
|
|
66
66
|
);
|
|
@@ -21,13 +21,13 @@ const TableBody = ({ rows }: TableBodyProps) => {
|
|
|
21
21
|
const { table, keyAccessor, currentDatum, debug, expand, isGrid, onDatumClick } = useTableContext();
|
|
22
22
|
|
|
23
23
|
const rowSelection = table.getState().rowSelection;
|
|
24
|
-
const
|
|
24
|
+
const arrowNavigationAttrs = useArrowNavigationGroup({ axis: 'grid' });
|
|
25
25
|
const canBeCurrent = !isGrid && !!onDatumClick;
|
|
26
26
|
|
|
27
27
|
const { virtualizer } = useContext(TableRootContext);
|
|
28
28
|
|
|
29
29
|
return (
|
|
30
|
-
<tbody {...(isGrid &&
|
|
30
|
+
<tbody {...(isGrid && arrowNavigationAttrs)}>
|
|
31
31
|
{rows.map((row) => {
|
|
32
32
|
const isCurrent = currentDatum === row.original;
|
|
33
33
|
const isSelected = rowSelection?.[row.id];
|
|
@@ -126,7 +126,7 @@ const StringBuilderCell = <TData extends RowData>(cellContext: CellContext<TData
|
|
|
126
126
|
let placeholder = false;
|
|
127
127
|
const columns = cellContext.table.getVisibleFlatColumns();
|
|
128
128
|
|
|
129
|
-
// Calling getRowModel is expensive, so only do it when we're a cell in the first position
|
|
129
|
+
// Calling getRowModel is expensive, so only do it when we're a cell in the first position.
|
|
130
130
|
if (columns[0].id === cellContext.column.id) {
|
|
131
131
|
const rowCount = cellContext.table.getRowModel().rows.length;
|
|
132
132
|
placeholder = cellContext.row.index === rowCount - 1 && columns[0].id === cellContext.column.id;
|
|
@@ -206,7 +206,7 @@ const NumberBuilderCell = <TData extends RowData>(cellContext: CellContext<TData
|
|
|
206
206
|
onFocus={handleEdit}
|
|
207
207
|
onChange={({ target: { value } }) => setText(value)}
|
|
208
208
|
onKeyDown={(event) => {
|
|
209
|
-
// TODO(thure): `Escape` is reserved for blurring the input and moving focus to the cell
|
|
209
|
+
// TODO(thure): `Escape` is reserved for blurring the input and moving focus to the cell.
|
|
210
210
|
return /* (event.key === 'Escape' && handleCancel()) || */ event.key === 'Enter' && handleSave();
|
|
211
211
|
}}
|
|
212
212
|
autoComplete='off'
|
|
@@ -5,24 +5,34 @@
|
|
|
5
5
|
import { effect } from '@preact/signals-core';
|
|
6
6
|
import { useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import { type ReactiveObject } from '@dxos/react-client/echo';
|
|
8
|
+
import { fullyQualifiedId, getSpace, type ReactiveObject } from '@dxos/react-client/echo';
|
|
9
9
|
import { useSelectionActions } from '@dxos/react-ui-attention';
|
|
10
10
|
import { type ViewProjection } from '@dxos/schema';
|
|
11
11
|
import { isNonNullable } from '@dxos/util';
|
|
12
12
|
|
|
13
|
-
import { type BaseTableRow, TableModel, type TableModelProps } from '../model';
|
|
13
|
+
import { type BaseTableRow, TableModel, type TableModelProps, type TableRowAction } from '../model';
|
|
14
14
|
import { type TableType } from '../types';
|
|
15
15
|
|
|
16
16
|
export type UseTableModelParams<T extends BaseTableRow = { id: string }> = {
|
|
17
17
|
table?: TableType;
|
|
18
18
|
projection?: ViewProjection;
|
|
19
19
|
objects?: ReactiveObject<T>[];
|
|
20
|
-
|
|
20
|
+
onSelectionChanged?: (selection: string[]) => void;
|
|
21
|
+
rowActions?: TableRowAction[];
|
|
22
|
+
onRowAction?: (actionId: string, data: T) => void;
|
|
23
|
+
} & Pick<
|
|
24
|
+
TableModelProps<T>,
|
|
25
|
+
'features' | 'onInsertRow' | 'onDeleteRows' | 'onDeleteColumn' | 'onCellUpdate' | 'onRowOrderChanged'
|
|
26
|
+
>;
|
|
21
27
|
|
|
22
28
|
export const useTableModel = <T extends BaseTableRow = { id: string }>({
|
|
23
29
|
objects,
|
|
24
30
|
table,
|
|
25
31
|
projection,
|
|
32
|
+
features,
|
|
33
|
+
onSelectionChanged,
|
|
34
|
+
rowActions,
|
|
35
|
+
onRowAction,
|
|
26
36
|
...props
|
|
27
37
|
}: UseTableModelParams<T>): TableModel<T> | undefined => {
|
|
28
38
|
const [model, setModel] = useState<TableModel<T>>();
|
|
@@ -33,7 +43,16 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
|
|
|
33
43
|
|
|
34
44
|
let model: TableModel<T> | undefined;
|
|
35
45
|
const t = setTimeout(async () => {
|
|
36
|
-
model = new TableModel<T>({
|
|
46
|
+
model = new TableModel<T>({
|
|
47
|
+
id: fullyQualifiedId(table),
|
|
48
|
+
space: getSpace(table),
|
|
49
|
+
view: table.view?.target,
|
|
50
|
+
projection,
|
|
51
|
+
features,
|
|
52
|
+
rowActions,
|
|
53
|
+
onRowAction,
|
|
54
|
+
...props,
|
|
55
|
+
});
|
|
37
56
|
await model.open();
|
|
38
57
|
setModel(model);
|
|
39
58
|
});
|
|
@@ -42,7 +61,7 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
|
|
|
42
61
|
clearTimeout(t);
|
|
43
62
|
void model?.close();
|
|
44
63
|
};
|
|
45
|
-
}, [table, projection]); // TODO(burdon): Trigger if callbacks change?
|
|
64
|
+
}, [table, projection, table?.view?.target, features, rowActions]); // TODO(burdon): Trigger if callbacks change?
|
|
46
65
|
|
|
47
66
|
// Update data.
|
|
48
67
|
useEffect(() => {
|
|
@@ -59,7 +78,9 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
|
|
|
59
78
|
}
|
|
60
79
|
|
|
61
80
|
const unsubscribe = effect(() => {
|
|
62
|
-
|
|
81
|
+
const selectedItems = [...model.selection.selection.value];
|
|
82
|
+
select(selectedItems);
|
|
83
|
+
onSelectionChanged?.(selectedItems);
|
|
63
84
|
});
|
|
64
85
|
|
|
65
86
|
// Maybe clear the selection here?
|
|
@@ -67,7 +88,7 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
|
|
|
67
88
|
clear();
|
|
68
89
|
unsubscribe();
|
|
69
90
|
};
|
|
70
|
-
}, [model]);
|
|
91
|
+
}, [model, onSelectionChanged]);
|
|
71
92
|
|
|
72
93
|
return model;
|
|
73
94
|
};
|
|
@@ -108,5 +108,5 @@ const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
|
|
|
108
108
|
const view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
|
|
109
109
|
const projection = new ViewProjection(schema, view);
|
|
110
110
|
const table = create(TableType, { view: makeRef(view) });
|
|
111
|
-
return new TableModel({ table, projection, ...props });
|
|
111
|
+
return new TableModel({ id: table.id, space: undefined, view, projection, ...props });
|
|
112
112
|
};
|