@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
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { useCallback, useMemo } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { create } from '@dxos/live-object';
|
|
8
8
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
9
9
|
import {
|
|
10
10
|
createGapSeparator,
|
|
11
11
|
createMenuAction,
|
|
12
12
|
type MenuAction,
|
|
13
|
+
type MenuActionHandler,
|
|
13
14
|
MenuProvider,
|
|
14
15
|
ToolbarMenu,
|
|
15
16
|
useMenuActions,
|
|
@@ -26,18 +27,18 @@ export type TableToolbarActionType = 'add-row' | 'comment' | 'save-view';
|
|
|
26
27
|
type TableToolbarState = Partial<{ viewDirty: boolean }>;
|
|
27
28
|
|
|
28
29
|
export type TableToolbarProps = ThemedClassName<
|
|
29
|
-
TableToolbarState & { onAction
|
|
30
|
+
TableToolbarState & { onAction?: MenuActionHandler<TableToolbarAction>; attendableId?: string }
|
|
30
31
|
>;
|
|
31
32
|
|
|
32
|
-
const createTableToolbarActions = (state: TableToolbarState
|
|
33
|
-
const add = createMenuAction<TableToolbarActionProperties>('add-row',
|
|
34
|
-
type: 'add-row'
|
|
33
|
+
const createTableToolbarActions = (state: TableToolbarState) => {
|
|
34
|
+
const add = createMenuAction<TableToolbarActionProperties>('add-row', {
|
|
35
|
+
type: 'add-row',
|
|
35
36
|
icon: 'ph--plus--regular',
|
|
36
37
|
label: ['add row', { ns: translationKey }],
|
|
37
38
|
testId: 'table.toolbar.add-row',
|
|
38
39
|
});
|
|
39
|
-
const save = createMenuAction<TableToolbarActionProperties>('save-view',
|
|
40
|
-
type: 'save-view'
|
|
40
|
+
const save = createMenuAction<TableToolbarActionProperties>('save-view', {
|
|
41
|
+
type: 'save-view',
|
|
41
42
|
icon: 'ph--floppy-disk--regular',
|
|
42
43
|
label: ['save view label', { ns: translationKey }],
|
|
43
44
|
testId: 'table.toolbar.save-view',
|
|
@@ -45,8 +46,8 @@ const createTableToolbarActions = (state: TableToolbarState, onAction: (action:
|
|
|
45
46
|
hidden: !state.viewDirty,
|
|
46
47
|
});
|
|
47
48
|
const gap = createGapSeparator();
|
|
48
|
-
const comment = createMenuAction('comment',
|
|
49
|
-
type: 'comment'
|
|
49
|
+
const comment = createMenuAction('comment', {
|
|
50
|
+
type: 'comment',
|
|
50
51
|
icon: 'ph--chat-text--regular',
|
|
51
52
|
label: ['create comment', { ns: translationKey }],
|
|
52
53
|
testId: 'table.toolbar.comment',
|
|
@@ -59,12 +60,12 @@ const createTableToolbarActions = (state: TableToolbarState, onAction: (action:
|
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
export const TableToolbar = ({ classNames, viewDirty, attendableId, onAction }: TableToolbarProps) => {
|
|
62
|
-
const state = useMemo(() =>
|
|
63
|
-
const actionsCreator = useCallback(() => createTableToolbarActions(state
|
|
63
|
+
const state = useMemo(() => create<TableToolbarState>({ viewDirty }), []);
|
|
64
|
+
const actionsCreator = useCallback(() => createTableToolbarActions(state), [state]);
|
|
64
65
|
const menu = useMenuActions(actionsCreator);
|
|
65
66
|
|
|
66
67
|
return (
|
|
67
|
-
<MenuProvider {...menu} attendableId={attendableId}>
|
|
68
|
+
<MenuProvider {...menu} attendableId={attendableId} onAction={onAction as MenuActionHandler}>
|
|
68
69
|
<ToolbarMenu classNames={classNames} />
|
|
69
70
|
</MenuProvider>
|
|
70
71
|
);
|
|
@@ -2,26 +2,25 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema } from 'effect';
|
|
6
5
|
import { useEffect } from 'react';
|
|
7
6
|
|
|
8
|
-
import { setValue, toJsonSchema, TypeEnum, TypedObject, FormatEnum
|
|
7
|
+
import { setValue, toJsonSchema, S, TypeEnum, TypedObject, FormatEnum } from '@dxos/echo-schema';
|
|
9
8
|
import { faker } from '@dxos/random';
|
|
10
|
-
import {
|
|
9
|
+
import { create, makeRef } from '@dxos/react-client/echo';
|
|
11
10
|
import { createView, type ViewProjection } from '@dxos/schema';
|
|
12
11
|
|
|
13
12
|
import { TableType } from '../types';
|
|
14
13
|
|
|
15
14
|
export const TestSchema = TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
|
|
16
|
-
id:
|
|
17
|
-
name:
|
|
18
|
-
age:
|
|
19
|
-
active:
|
|
20
|
-
netWorth:
|
|
15
|
+
id: S.String,
|
|
16
|
+
name: S.optional(S.String),
|
|
17
|
+
age: S.optional(S.Number),
|
|
18
|
+
active: S.optional(S.Boolean),
|
|
19
|
+
netWorth: S.optional(S.Number),
|
|
21
20
|
});
|
|
22
21
|
|
|
23
22
|
export const createTable = (schema = TestSchema) => {
|
|
24
|
-
return
|
|
23
|
+
return create(TableType, {
|
|
25
24
|
view: makeRef(
|
|
26
25
|
createView({
|
|
27
26
|
name: 'Test',
|
|
@@ -33,7 +32,7 @@ export const createTable = (schema = TestSchema) => {
|
|
|
33
32
|
};
|
|
34
33
|
|
|
35
34
|
export const createItems = (n: number) => {
|
|
36
|
-
const { data } =
|
|
35
|
+
const { data } = create({
|
|
37
36
|
data: Array.from({ length: n }, () => ({
|
|
38
37
|
name: faker.person.fullName(),
|
|
39
38
|
age: faker.number.int({ min: 20, max: 70 }),
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { effect } from '@preact/signals-core';
|
|
6
6
|
import { useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import { fullyQualifiedId, getSpace, type
|
|
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';
|
|
@@ -16,7 +16,7 @@ import { type TableType } from '../types';
|
|
|
16
16
|
export type UseTableModelParams<T extends TableRow = TableRow> = {
|
|
17
17
|
table?: TableType;
|
|
18
18
|
projection?: ViewProjection;
|
|
19
|
-
rows?:
|
|
19
|
+
rows?: ReactiveObject<T>[];
|
|
20
20
|
rowActions?: TableRowAction[];
|
|
21
21
|
onSelectionChanged?: (selection: string[]) => void;
|
|
22
22
|
onRowAction?: (actionId: string, data: T) => void;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { signal } from '@preact/signals-core';
|
|
6
6
|
import { type RefObject, type MutableRefObject } from 'react';
|
|
7
7
|
|
|
8
|
-
import { type
|
|
8
|
+
import { type ReactiveObject } from '@dxos/live-object';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
|
|
11
11
|
export type ColumnSettingsMode = { type: 'create' } | { type: 'edit'; fieldId: string };
|
|
@@ -18,7 +18,7 @@ export type ModalState =
|
|
|
18
18
|
type: 'createRefPanel';
|
|
19
19
|
typename: string;
|
|
20
20
|
initialValues?: Record<string, string>;
|
|
21
|
-
onCreate?: (obj:
|
|
21
|
+
onCreate?: (obj: ReactiveObject<any>) => void;
|
|
22
22
|
}
|
|
23
23
|
| { type: 'columnSettings'; mode: ColumnSettingsMode }
|
|
24
24
|
| { type: 'closed' };
|
|
@@ -72,7 +72,7 @@ export class ModalController {
|
|
|
72
72
|
typename: string,
|
|
73
73
|
anchorCell: Element | null,
|
|
74
74
|
initialValues?: Record<string, string>,
|
|
75
|
-
onCreate?: (obj:
|
|
75
|
+
onCreate?: (obj: ReactiveObject<any>) => void,
|
|
76
76
|
) => {
|
|
77
77
|
if (anchorCell) {
|
|
78
78
|
this._triggerRef.current = anchorCell as HTMLElement;
|
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { computed } from '@preact/signals-core';
|
|
6
|
-
import { Schema } from 'effect';
|
|
7
6
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
8
7
|
|
|
9
|
-
import { TypedObject } from '@dxos/echo-schema';
|
|
8
|
+
import { S, TypedObject } from '@dxos/echo-schema';
|
|
10
9
|
import { updateCounter } from '@dxos/echo-schema/testing';
|
|
11
10
|
import { registerSignalsRuntime } from '@dxos/echo-signals';
|
|
12
11
|
import { createEchoSchema } from '@dxos/live-object/testing';
|
|
13
|
-
import {
|
|
12
|
+
import { create, makeRef } from '@dxos/react-client/echo';
|
|
14
13
|
import { createView, ViewProjection } from '@dxos/schema';
|
|
15
14
|
|
|
16
15
|
import { TableModel, type TableModelProps } from './table-model';
|
|
@@ -70,7 +69,7 @@ describe('TableModel', () => {
|
|
|
70
69
|
|
|
71
70
|
describe('reactivity', () => {
|
|
72
71
|
it('pure signals should nest', () => {
|
|
73
|
-
const signal$ =
|
|
72
|
+
const signal$ = create({ arr: [{ thingInside: 1 }, { thingInside: 2 }] });
|
|
74
73
|
|
|
75
74
|
const computed$ = computed(() => {
|
|
76
75
|
return signal$.arr.map((row) =>
|
|
@@ -100,14 +99,14 @@ describe('TableModel', () => {
|
|
|
100
99
|
});
|
|
101
100
|
|
|
102
101
|
class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
|
|
103
|
-
title:
|
|
104
|
-
completed:
|
|
102
|
+
title: S.String,
|
|
103
|
+
completed: S.Boolean,
|
|
105
104
|
}) {}
|
|
106
105
|
|
|
107
106
|
const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
|
|
108
107
|
const schema = createEchoSchema(Test);
|
|
109
108
|
const view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
|
|
110
109
|
const projection = new ViewProjection(schema.jsonSchema, view);
|
|
111
|
-
const table =
|
|
110
|
+
const table = create(TableType, { view: makeRef(view) });
|
|
112
111
|
return new TableModel({ id: table.id, space: undefined, view, projection, ...props });
|
|
113
112
|
};
|
package/src/model/table-model.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { type Space } from '@dxos/client/echo';
|
|
|
8
8
|
import { Resource } from '@dxos/context';
|
|
9
9
|
import { type FieldSortType, FormatEnum, getValue, setValue, type JsonProp } from '@dxos/echo-schema';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
|
-
import {
|
|
11
|
+
import { isReactiveObject, makeRef } from '@dxos/live-object';
|
|
12
12
|
import { formatForEditing, parseValue } from '@dxos/react-ui-form';
|
|
13
13
|
import {
|
|
14
14
|
type DxGridAxisMeta,
|
|
@@ -21,7 +21,6 @@ import { type ViewType, type ViewProjection } from '@dxos/schema';
|
|
|
21
21
|
import { type SelectionMode, SelectionModel } from './selection-model';
|
|
22
22
|
import { TableSorting } from './table-sorting';
|
|
23
23
|
import { touch } from '../util';
|
|
24
|
-
import { extractTagIds } from '../util/tag';
|
|
25
24
|
|
|
26
25
|
// TODO(burdon): Use schema types.
|
|
27
26
|
export type TableRow = Record<JsonProp, any> & { id: string };
|
|
@@ -343,28 +342,12 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
|
|
|
343
342
|
case FormatEnum.Ref: {
|
|
344
343
|
// TODO(ZaymonFC): This get's called an additional time by the cell editor onBlur, but with the cell editors
|
|
345
344
|
// plain string value. Maybe onBlur should be called with the actual value?
|
|
346
|
-
if (
|
|
345
|
+
if (isReactiveObject(value)) {
|
|
347
346
|
setValue(this._rows.value[rowIdx], field.path, makeRef(value));
|
|
348
347
|
}
|
|
349
348
|
break;
|
|
350
349
|
}
|
|
351
350
|
|
|
352
|
-
case FormatEnum.SingleSelect: {
|
|
353
|
-
const ids = extractTagIds(value);
|
|
354
|
-
if (ids && ids.length > 0) {
|
|
355
|
-
setValue(this._rows.value[rowIdx], field.path, ids[0]);
|
|
356
|
-
}
|
|
357
|
-
break;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
case FormatEnum.MultiSelect: {
|
|
361
|
-
const ids = extractTagIds(value);
|
|
362
|
-
if (ids) {
|
|
363
|
-
setValue(this._rows.value[rowIdx], field.path, ids);
|
|
364
|
-
}
|
|
365
|
-
break;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
351
|
default: {
|
|
369
352
|
setValue(
|
|
370
353
|
this._rows.value[rowIdx],
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema } from 'effect';
|
|
6
5
|
import { describe, expect, it, beforeEach } from 'vitest';
|
|
7
6
|
|
|
8
|
-
import { TypedObject } from '@dxos/echo-schema';
|
|
9
|
-
import {
|
|
7
|
+
import { S, TypedObject } from '@dxos/echo-schema';
|
|
8
|
+
import { create, makeRef } from '@dxos/live-object';
|
|
10
9
|
import { createEchoSchema } from '@dxos/live-object/testing';
|
|
11
10
|
import { createView, ViewProjection } from '@dxos/schema';
|
|
12
11
|
|
|
@@ -23,7 +22,7 @@ describe('TablePresentation', () => {
|
|
|
23
22
|
|
|
24
23
|
beforeEach(async () => {
|
|
25
24
|
updateCount = 0;
|
|
26
|
-
({ data } =
|
|
25
|
+
({ data } = create({
|
|
27
26
|
data: [
|
|
28
27
|
{ col1: 'A', col2: 1, col3: true },
|
|
29
28
|
{ col1: 'B', col2: 2, col3: false },
|
|
@@ -90,14 +89,14 @@ describe('TablePresentation', () => {
|
|
|
90
89
|
});
|
|
91
90
|
|
|
92
91
|
class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
|
|
93
|
-
title:
|
|
94
|
-
completed:
|
|
92
|
+
title: S.String,
|
|
93
|
+
completed: S.Boolean,
|
|
95
94
|
}) {}
|
|
96
95
|
|
|
97
96
|
const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
|
|
98
97
|
const schema = createEchoSchema(Test);
|
|
99
98
|
const view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
|
|
100
99
|
const projection = new ViewProjection(schema.jsonSchema, view);
|
|
101
|
-
const table =
|
|
100
|
+
const table = create(TableType, { view: makeRef(view) });
|
|
102
101
|
return new TableModel({ id: table.id, view, projection, ...props });
|
|
103
102
|
};
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { signal } from '@preact/signals-core';
|
|
6
|
-
import { isNotNullable } from 'effect/Predicate';
|
|
7
6
|
|
|
8
|
-
import { FormatEnum,
|
|
7
|
+
import { FormatEnum, getValue } from '@dxos/echo-schema';
|
|
9
8
|
import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
|
|
10
9
|
import {
|
|
11
10
|
type DxGridPlane,
|
|
@@ -85,10 +84,6 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
85
84
|
return '';
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
if (props.type === 'array') {
|
|
89
|
-
return '';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
87
|
switch (props.format) {
|
|
93
88
|
case FormatEnum.Boolean:
|
|
94
89
|
case FormatEnum.SingleSelect:
|
|
@@ -126,52 +121,13 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
126
121
|
cell.className = mx(classes.flat());
|
|
127
122
|
}
|
|
128
123
|
|
|
129
|
-
if (props.type === TypeEnum.Array) {
|
|
130
|
-
const targetArray = getValue(obj, field.path);
|
|
131
|
-
if (targetArray && Array.isArray(targetArray)) {
|
|
132
|
-
// TODO(ZaymonFC): For arrays of objects, objects should have a 'label' annotation on the field
|
|
133
|
-
// that can be used to render tags.
|
|
134
|
-
// TODO(ZaymonFC): Move to util.
|
|
135
|
-
const getLabel = (value: any) => {
|
|
136
|
-
// If the value is falsy, return undefined
|
|
137
|
-
// If the object is an array, check for 'name' property
|
|
138
|
-
// If the object is a primitive type (string, number, boolean) stringify
|
|
139
|
-
// If the object is an array return 'Array'
|
|
140
|
-
if (!value) {
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
-
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
144
|
-
return String(value);
|
|
145
|
-
}
|
|
146
|
-
if (Array.isArray(value)) {
|
|
147
|
-
return 'Array';
|
|
148
|
-
}
|
|
149
|
-
if (typeof value === 'object' && value.name) {
|
|
150
|
-
return value.name;
|
|
151
|
-
}
|
|
152
|
-
if (typeof value === 'object' && value.value) {
|
|
153
|
-
return `${value.value}`;
|
|
154
|
-
}
|
|
155
|
-
return 'Object';
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const tags = targetArray
|
|
159
|
-
.map(getLabel)
|
|
160
|
-
.filter(isNotNullable)
|
|
161
|
-
.map((title) => {
|
|
162
|
-
return `<span class="dx-tag rounded-xl" data-hue="neutral">${title}</span>`;
|
|
163
|
-
})
|
|
164
|
-
.join('');
|
|
165
|
-
|
|
166
|
-
cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
124
|
if (props.format === FormatEnum.Ref && props.referenceSchema) {
|
|
171
125
|
const targetObj = getValue(obj, field.path)?.target;
|
|
172
126
|
if (targetObj) {
|
|
173
|
-
|
|
174
|
-
|
|
127
|
+
cell.accessoryHtml = tableButtons.referencedCell.render({
|
|
128
|
+
targetId: targetObj.id as any as string,
|
|
129
|
+
schemaId: props.referenceSchema,
|
|
130
|
+
});
|
|
175
131
|
}
|
|
176
132
|
}
|
|
177
133
|
|
|
@@ -212,7 +168,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
212
168
|
.join(' ');
|
|
213
169
|
|
|
214
170
|
if (tags) {
|
|
215
|
-
cell.accessoryHtml =
|
|
171
|
+
cell.accessoryHtml = tags;
|
|
216
172
|
}
|
|
217
173
|
}
|
|
218
174
|
}
|
|
@@ -252,7 +208,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
252
208
|
${direction !== undefined ? tableButtons.sort.render({ fieldId: field.id, direction }) : ''}
|
|
253
209
|
${tableButtons.columnSettings.render({ fieldId: field.id })}
|
|
254
210
|
`,
|
|
255
|
-
className: '!bg-
|
|
211
|
+
className: '!bg-gridHeader',
|
|
256
212
|
};
|
|
257
213
|
}
|
|
258
214
|
|
|
@@ -295,7 +251,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
295
251
|
if (!this.model.features.selection.enabled || this.model.selection.selectionMode === 'single') {
|
|
296
252
|
return {
|
|
297
253
|
[toPlaneCellIndex({ col: 0, row: 0 })]: {
|
|
298
|
-
className: '!bg-
|
|
254
|
+
className: '!bg-gridHeader',
|
|
299
255
|
readonly: true,
|
|
300
256
|
value: '',
|
|
301
257
|
},
|
|
@@ -309,7 +265,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
309
265
|
header: true,
|
|
310
266
|
checked: this.model.selection.allRowsSeleted.value,
|
|
311
267
|
}),
|
|
312
|
-
className: '!bg-
|
|
268
|
+
className: '!bg-gridHeader',
|
|
313
269
|
readonly: true,
|
|
314
270
|
value: '',
|
|
315
271
|
},
|
|
@@ -324,7 +280,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
324
280
|
disabled: (this.model.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT,
|
|
325
281
|
})
|
|
326
282
|
: undefined,
|
|
327
|
-
className: '!bg-
|
|
283
|
+
className: '!bg-gridHeader',
|
|
328
284
|
readonly: true,
|
|
329
285
|
value: '',
|
|
330
286
|
},
|
package/src/types/table.ts
CHANGED
|
@@ -2,28 +2,20 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';
|
|
7
6
|
// import { ThreadType } from '@dxos/plugin-space/types';
|
|
8
|
-
import { LabelAnnotationId, ObjectId, Ref, Expando, EchoObject } from '@dxos/echo-schema';
|
|
9
7
|
import { ViewType } from '@dxos/schema';
|
|
10
8
|
|
|
11
|
-
export const TableSchema =
|
|
9
|
+
export const TableSchema = S.Struct({
|
|
12
10
|
id: ObjectId,
|
|
13
|
-
name:
|
|
14
|
-
view:
|
|
11
|
+
name: S.optional(S.String),
|
|
12
|
+
view: S.optional(Ref(ViewType)),
|
|
15
13
|
// TODO(burdon): Document why threads is included here?
|
|
16
|
-
threads:
|
|
14
|
+
threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),
|
|
17
15
|
}).annotations({
|
|
18
16
|
// TODO(burdon): Move annotation to property.
|
|
19
17
|
[LabelAnnotationId]: 'name',
|
|
20
18
|
});
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
export
|
|
24
|
-
EchoObject({
|
|
25
|
-
typename: 'dxos.org/type/Table',
|
|
26
|
-
version: '0.1.0',
|
|
27
|
-
}),
|
|
28
|
-
);
|
|
29
|
-
export interface TableType extends Schema.Schema.Type<typeof TableType> {}
|
|
20
|
+
export const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));
|
|
21
|
+
export interface TableType extends S.Schema.Type<typeof TableType> {}
|
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
import { getTypename, toJsonSchema } from '@dxos/echo-schema';
|
|
8
|
-
import type { JsonSchemaType, SortDirectionType } from '@dxos/echo-schema';
|
|
9
|
-
import { live, makeRef } from '@dxos/live-object';
|
|
5
|
+
import type { BaseSchema, JsonSchemaType, SortDirectionType } from '@dxos/echo-schema';
|
|
6
|
+
import { create, makeRef } from '@dxos/live-object';
|
|
10
7
|
import {
|
|
11
8
|
createView,
|
|
12
9
|
getSchemaFromPropertyDefinitions,
|
|
@@ -30,7 +27,7 @@ export type TablePropertyDefinition = SchemaPropertyDefinition & Partial<Propert
|
|
|
30
27
|
* @deprecated
|
|
31
28
|
*/
|
|
32
29
|
// TODO(burdon): Remove variance.
|
|
33
|
-
export const
|
|
30
|
+
export const getBaseSchems = ({
|
|
34
31
|
typename,
|
|
35
32
|
properties,
|
|
36
33
|
jsonSchema,
|
|
@@ -39,13 +36,13 @@ export const getBaseSchema = ({
|
|
|
39
36
|
typename?: string;
|
|
40
37
|
properties?: TablePropertyDefinition[];
|
|
41
38
|
jsonSchema?: JsonSchemaType;
|
|
42
|
-
schema?:
|
|
39
|
+
schema?: BaseSchema;
|
|
43
40
|
}): { typename: string; jsonSchema: JsonSchemaType } => {
|
|
44
41
|
if (typename && properties) {
|
|
45
42
|
const schema = getSchemaFromPropertyDefinitions(typename, properties);
|
|
46
43
|
return { typename: schema.typename, jsonSchema: schema.jsonSchema };
|
|
47
44
|
} else if (schema) {
|
|
48
|
-
return { typename:
|
|
45
|
+
return { typename: schema.typename, jsonSchema: schema.jsonSchema };
|
|
49
46
|
} else if (typename && jsonSchema) {
|
|
50
47
|
return { typename, jsonSchema };
|
|
51
48
|
} else {
|
|
@@ -69,7 +66,7 @@ export const makeDynamicTable = ({
|
|
|
69
66
|
...(properties && { fields: properties.map((property) => property.name) }),
|
|
70
67
|
});
|
|
71
68
|
|
|
72
|
-
const table =
|
|
69
|
+
const table = create(TableType, { name: 'dynamic-table', view: makeRef(view) });
|
|
73
70
|
const projection = new ViewProjection(jsonSchema, view);
|
|
74
71
|
if (properties && view.fields) {
|
|
75
72
|
setProperties(view, projection, properties);
|
package/src/util/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export const BUTTON_IDENTIFIERS: { [K in TableButton]: string } = {
|
|
|
15
15
|
type ButtonData =
|
|
16
16
|
| { type: 'columnSettings'; fieldId: string }
|
|
17
17
|
| { type: 'newColumn'; disabled?: boolean }
|
|
18
|
+
| { type: 'referencedCell'; schemaId: string; targetId: string }
|
|
18
19
|
| { type: 'rowMenu'; rowIndex: number }
|
|
19
20
|
| { type: 'sort'; fieldId: string; direction?: 'asc' | 'desc' };
|
|
20
21
|
|
|
@@ -75,6 +76,27 @@ const columnSettingsButton = {
|
|
|
75
76
|
}),
|
|
76
77
|
} as const;
|
|
77
78
|
|
|
79
|
+
const referencedCellButton = {
|
|
80
|
+
attr: BUTTON_IDENTIFIERS.referencedCell,
|
|
81
|
+
icon: 'ph--link-simple-horizontal--regular',
|
|
82
|
+
render: ({ targetId, schemaId }: Omit<Extract<ButtonData, { type: 'referencedCell' }>, 'type'>) => {
|
|
83
|
+
return createButton({
|
|
84
|
+
attr: BUTTON_IDENTIFIERS.referencedCell,
|
|
85
|
+
icon: referencedCellButton.icon,
|
|
86
|
+
data: {
|
|
87
|
+
'data-target-id': targetId,
|
|
88
|
+
'data-schema-id': schemaId,
|
|
89
|
+
},
|
|
90
|
+
testId: 'table-ref-cell-button',
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
getData: (el: HTMLElement): Extract<ButtonData, { type: 'referencedCell' }> => ({
|
|
94
|
+
type: 'referencedCell',
|
|
95
|
+
targetId: el.getAttribute('data-target-id')!,
|
|
96
|
+
schemaId: el.getAttribute('data-schema-id')!,
|
|
97
|
+
}),
|
|
98
|
+
} as const;
|
|
99
|
+
|
|
78
100
|
const rowMenuButton = {
|
|
79
101
|
attr: BUTTON_IDENTIFIERS.rowMenu,
|
|
80
102
|
icon: 'ph--dots-three--regular',
|
|
@@ -121,6 +143,7 @@ const sortButton = {
|
|
|
121
143
|
export const tableButtons = {
|
|
122
144
|
addColumn: addColumnButton,
|
|
123
145
|
columnSettings: columnSettingsButton,
|
|
146
|
+
referencedCell: referencedCellButton,
|
|
124
147
|
rowMenu: rowMenuButton,
|
|
125
148
|
sort: sortButton,
|
|
126
149
|
} as const;
|
package/src/util/table.ts
CHANGED
|
@@ -2,20 +2,19 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Schema, SchemaAST } from 'effect';
|
|
6
|
-
|
|
7
5
|
import {
|
|
6
|
+
AST,
|
|
8
7
|
type EchoSchema,
|
|
9
8
|
Format,
|
|
10
9
|
FormatEnum,
|
|
11
10
|
type JsonPath,
|
|
12
11
|
type JsonProp,
|
|
13
|
-
|
|
12
|
+
S,
|
|
14
13
|
TypedObject,
|
|
15
14
|
TypeEnum,
|
|
16
15
|
} from '@dxos/echo-schema';
|
|
17
16
|
import { type Client, PublicKey } from '@dxos/react-client';
|
|
18
|
-
import {
|
|
17
|
+
import { create, makeRef, type Space } from '@dxos/react-client/echo';
|
|
19
18
|
import { createFieldId, createView, getSchemaProperties, ViewProjection, type ViewType } from '@dxos/schema';
|
|
20
19
|
|
|
21
20
|
import { type TableType } from '../types';
|
|
@@ -35,16 +34,20 @@ export const initializeTable = async ({
|
|
|
35
34
|
table,
|
|
36
35
|
typename,
|
|
37
36
|
initialRow = true,
|
|
38
|
-
}: InitialiseTableProps): Promise<
|
|
37
|
+
}: InitialiseTableProps): Promise<S.Schema.AnyNoContext> => {
|
|
39
38
|
if (typename) {
|
|
40
39
|
const schema = await space.db.graph.getSchemaByTypename(typename, space.db);
|
|
41
40
|
if (!schema) {
|
|
42
41
|
throw new Error(`Schema not found: ${typename}`);
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
// We need to get the schema properties here.
|
|
45
|
+
// For now, only simple types and refs, not compound types are going to be supported.
|
|
46
|
+
const fields = getSchemaProperties(schema.ast)
|
|
47
|
+
.filter((prop) => prop.format !== FormatEnum.Ref)
|
|
48
|
+
.map((prop) => prop.name);
|
|
46
49
|
|
|
47
|
-
table.view =
|
|
50
|
+
table.view = makeRef(
|
|
48
51
|
createView({
|
|
49
52
|
// TODO(ZaymonFC): Don't hardcode name?
|
|
50
53
|
name: 'View',
|
|
@@ -59,7 +62,7 @@ export const initializeTable = async ({
|
|
|
59
62
|
const [schema] = await space.db.schemaRegistry.register([ContactSchema]);
|
|
60
63
|
const fields = ContactFields;
|
|
61
64
|
|
|
62
|
-
table.view =
|
|
65
|
+
table.view = makeRef(
|
|
63
66
|
createView({
|
|
64
67
|
name: 'View',
|
|
65
68
|
typename: schema.typename,
|
|
@@ -72,7 +75,7 @@ export const initializeTable = async ({
|
|
|
72
75
|
|
|
73
76
|
if (initialRow) {
|
|
74
77
|
// TODO(burdon): Last (first) row should not be in db and should be managed by the model.
|
|
75
|
-
space.db.add(
|
|
78
|
+
space.db.add(create(schema, {}));
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
return schema;
|
|
@@ -83,10 +86,10 @@ const ContactSchema = TypedObject({
|
|
|
83
86
|
typename: `example.com/type/${PublicKey.random().truncate()}`,
|
|
84
87
|
version: '0.1.0',
|
|
85
88
|
})({
|
|
86
|
-
name:
|
|
87
|
-
active:
|
|
88
|
-
email:
|
|
89
|
-
salary:
|
|
89
|
+
name: S.optional(S.String).annotations({ [AST.TitleAnnotationId]: 'Name' }),
|
|
90
|
+
active: S.optional(S.Boolean),
|
|
91
|
+
email: S.optional(Format.Email),
|
|
92
|
+
salary: S.optional(Format.Currency()).annotations({ [AST.TitleAnnotationId]: 'Salary' }),
|
|
90
93
|
});
|
|
91
94
|
|
|
92
95
|
const ContactFields = ['name', 'email', 'salary', 'active'];
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/types/table.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema } from 'effect';\n\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { LabelAnnotationId, ObjectId, Ref, Expando, EchoObject } from '@dxos/echo-schema';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = Schema.Struct({\n id: ObjectId,\n name: Schema.optional(Schema.String),\n view: Schema.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\n// TODO(burdon): Move out of react-ui-xxx.\nexport const TableType = TableSchema.pipe(\n EchoObject({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n);\nexport interface TableType extends Schema.Schema.Type<typeof TableType> {}\n"],
|
|
5
|
-
"mappings": ";AAIA,SAASA,cAAc;AAGvB,SAASC,mBAAmBC,UAAUC,KAAKC,SAASC,kBAAkB;AACtE,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,OAAOC,OAAO;EACvCC,IAAIC;EACJC,MAAMJ,OAAOK,SAASL,OAAOM,MAAM;EACnCC,MAAMP,OAAOK,SAASG,IAAIC,QAAAA,CAAAA;;EAE1BC,SAASV,OAAOK,SAASL,OAAOW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AAClE,CAAA,EAAGC,YAAY;;EAEb,CAACC,iBAAAA,GAAoB;AACvB,CAAA;AAGO,IAAMC,YAAYhB,YAAYiB,KACnCC,WAAW;EACTC,UAAU;EACVC,SAAS;AACX,CAAA,CAAA;",
|
|
6
|
-
"names": ["Schema", "LabelAnnotationId", "ObjectId", "Ref", "Expando", "EchoObject", "ViewType", "TableSchema", "Schema", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "annotations", "LabelAnnotationId", "TableType", "pipe", "EchoObject", "typename", "version"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/types/table.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema } from 'effect';\n\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { LabelAnnotationId, ObjectId, Ref, Expando, EchoObject } from '@dxos/echo-schema';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = Schema.Struct({\n id: ObjectId,\n name: Schema.optional(Schema.String),\n view: Schema.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\n// TODO(burdon): Move out of react-ui-xxx.\nexport const TableType = TableSchema.pipe(\n EchoObject({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n);\nexport interface TableType extends Schema.Schema.Type<typeof TableType> {}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAIA,oBAAuB;AAGvB,yBAAsE;AACtE,oBAAyB;AAElB,IAAMA,cAAcC,qBAAOC,OAAO;EACvCC,IAAIC;EACJC,MAAMJ,qBAAOK,SAASL,qBAAOM,MAAM;EACnCC,MAAMP,qBAAOK,aAASG,wBAAIC,sBAAAA,CAAAA;;EAE1BC,SAASV,qBAAOK,SAASL,qBAAOW,UAAMH;IAAII;;EAAsB,CAAA,CAAA;AAClE,CAAA,EAAGC,YAAY;;EAEb,CAACC,oCAAAA,GAAoB;AACvB,CAAA;AAGO,IAAMC,YAAYhB,YAAYiB,SACnCC,+BAAW;EACTC,UAAU;EACVC,SAAS;AACX,CAAA,CAAA;",
|
|
6
|
-
"names": ["TableSchema", "Schema", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "annotations", "LabelAnnotationId", "TableType", "pipe", "EchoObject", "typename", "version"]
|
|
7
|
-
}
|