@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,103 +2,113 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Registry } from '@effect-atom/atom-react';
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
6
7
|
import { beforeEach, describe, expect, it } from 'vitest';
|
|
7
8
|
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { createEchoSchema } from '@dxos/live-object/testing';
|
|
12
|
-
import { createView } from '@dxos/schema';
|
|
13
|
-
|
|
14
|
-
import { TableView } from '../types';
|
|
9
|
+
import { Filter, JsonSchema, Query, Type } from '@dxos/echo';
|
|
10
|
+
import { createEchoSchema } from '@dxos/echo/testing';
|
|
11
|
+
import { ProjectionModel, ViewModel, createDirectChangeCallback } from '@dxos/schema';
|
|
15
12
|
|
|
13
|
+
import { Table } from '../types';
|
|
16
14
|
import { TableModel, type TableModelProps } from './table-model';
|
|
17
15
|
import { TablePresentation } from './table-presentation';
|
|
18
16
|
|
|
19
17
|
describe('TablePresentation', () => {
|
|
20
|
-
describe('
|
|
18
|
+
describe('getCells', () => {
|
|
19
|
+
let registry: Registry.Registry;
|
|
21
20
|
let data: any[];
|
|
22
|
-
let updateCount: number;
|
|
23
21
|
let model: any;
|
|
24
22
|
let presentation: TablePresentation;
|
|
25
23
|
|
|
26
24
|
beforeEach(async () => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
model = createTableModel({
|
|
36
|
-
onCellUpdate: () => updateCount++,
|
|
37
|
-
});
|
|
38
|
-
model.setRows(data);
|
|
25
|
+
registry = Registry.make();
|
|
26
|
+
data = [
|
|
27
|
+
{ id: '1', title: 'A', count: 1 },
|
|
28
|
+
{ id: '2', title: 'B', count: 2 },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
model = createTableModel(registry, {});
|
|
39
32
|
await model.open();
|
|
40
|
-
|
|
33
|
+
model.setRows(data);
|
|
34
|
+
presentation = new TablePresentation(registry, model);
|
|
41
35
|
});
|
|
42
36
|
|
|
43
|
-
it('should
|
|
44
|
-
|
|
45
|
-
presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 1, col: 2 } }, 'grid');
|
|
37
|
+
it('should return cells for the visible range', () => {
|
|
38
|
+
const cells = presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 1, col: 2 } }, 'grid');
|
|
46
39
|
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
expect(
|
|
40
|
+
// Verify that cells are returned for the range. The exact column indices depend on the projection.
|
|
41
|
+
const cellKeys = Object.keys(cells);
|
|
42
|
+
expect(cellKeys.length).toBeGreaterThan(0);
|
|
50
43
|
|
|
51
|
-
//
|
|
52
|
-
const
|
|
53
|
-
expect(
|
|
44
|
+
// Check that values from the data are present in the cells.
|
|
45
|
+
const values = Object.values(cells).map((c) => c.value);
|
|
46
|
+
expect(values).toContain('A');
|
|
47
|
+
expect(values).toContain('B');
|
|
54
48
|
});
|
|
55
49
|
|
|
56
|
-
it('should
|
|
57
|
-
//
|
|
58
|
-
|
|
50
|
+
it('should reflect row data changes', () => {
|
|
51
|
+
// Update the row data and refresh.
|
|
52
|
+
data[0].title = 'New Value';
|
|
53
|
+
model.setRows(data);
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
// Verify the new value through getCells.
|
|
56
|
+
const cells = presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 0, col: 2 } }, 'grid');
|
|
57
|
+
const values = Object.values(cells).map((c) => c.value);
|
|
58
|
+
expect(values).toContain('New Value');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should reflect new rows', () => {
|
|
62
|
+
// Add a new row.
|
|
63
|
+
data.push({ id: '3', title: 'C', count: 3 });
|
|
64
|
+
model.setRows(data);
|
|
62
65
|
|
|
63
66
|
const cells = presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 2, col: 2 } }, 'grid');
|
|
64
67
|
|
|
65
68
|
// Verify the new row's data.
|
|
66
69
|
expect(cells['0,2']?.value).toBe('C');
|
|
67
70
|
expect(cells['1,2']?.value).toBe('3');
|
|
68
|
-
expect(cells['2,2']?.value).toBe('true');
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
it('should handle
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// Multiple operations.
|
|
76
|
-
data[0].col1 = 'Updated A';
|
|
77
|
-
data.push({ col1: 'C', col2: 3, col3: true });
|
|
73
|
+
it('should handle row modifications', () => {
|
|
74
|
+
// Modify the data.
|
|
75
|
+
data[0].title = 'Updated A';
|
|
76
|
+
data.push({ id: '3', title: 'C', count: 3 });
|
|
78
77
|
data.splice(1, 1);
|
|
79
|
-
|
|
80
|
-
// We expect one update per operation affecting visible rows.
|
|
81
|
-
expect(updateCount).toBe(3);
|
|
78
|
+
model.setRows(data);
|
|
82
79
|
|
|
83
80
|
const cells = presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 1, col: 2 } }, 'grid');
|
|
84
81
|
|
|
85
82
|
// Verify final state.
|
|
86
83
|
expect(cells['0,0']?.value).toBe('Updated A');
|
|
87
84
|
expect(cells['0,1']?.value).toBe('C');
|
|
88
|
-
expect(cells['1,1']?.value).toBe('3');
|
|
89
|
-
expect(cells['2,1']?.value).toBe('true');
|
|
90
85
|
});
|
|
91
86
|
});
|
|
92
87
|
});
|
|
93
88
|
|
|
94
|
-
|
|
89
|
+
const Test = Schema.Struct({
|
|
95
90
|
title: Schema.String,
|
|
96
|
-
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
count: Schema.Number,
|
|
92
|
+
}).pipe(
|
|
93
|
+
Type.object({
|
|
94
|
+
typename: 'com.example.type.test',
|
|
95
|
+
version: '0.1.0',
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const createTableModel = (registry: Registry.Registry, props: Partial<TableModelProps> = {}): TableModel => {
|
|
100
100
|
const schema = createEchoSchema(Test);
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
const view = ViewModel.make({
|
|
102
|
+
query: Query.select(Filter.type(schema)),
|
|
103
|
+
jsonSchema: schema.jsonSchema,
|
|
104
|
+
});
|
|
105
|
+
const object = Table.make({ view });
|
|
106
|
+
const projection = new ProjectionModel({
|
|
107
|
+
registry,
|
|
108
|
+
view,
|
|
109
|
+
baseSchema: schema.jsonSchema,
|
|
110
|
+
change: createDirectChangeCallback(view.projection, JsonSchema.toJsonSchema(schema)),
|
|
111
|
+
});
|
|
112
|
+
projection.normalizeView();
|
|
113
|
+
return new TableModel({ registry, object, projection, ...props });
|
|
104
114
|
};
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { Atom, type Registry } from '@effect-atom/atom-react';
|
|
6
|
+
import * as Predicate from 'effect/Predicate';
|
|
7
7
|
|
|
8
8
|
import { Obj } from '@dxos/echo';
|
|
9
|
-
import {
|
|
9
|
+
import { type View } from '@dxos/echo';
|
|
10
|
+
import { Format, TypeEnum, getValue } from '@dxos/echo/internal';
|
|
10
11
|
import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
|
|
11
12
|
import {
|
|
12
13
|
type DxGridCellValue,
|
|
@@ -15,11 +16,10 @@ import {
|
|
|
15
16
|
type DxGridPlaneRange,
|
|
16
17
|
toPlaneCellIndex,
|
|
17
18
|
} from '@dxos/react-ui-grid';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
19
|
+
import { VIEW_FIELD_LIMIT } from '@dxos/schema';
|
|
20
|
+
import { mx } from '@dxos/ui-theme';
|
|
20
21
|
|
|
21
22
|
import { tableButtons, tableControls } from '../util';
|
|
22
|
-
|
|
23
23
|
import { type SelectionMode } from './selection-model';
|
|
24
24
|
import { type TableModel, type TableRow } from './table-model';
|
|
25
25
|
|
|
@@ -29,15 +29,20 @@ import { type TableModel, type TableRow } from './table-model';
|
|
|
29
29
|
* different grid planes.
|
|
30
30
|
*/
|
|
31
31
|
export class TablePresentation<T extends TableRow = TableRow> {
|
|
32
|
+
private readonly _registry: Registry.Registry;
|
|
33
|
+
private readonly _visibleRange: Atom.Writable<DxGridPlaneRange>;
|
|
32
34
|
private fieldProjectionCache = new Map<string, ReturnType<typeof this.model.projection.getFieldProjection>>();
|
|
33
35
|
|
|
34
36
|
constructor(
|
|
37
|
+
registry: Registry.Registry,
|
|
35
38
|
private readonly model: TableModel<T>,
|
|
36
|
-
|
|
39
|
+
) {
|
|
40
|
+
this._registry = registry;
|
|
41
|
+
this._visibleRange = Atom.make<DxGridPlaneRange>({
|
|
37
42
|
start: { row: 0, col: 0 },
|
|
38
43
|
end: { row: 0, col: 0 },
|
|
39
|
-
})
|
|
40
|
-
|
|
44
|
+
});
|
|
45
|
+
}
|
|
41
46
|
|
|
42
47
|
public getCells(range: DxGridPlaneRange, plane: DxGridPlane): DxGridPlaneCells {
|
|
43
48
|
// Clear cache at the start of each render pass
|
|
@@ -47,7 +52,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
47
52
|
|
|
48
53
|
switch (plane) {
|
|
49
54
|
case 'grid':
|
|
50
|
-
this._visibleRange
|
|
55
|
+
this._registry.set(this._visibleRange, range);
|
|
51
56
|
cells = this.getMainGridCells(range);
|
|
52
57
|
break;
|
|
53
58
|
case 'frozenRowsStart':
|
|
@@ -69,7 +74,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
69
74
|
cells = this.getDraftRowCells(range);
|
|
70
75
|
break;
|
|
71
76
|
case 'fixedEndStart':
|
|
72
|
-
cells = this.
|
|
77
|
+
cells = this.getDraftIconCells(range);
|
|
73
78
|
break;
|
|
74
79
|
case 'fixedEndEnd':
|
|
75
80
|
cells = this.getDraftActionCells(range);
|
|
@@ -102,7 +107,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
102
107
|
private createDataCell(
|
|
103
108
|
cells: DxGridPlaneCells,
|
|
104
109
|
obj: T,
|
|
105
|
-
field: FieldType,
|
|
110
|
+
field: View.FieldType,
|
|
106
111
|
colIndex: number,
|
|
107
112
|
displayIndex: number,
|
|
108
113
|
): void {
|
|
@@ -120,12 +125,12 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
switch (props.format) {
|
|
123
|
-
case
|
|
124
|
-
case
|
|
125
|
-
case
|
|
128
|
+
case Format.TypeFormat.Boolean:
|
|
129
|
+
case Format.TypeFormat.SingleSelect:
|
|
130
|
+
case Format.TypeFormat.MultiSelect: {
|
|
126
131
|
return '';
|
|
127
132
|
}
|
|
128
|
-
case
|
|
133
|
+
case Format.TypeFormat.Ref: {
|
|
129
134
|
if (!field.referencePath) {
|
|
130
135
|
return ''; // TODO(burdon): Show error.
|
|
131
136
|
}
|
|
@@ -141,20 +146,22 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
141
146
|
};
|
|
142
147
|
|
|
143
148
|
const classes = [];
|
|
144
|
-
const formatClasses = cellClassesForFieldType(
|
|
149
|
+
const formatClasses = cellClassesForFieldType(props);
|
|
150
|
+
|
|
145
151
|
if (formatClasses) {
|
|
146
152
|
classes.push(formatClasses);
|
|
147
153
|
}
|
|
154
|
+
|
|
148
155
|
const rowSelectionClasses = cellClassesForRowSelection(
|
|
149
156
|
this.model.selection.isObjectSelected(obj),
|
|
150
157
|
this.model.selection.selectionMode,
|
|
151
158
|
);
|
|
159
|
+
|
|
152
160
|
if (rowSelectionClasses) {
|
|
153
161
|
classes.push(rowSelectionClasses);
|
|
154
162
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
163
|
+
|
|
164
|
+
cell.className = mx(classes);
|
|
158
165
|
|
|
159
166
|
// Arrays.
|
|
160
167
|
if (props.type === TypeEnum.Array) {
|
|
@@ -188,7 +195,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
188
195
|
|
|
189
196
|
const tags = targetArray
|
|
190
197
|
.map(getLabel)
|
|
191
|
-
.filter(isNotNullable)
|
|
198
|
+
.filter(Predicate.isNotNullable)
|
|
192
199
|
.map((title) => {
|
|
193
200
|
return `<span class="dx-tag" data-hue="neutral">${title}</span>`;
|
|
194
201
|
})
|
|
@@ -199,16 +206,16 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
199
206
|
}
|
|
200
207
|
|
|
201
208
|
// References.
|
|
202
|
-
if (props.format ===
|
|
209
|
+
if (props.format === Format.TypeFormat.Ref && props.referenceSchema) {
|
|
203
210
|
const targetObj = getValue(obj, field.path)?.target;
|
|
204
211
|
if (targetObj) {
|
|
205
212
|
const dxn = Obj.getDXN(targetObj)?.toString();
|
|
206
|
-
cell.accessoryHtml = `<dx-
|
|
213
|
+
cell.accessoryHtml = `<div role="none" class="absolute end-0 inset-y-0 p-(--dx-grid-cell-content-padding-block)"><dx-anchor dxn=${dxn} class="dx-button w-6 aspect-square min-h-0" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-anchor></div>`;
|
|
207
214
|
}
|
|
208
215
|
}
|
|
209
216
|
|
|
210
217
|
// Booleans.
|
|
211
|
-
if (props.format ===
|
|
218
|
+
if (props.format === Format.TypeFormat.Boolean) {
|
|
212
219
|
const value = getValue(obj, field.path);
|
|
213
220
|
cell.accessoryHtml = tableControls.switch.render({
|
|
214
221
|
colIndex,
|
|
@@ -219,7 +226,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
219
226
|
}
|
|
220
227
|
|
|
221
228
|
// Single-Selects.
|
|
222
|
-
if (props.format ===
|
|
229
|
+
if (props.format === Format.TypeFormat.SingleSelect) {
|
|
223
230
|
const value = getValue(obj, field.path);
|
|
224
231
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
225
232
|
if (options) {
|
|
@@ -231,7 +238,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
231
238
|
}
|
|
232
239
|
|
|
233
240
|
// Multi-Selects.
|
|
234
|
-
if (props.format ===
|
|
241
|
+
if (props.format === Format.TypeFormat.MultiSelect) {
|
|
235
242
|
const values = getValue(obj, field.path) as string[] | undefined;
|
|
236
243
|
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
237
244
|
if (options && values && values.length > 0) {
|
|
@@ -258,7 +265,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
258
265
|
|
|
259
266
|
private getMainGridCells(range: DxGridPlaneRange): DxGridPlaneCells {
|
|
260
267
|
const cells: DxGridPlaneCells = {};
|
|
261
|
-
const fields = this.model.projection?.
|
|
268
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
262
269
|
|
|
263
270
|
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
264
271
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
@@ -267,7 +274,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
267
274
|
continue;
|
|
268
275
|
}
|
|
269
276
|
|
|
270
|
-
this.createDataCell(cells, this.model.
|
|
277
|
+
this.createDataCell(cells, this.model.getRows()[row], field, col, row);
|
|
271
278
|
}
|
|
272
279
|
}
|
|
273
280
|
|
|
@@ -276,30 +283,39 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
276
283
|
|
|
277
284
|
private getDraftRowCells(range: DxGridPlaneRange): DxGridPlaneCells {
|
|
278
285
|
const cells: DxGridPlaneCells = {};
|
|
279
|
-
const fields = this.model.projection?.
|
|
280
|
-
const draftRows = this.model.
|
|
286
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
287
|
+
const draftRows = this.model.getDraftRows();
|
|
281
288
|
|
|
282
|
-
|
|
283
|
-
|
|
289
|
+
// Return cells of the CTA row if no draft row is active
|
|
290
|
+
if (draftRows.length === 0) {
|
|
284
291
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
292
|
+
cells[toPlaneCellIndex({ col, row: 0 })] = {
|
|
293
|
+
value: '',
|
|
294
|
+
readonly: true,
|
|
295
|
+
className: 'dx-grid__row--cta__cell',
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
|
|
300
|
+
const draftRow = draftRows[row];
|
|
301
|
+
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
302
|
+
const cellIndex = toPlaneCellIndex({ col, row });
|
|
303
|
+
const field = fields[col];
|
|
304
|
+
if (!field) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
290
307
|
|
|
291
|
-
|
|
308
|
+
this.createDataCell(cells, draftRow.data, field, col, row);
|
|
292
309
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
310
|
+
if (this.model.hasDraftRowValidationError(row, field.path)) {
|
|
311
|
+
const cellValue = cells[cellIndex];
|
|
312
|
+
if (cellValue) {
|
|
313
|
+
const existingClasses = cellValue.className || '';
|
|
314
|
+
const draftClasses = 'dx-grid__cell--flagged';
|
|
315
|
+
cellValue.className = existingClasses ? `${existingClasses} ${draftClasses}` : draftClasses;
|
|
316
|
+
}
|
|
299
317
|
}
|
|
300
318
|
}
|
|
301
|
-
|
|
302
|
-
cells[cellIndex].className += ' !bg-toolbarSurface';
|
|
303
319
|
}
|
|
304
320
|
}
|
|
305
321
|
|
|
@@ -308,22 +324,22 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
308
324
|
|
|
309
325
|
private getHeaderCells(range: DxGridPlaneRange): DxGridPlaneCells {
|
|
310
326
|
const cells: DxGridPlaneCells = {};
|
|
311
|
-
const fields = this.model.projection?.
|
|
327
|
+
const fields = this.model.projection?.getFields() ?? [];
|
|
328
|
+
const currentSort = this.model.getSorting();
|
|
312
329
|
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
313
330
|
const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
|
|
314
|
-
const
|
|
315
|
-
const direction = sorting?.fieldId === field.id ? sorting.direction : undefined;
|
|
331
|
+
const direction = currentSort?.fieldId === field.id ? currentSort.direction : undefined;
|
|
316
332
|
|
|
317
333
|
cells[toPlaneCellIndex({ col, row: 0 })] = {
|
|
318
334
|
// TODO(burdon): Use same logic as form for fallback title.
|
|
319
|
-
value:
|
|
320
|
-
readonly: true,
|
|
335
|
+
value: '',
|
|
321
336
|
resizeHandle: 'col',
|
|
322
337
|
accessoryHtml: `
|
|
338
|
+
<span class="grow min-w-0 truncate">${props.title ?? field.path}</span>
|
|
323
339
|
${direction !== undefined ? tableButtons.sort.render({ fieldId: field.id, direction }) : ''}
|
|
324
340
|
${tableButtons.columnSettings.render({ fieldId: field.id })}
|
|
325
341
|
`,
|
|
326
|
-
className: '!bg-
|
|
342
|
+
className: '!bg-toolbar-surface text-description! [&>div]:flex [&>div]:items-stretch',
|
|
327
343
|
};
|
|
328
344
|
}
|
|
329
345
|
|
|
@@ -366,7 +382,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
366
382
|
if (!this.model.features.selection.enabled || this.model.selection.selectionMode === 'single') {
|
|
367
383
|
return {
|
|
368
384
|
[toPlaneCellIndex({ col: 0, row: 0 })]: {
|
|
369
|
-
className: '!bg-
|
|
385
|
+
className: '!bg-toolbar-surface',
|
|
370
386
|
readonly: true,
|
|
371
387
|
value: '',
|
|
372
388
|
},
|
|
@@ -378,9 +394,9 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
378
394
|
accessoryHtml: tableControls.checkbox.render({
|
|
379
395
|
rowIndex: 0,
|
|
380
396
|
header: true,
|
|
381
|
-
checked: this.model.selection.
|
|
397
|
+
checked: this.model.selection.allRowsSelected,
|
|
382
398
|
}),
|
|
383
|
-
className: '!bg-
|
|
399
|
+
className: '!bg-toolbar-surface',
|
|
384
400
|
readonly: true,
|
|
385
401
|
value: '',
|
|
386
402
|
},
|
|
@@ -392,10 +408,10 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
392
408
|
[toPlaneCellIndex({ col: 0, row: 0 })]: {
|
|
393
409
|
accessoryHtml: this.model.features.schemaEditable
|
|
394
410
|
? tableButtons.addColumn.render({
|
|
395
|
-
disabled: (this.model.projection?.
|
|
411
|
+
disabled: (this.model.projection?.getFields()?.length ?? 0) >= VIEW_FIELD_LIMIT,
|
|
396
412
|
})
|
|
397
413
|
: undefined,
|
|
398
|
-
className: '!bg-
|
|
414
|
+
className: '!bg-toolbar-surface',
|
|
399
415
|
readonly: true,
|
|
400
416
|
value: '',
|
|
401
417
|
},
|
|
@@ -404,32 +420,41 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
404
420
|
|
|
405
421
|
private getDraftActionCells(range: DxGridPlaneRange): DxGridPlaneCells {
|
|
406
422
|
const cells: DxGridPlaneCells = {};
|
|
407
|
-
const draftRows = this.model.
|
|
408
|
-
|
|
409
|
-
for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
|
|
410
|
-
const draftRow = draftRows[row];
|
|
411
|
-
const disabled = !draftRow.valid;
|
|
423
|
+
const draftRows = this.model.getDraftRows();
|
|
412
424
|
|
|
413
|
-
|
|
425
|
+
// Return cells of the CTA row if no draft row is active
|
|
426
|
+
if (draftRows.length === 0) {
|
|
427
|
+
cells[toPlaneCellIndex({ col: 0, row: 0 })] = {
|
|
414
428
|
value: '',
|
|
429
|
+
className: 'dx-grid__row--cta__cell',
|
|
415
430
|
readonly: true,
|
|
416
|
-
accessoryHtml: tableButtons.saveDraftRow.render({ rowIndex: row, disabled }),
|
|
417
|
-
className: '!bg-toolbarSurface',
|
|
418
431
|
};
|
|
432
|
+
} else {
|
|
433
|
+
for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
|
|
434
|
+
const draftRow = draftRows[row];
|
|
435
|
+
const disabled = !draftRow.valid;
|
|
436
|
+
|
|
437
|
+
cells[toPlaneCellIndex({ col: 0, row })] = {
|
|
438
|
+
value: '',
|
|
439
|
+
readonly: true,
|
|
440
|
+
accessoryHtml: tableButtons.saveDraftRow.render({ rowIndex: row, disabled }),
|
|
441
|
+
};
|
|
442
|
+
}
|
|
419
443
|
}
|
|
420
444
|
|
|
421
445
|
return cells;
|
|
422
446
|
}
|
|
423
447
|
|
|
424
|
-
private
|
|
448
|
+
private getDraftIconCells(range: DxGridPlaneRange): DxGridPlaneCells {
|
|
425
449
|
const cells: DxGridPlaneCells = {};
|
|
426
|
-
const draftRows = this.model.
|
|
450
|
+
const draftRows = this.model.getDraftRows();
|
|
427
451
|
|
|
428
|
-
for (let row = range.start.row; row <= range.end.row
|
|
452
|
+
for (let row = range.start.row; row <= range.end.row; row++) {
|
|
429
453
|
cells[toPlaneCellIndex({ col: 0, row })] = {
|
|
430
454
|
value: '',
|
|
431
455
|
readonly: true,
|
|
432
|
-
|
|
456
|
+
accessoryHtml: '<dx-icon icon="ph--plus--regular" class="contents"></dx-icon>',
|
|
457
|
+
className: mx('[&>div]:grid [&>div]:place-content-center', draftRows.length < 1 && 'dx-grid__row--cta__cell'),
|
|
433
458
|
};
|
|
434
459
|
}
|
|
435
460
|
|
|
@@ -440,7 +465,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
440
465
|
export const cellClassesForRowSelection = (selected: boolean, selectionMode: SelectionMode) => {
|
|
441
466
|
if (!selected) {
|
|
442
467
|
if (selectionMode === 'single') {
|
|
443
|
-
return ['
|
|
468
|
+
return ['cursor-pointer!'];
|
|
444
469
|
} else {
|
|
445
470
|
return undefined;
|
|
446
471
|
}
|
|
@@ -448,9 +473,8 @@ export const cellClassesForRowSelection = (selected: boolean, selectionMode: Sel
|
|
|
448
473
|
|
|
449
474
|
switch (selectionMode) {
|
|
450
475
|
case 'single':
|
|
451
|
-
|
|
452
|
-
return ['!bg-currentRelated dx-grid__cell--no-focus-unfurl hover:bg-hoverSurface !cursor-pointer'];
|
|
476
|
+
return ['dx-grid__cell--no-focus-unfurl !bg-current-surface hover:bg-hover-surface cursor-pointer!'];
|
|
453
477
|
case 'multiple':
|
|
454
|
-
return ['!bg-
|
|
478
|
+
return ['!bg-grid-cell-selected'];
|
|
455
479
|
}
|
|
456
480
|
};
|
|
@@ -17,6 +17,7 @@ const TABLE_SELECTORS = {
|
|
|
17
17
|
},
|
|
18
18
|
columnDelete: 'column-delete',
|
|
19
19
|
rowDelete: 'row-menu-delete',
|
|
20
|
+
addRow: 'table.toolbar.add-row',
|
|
20
21
|
} as const;
|
|
21
22
|
|
|
22
23
|
export class TableManager {
|
|
@@ -53,12 +54,18 @@ export class TableManager {
|
|
|
53
54
|
await this.page.getByTestId(TABLE_SELECTORS.columnSort[direction]).click();
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
public async
|
|
57
|
+
public async addRow(): Promise<void> {
|
|
58
|
+
await this.page.getByTestId(TABLE_SELECTORS.addRow).click();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public async addColumn({ label, format }: { label: string; format?: string }): Promise<void> {
|
|
57
62
|
await this.page.getByTestId(TABLE_SELECTORS.newColumnButton).click();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
await this.page.
|
|
63
|
+
if (format) {
|
|
64
|
+
await this.page.getByRole('combobox').click();
|
|
65
|
+
await this.page.getByLabel(format).click();
|
|
66
|
+
}
|
|
67
|
+
await this.page.getByPlaceholder('Property label').click();
|
|
68
|
+
await this.page.getByPlaceholder('Property label').fill(label);
|
|
69
|
+
await this.page.getByRole('button', { name: 'Save' }).click();
|
|
63
70
|
}
|
|
64
71
|
}
|
|
@@ -10,7 +10,7 @@ export default defineConfig({
|
|
|
10
10
|
...e2ePreset(import.meta.dirname),
|
|
11
11
|
// TODO(wittjosiah): Avoid hard-coding ports.
|
|
12
12
|
webServer: {
|
|
13
|
-
command: '
|
|
13
|
+
command: 'pnpm storybook dev --ci --quiet --port=9004 --config-dir=.storybook',
|
|
14
14
|
port: 9004,
|
|
15
15
|
reuseExistingServer: false,
|
|
16
16
|
},
|