@dxos/react-ui-table 0.8.2-staging.7ac8446 → 0.8.2
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-U6LL2AVU.mjs +26 -0
- package/dist/lib/browser/chunk-U6LL2AVU.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1115 -905
- 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-TGG6OZ54.cjs → chunk-CXDGXPM6.cjs} +12 -12
- package/dist/lib/node/chunk-CXDGXPM6.cjs.map +7 -0
- package/dist/lib/node/index.cjs +1113 -906
- 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-KKLP54L3.mjs → chunk-EFSM52KQ.mjs} +10 -10
- package/dist/lib/node-esm/chunk-EFSM52KQ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1115 -905
- 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 +3 -4
- package/dist/types/src/components/Table/DynamicTable.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 +2 -0
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +1 -0
- 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/FormCellEditor.d.ts +13 -0
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -0
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -0
- 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 +6 -3
- 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 +46 -45
- package/dist/types/src/types/table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +4 -3
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
- 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/schema.d.ts +12 -0
- package/dist/types/src/util/schema.d.ts.map +1 -0
- package/dist/types/src/util/signals.d.ts.map +1 -1
- package/dist/types/src/util/table-buttons.d.ts +0 -14
- 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/src/util/tag.d.ts +11 -0
- package/dist/types/src/util/tag.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +41 -34
- package/src/components/Table/CreateRefPanel.tsx +5 -5
- package/src/components/Table/DynamicTable.stories.tsx +4 -4
- package/src/components/Table/DynamicTable.tsx +4 -5
- package/src/components/Table/Table.stories.tsx +84 -50
- package/src/components/Table/Table.tsx +25 -28
- package/src/components/Table/relations.stories.tsx +38 -32
- package/src/components/TableCellEditor/FormCellEditor.tsx +94 -0
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +13 -11
- package/src/components/TableCellEditor/TableCellEditor.tsx +45 -4
- package/src/components/TableToolbar/TableToolbar.tsx +65 -35
- package/src/components/testing.ts +10 -9
- package/src/hooks/useTableModel.ts +6 -4
- package/src/model/modal-controller.ts +3 -3
- package/src/model/selection-model.ts +1 -1
- package/src/model/table-model.test.ts +7 -6
- package/src/model/table-model.ts +20 -3
- package/src/model/table-presentation.test.ts +7 -6
- package/src/model/table-presentation.ts +54 -10
- package/src/types/table.ts +16 -11
- package/src/util/dynamic-table.ts +9 -6
- package/src/util/index.ts +1 -0
- package/src/util/schema.ts +36 -0
- package/src/util/table-buttons.ts +1 -24
- package/src/util/table.ts +13 -16
- package/src/util/tag.ts +33 -0
- package/dist/lib/browser/chunk-YWNRUF4J.mjs +0 -26
- package/dist/lib/browser/chunk-YWNRUF4J.mjs.map +0 -7
- package/dist/lib/node/chunk-TGG6OZ54.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-KKLP54L3.mjs.map +0 -7
- package/dist/types/src/components/Table/RefPanel.d.ts +0 -9
- package/dist/types/src/components/Table/RefPanel.d.ts.map +0 -1
- package/src/components/Table/RefPanel.tsx +0 -52
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { signal } from '@preact/signals-core';
|
|
6
|
+
import { isNotNullable } from 'effect/Predicate';
|
|
6
7
|
|
|
7
|
-
import { FormatEnum, getValue } from '@dxos/echo-schema';
|
|
8
|
+
import { FormatEnum, getDXN, getValue, TypeEnum } from '@dxos/echo-schema';
|
|
8
9
|
import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
|
|
9
10
|
import {
|
|
10
11
|
type DxGridPlane,
|
|
@@ -84,6 +85,10 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
84
85
|
return '';
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
if (props.type === 'array') {
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
|
|
87
92
|
switch (props.format) {
|
|
88
93
|
case FormatEnum.Boolean:
|
|
89
94
|
case FormatEnum.SingleSelect:
|
|
@@ -121,13 +126,52 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
121
126
|
cell.className = mx(classes.flat());
|
|
122
127
|
}
|
|
123
128
|
|
|
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
|
+
|
|
124
170
|
if (props.format === FormatEnum.Ref && props.referenceSchema) {
|
|
125
171
|
const targetObj = getValue(obj, field.path)?.target;
|
|
126
172
|
if (targetObj) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
schemaId: props.referenceSchema,
|
|
130
|
-
});
|
|
173
|
+
const dxn = getDXN(targetObj)?.toString();
|
|
174
|
+
cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button block is-6 pli-[3px] plb-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
|
|
131
175
|
}
|
|
132
176
|
}
|
|
133
177
|
|
|
@@ -168,7 +212,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
168
212
|
.join(' ');
|
|
169
213
|
|
|
170
214
|
if (tags) {
|
|
171
|
-
cell.accessoryHtml = tags
|
|
215
|
+
cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1">${tags}</div>`;
|
|
172
216
|
}
|
|
173
217
|
}
|
|
174
218
|
}
|
|
@@ -208,7 +252,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
208
252
|
${direction !== undefined ? tableButtons.sort.render({ fieldId: field.id, direction }) : ''}
|
|
209
253
|
${tableButtons.columnSettings.render({ fieldId: field.id })}
|
|
210
254
|
`,
|
|
211
|
-
className: '!bg-
|
|
255
|
+
className: '!bg-toolbarSurface',
|
|
212
256
|
};
|
|
213
257
|
}
|
|
214
258
|
|
|
@@ -251,7 +295,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
251
295
|
if (!this.model.features.selection.enabled || this.model.selection.selectionMode === 'single') {
|
|
252
296
|
return {
|
|
253
297
|
[toPlaneCellIndex({ col: 0, row: 0 })]: {
|
|
254
|
-
className: '!bg-
|
|
298
|
+
className: '!bg-toolbarSurface',
|
|
255
299
|
readonly: true,
|
|
256
300
|
value: '',
|
|
257
301
|
},
|
|
@@ -265,7 +309,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
265
309
|
header: true,
|
|
266
310
|
checked: this.model.selection.allRowsSeleted.value,
|
|
267
311
|
}),
|
|
268
|
-
className: '!bg-
|
|
312
|
+
className: '!bg-toolbarSurface',
|
|
269
313
|
readonly: true,
|
|
270
314
|
value: '',
|
|
271
315
|
},
|
|
@@ -280,7 +324,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
|
|
|
280
324
|
disabled: (this.model.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT,
|
|
281
325
|
})
|
|
282
326
|
: undefined,
|
|
283
|
-
className: '!bg-
|
|
327
|
+
className: '!bg-toolbarSurface',
|
|
284
328
|
readonly: true,
|
|
285
329
|
value: '',
|
|
286
330
|
},
|
package/src/types/table.ts
CHANGED
|
@@ -2,20 +2,25 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
|
+
|
|
6
7
|
// import { ThreadType } from '@dxos/plugin-space/types';
|
|
8
|
+
import { ObjectId, Ref, Expando, EchoObject, LabelAnnotation } from '@dxos/echo-schema';
|
|
7
9
|
import { ViewType } from '@dxos/schema';
|
|
8
10
|
|
|
9
|
-
export const TableSchema =
|
|
11
|
+
export const TableSchema = Schema.Struct({
|
|
10
12
|
id: ObjectId,
|
|
11
|
-
name:
|
|
12
|
-
view:
|
|
13
|
+
name: Schema.optional(Schema.String),
|
|
14
|
+
view: Schema.optional(Ref(ViewType)),
|
|
13
15
|
// TODO(burdon): Document why threads is included here?
|
|
14
|
-
threads:
|
|
15
|
-
}).
|
|
16
|
-
// TODO(burdon): Move annotation to property.
|
|
17
|
-
[LabelAnnotationId]: 'name',
|
|
18
|
-
});
|
|
16
|
+
threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),
|
|
17
|
+
}).pipe(LabelAnnotation.set(['name']));
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
export
|
|
19
|
+
// TODO(burdon): Move out of react-ui-xxx.
|
|
20
|
+
export const TableType = TableSchema.pipe(
|
|
21
|
+
EchoObject({
|
|
22
|
+
typename: 'dxos.org/type/Table',
|
|
23
|
+
version: '0.1.0',
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
export interface TableType extends Schema.Schema.Type<typeof TableType> {}
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
import { type Schema } from 'effect';
|
|
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';
|
|
7
10
|
import {
|
|
8
11
|
createView,
|
|
9
12
|
getSchemaFromPropertyDefinitions,
|
|
@@ -27,7 +30,7 @@ export type TablePropertyDefinition = SchemaPropertyDefinition & Partial<Propert
|
|
|
27
30
|
* @deprecated
|
|
28
31
|
*/
|
|
29
32
|
// TODO(burdon): Remove variance.
|
|
30
|
-
export const
|
|
33
|
+
export const getBaseSchema = ({
|
|
31
34
|
typename,
|
|
32
35
|
properties,
|
|
33
36
|
jsonSchema,
|
|
@@ -36,13 +39,13 @@ export const getBaseSchems = ({
|
|
|
36
39
|
typename?: string;
|
|
37
40
|
properties?: TablePropertyDefinition[];
|
|
38
41
|
jsonSchema?: JsonSchemaType;
|
|
39
|
-
schema?:
|
|
42
|
+
schema?: Schema.Schema.AnyNoContext;
|
|
40
43
|
}): { typename: string; jsonSchema: JsonSchemaType } => {
|
|
41
44
|
if (typename && properties) {
|
|
42
45
|
const schema = getSchemaFromPropertyDefinitions(typename, properties);
|
|
43
46
|
return { typename: schema.typename, jsonSchema: schema.jsonSchema };
|
|
44
47
|
} else if (schema) {
|
|
45
|
-
return { typename: schema
|
|
48
|
+
return { typename: getTypename(schema)!, jsonSchema: toJsonSchema(schema) };
|
|
46
49
|
} else if (typename && jsonSchema) {
|
|
47
50
|
return { typename, jsonSchema };
|
|
48
51
|
} else {
|
|
@@ -66,7 +69,7 @@ export const makeDynamicTable = ({
|
|
|
66
69
|
...(properties && { fields: properties.map((property) => property.name) }),
|
|
67
70
|
});
|
|
68
71
|
|
|
69
|
-
const table =
|
|
72
|
+
const table = live(TableType, { name: 'dynamic-table', view: makeRef(view) });
|
|
70
73
|
const projection = new ViewProjection(jsonSchema, view);
|
|
71
74
|
if (properties && view.fields) {
|
|
72
75
|
setProperties(view, projection, properties);
|
package/src/util/index.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
|
+
import { isTypeLiteral, TypeLiteral } from 'effect/SchemaAST';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a narrowed schema from an original schema that only includes
|
|
10
|
+
* the specified paths. This allows form components to only display
|
|
11
|
+
* and edit/validate specific fields rather than the entire object.
|
|
12
|
+
*
|
|
13
|
+
* @param schema The original schema to narrow
|
|
14
|
+
* @param paths Array of field paths to extract
|
|
15
|
+
* @returns A narrowed Schema instance containing only the properties at the specified paths
|
|
16
|
+
*/
|
|
17
|
+
export const narrowSchema = <S extends Schema.Schema.AnyNoContext>(
|
|
18
|
+
schema: S,
|
|
19
|
+
paths: string[],
|
|
20
|
+
): Schema.Schema<unknown, unknown> | undefined => {
|
|
21
|
+
const ast = (schema as any)?.ast;
|
|
22
|
+
|
|
23
|
+
if (isTypeLiteral(ast)) {
|
|
24
|
+
// Filter property signatures that match any of the provided paths
|
|
25
|
+
const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
|
|
26
|
+
|
|
27
|
+
// If we found at least one matching property
|
|
28
|
+
if (propertySignatures.length > 0) {
|
|
29
|
+
// Create a new TypeLiteral with only the matching properties
|
|
30
|
+
const narrowType = new TypeLiteral(propertySignatures, []);
|
|
31
|
+
return Schema.make(narrowType);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return undefined;
|
|
36
|
+
};
|
|
@@ -15,7 +15,6 @@ 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 }
|
|
19
18
|
| { type: 'rowMenu'; rowIndex: number }
|
|
20
19
|
| { type: 'sort'; fieldId: string; direction?: 'asc' | 'desc' };
|
|
21
20
|
|
|
@@ -39,7 +38,7 @@ const createButton = ({
|
|
|
39
38
|
.join(' ');
|
|
40
39
|
|
|
41
40
|
const positionClass = type === 'primary' ? 'inline-end-2' : 'inline-end-9';
|
|
42
|
-
return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? 'disabled' : ''}><svg><use href="/icons.svg#${icon}"/></svg></button>`;
|
|
41
|
+
return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? 'disabled' : ''}><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
|
|
43
42
|
};
|
|
44
43
|
|
|
45
44
|
const addColumnButton = {
|
|
@@ -76,27 +75,6 @@ const columnSettingsButton = {
|
|
|
76
75
|
}),
|
|
77
76
|
} as const;
|
|
78
77
|
|
|
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
|
-
|
|
100
78
|
const rowMenuButton = {
|
|
101
79
|
attr: BUTTON_IDENTIFIERS.rowMenu,
|
|
102
80
|
icon: 'ph--dots-three--regular',
|
|
@@ -143,7 +121,6 @@ const sortButton = {
|
|
|
143
121
|
export const tableButtons = {
|
|
144
122
|
addColumn: addColumnButton,
|
|
145
123
|
columnSettings: columnSettingsButton,
|
|
146
|
-
referencedCell: referencedCellButton,
|
|
147
124
|
rowMenu: rowMenuButton,
|
|
148
125
|
sort: sortButton,
|
|
149
126
|
} as const;
|
package/src/util/table.ts
CHANGED
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Schema } from 'effect';
|
|
6
|
+
|
|
5
7
|
import {
|
|
6
|
-
AST,
|
|
7
8
|
type EchoSchema,
|
|
8
9
|
Format,
|
|
9
10
|
FormatEnum,
|
|
10
11
|
type JsonPath,
|
|
11
12
|
type JsonProp,
|
|
12
|
-
|
|
13
|
+
Ref,
|
|
13
14
|
TypedObject,
|
|
14
15
|
TypeEnum,
|
|
15
16
|
} from '@dxos/echo-schema';
|
|
16
17
|
import { type Client, PublicKey } from '@dxos/react-client';
|
|
17
|
-
import {
|
|
18
|
+
import { live, type Space } from '@dxos/react-client/echo';
|
|
18
19
|
import { createFieldId, createView, getSchemaProperties, ViewProjection, type ViewType } from '@dxos/schema';
|
|
19
20
|
|
|
20
21
|
import { type TableType } from '../types';
|
|
@@ -34,20 +35,16 @@ export const initializeTable = async ({
|
|
|
34
35
|
table,
|
|
35
36
|
typename,
|
|
36
37
|
initialRow = true,
|
|
37
|
-
}: InitialiseTableProps): Promise<
|
|
38
|
+
}: InitialiseTableProps): Promise<Schema.Schema.AnyNoContext> => {
|
|
38
39
|
if (typename) {
|
|
39
40
|
const schema = await space.db.graph.getSchemaByTypename(typename, space.db);
|
|
40
41
|
if (!schema) {
|
|
41
42
|
throw new Error(`Schema not found: ${typename}`);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
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);
|
|
45
|
+
const fields = getSchemaProperties(schema.ast).map((prop) => prop.name);
|
|
49
46
|
|
|
50
|
-
table.view =
|
|
47
|
+
table.view = Ref.make(
|
|
51
48
|
createView({
|
|
52
49
|
// TODO(ZaymonFC): Don't hardcode name?
|
|
53
50
|
name: 'View',
|
|
@@ -62,7 +59,7 @@ export const initializeTable = async ({
|
|
|
62
59
|
const [schema] = await space.db.schemaRegistry.register([ContactSchema]);
|
|
63
60
|
const fields = ContactFields;
|
|
64
61
|
|
|
65
|
-
table.view =
|
|
62
|
+
table.view = Ref.make(
|
|
66
63
|
createView({
|
|
67
64
|
name: 'View',
|
|
68
65
|
typename: schema.typename,
|
|
@@ -75,7 +72,7 @@ export const initializeTable = async ({
|
|
|
75
72
|
|
|
76
73
|
if (initialRow) {
|
|
77
74
|
// TODO(burdon): Last (first) row should not be in db and should be managed by the model.
|
|
78
|
-
space.db.add(
|
|
75
|
+
space.db.add(live(schema, {}));
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
return schema;
|
|
@@ -86,10 +83,10 @@ const ContactSchema = TypedObject({
|
|
|
86
83
|
typename: `example.com/type/${PublicKey.random().truncate()}`,
|
|
87
84
|
version: '0.1.0',
|
|
88
85
|
})({
|
|
89
|
-
name:
|
|
90
|
-
active:
|
|
91
|
-
email:
|
|
92
|
-
salary:
|
|
86
|
+
name: Schema.optional(Schema.String).annotations({ title: 'Name' }),
|
|
87
|
+
active: Schema.optional(Schema.Boolean),
|
|
88
|
+
email: Schema.optional(Format.Email),
|
|
89
|
+
salary: Schema.optional(Format.Currency()).annotations({ title: 'Salary' }),
|
|
93
90
|
});
|
|
94
91
|
|
|
95
92
|
const ContactFields = ['name', 'email', 'salary', 'active'];
|
package/src/util/tag.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// TODO(ZaymonFC): Push this into the tag picker module.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Regex pattern for matching tags in the format [Label](id)
|
|
9
|
+
*/
|
|
10
|
+
export const TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Extracts tag IDs from a string in the format [Label](id)
|
|
14
|
+
* @param value The string to extract IDs from
|
|
15
|
+
* @returns Array of extracted IDs or undefined if no matches or value is not a string
|
|
16
|
+
*/
|
|
17
|
+
export const extractTagIds = (value: unknown): string[] | undefined => {
|
|
18
|
+
if (typeof value !== 'string') {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const ids: string[] = [];
|
|
23
|
+
let match;
|
|
24
|
+
|
|
25
|
+
// Use the global regex to find all matches
|
|
26
|
+
while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
|
|
27
|
+
if (match[2]) {
|
|
28
|
+
ids.push(match[2]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return ids.length > 0 ? ids : undefined;
|
|
33
|
+
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// packages/ui/react-ui-table/src/types/table.ts
|
|
2
|
-
import { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from "@dxos/echo-schema";
|
|
3
|
-
import { ViewType } from "@dxos/schema";
|
|
4
|
-
var TableSchema = S.Struct({
|
|
5
|
-
id: ObjectId,
|
|
6
|
-
name: S.optional(S.String),
|
|
7
|
-
view: S.optional(Ref(ViewType)),
|
|
8
|
-
// TODO(burdon): Document why threads is included here?
|
|
9
|
-
threads: S.optional(S.Array(Ref(
|
|
10
|
-
Expando
|
|
11
|
-
/* ThreadType */
|
|
12
|
-
)))
|
|
13
|
-
}).annotations({
|
|
14
|
-
// TODO(burdon): Move annotation to property.
|
|
15
|
-
[LabelAnnotationId]: "name"
|
|
16
|
-
});
|
|
17
|
-
var TableType = TableSchema.pipe(EchoObject({
|
|
18
|
-
typename: "dxos.org/type/Table",
|
|
19
|
-
version: "0.1.0"
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
export {
|
|
23
|
-
TableSchema,
|
|
24
|
-
TableType
|
|
25
|
-
};
|
|
26
|
-
//# sourceMappingURL=chunk-YWNRUF4J.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/types/table.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = S.Struct({\n id: ObjectId,\n name: S.optional(S.String),\n view: S.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\nexport const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));\nexport interface TableType extends S.Schema.Type<typeof TableType> {}\n"],
|
|
5
|
-
"mappings": ";AAIA,SAASA,YAAYC,SAASC,mBAAmBC,UAAUC,KAAKC,SAAS;AAEzE,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,EAAEC,OAAO;EAClCC,IAAIC;EACJC,MAAMJ,EAAEK,SAASL,EAAEM,MAAM;EACzBC,MAAMP,EAAEK,SAASG,IAAIC,QAAAA,CAAAA;;EAErBC,SAASV,EAAEK,SAASL,EAAEW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AACxD,CAAA,EAAGC,YAAY;;EAEb,CAACC,iBAAAA,GAAoB;AACvB,CAAA;AAEO,IAAMC,YAAYhB,YAAYiB,KAAKC,WAAW;EAAEC,UAAU;EAAuBC,SAAS;AAAQ,CAAA,CAAA;",
|
|
6
|
-
"names": ["EchoObject", "Expando", "LabelAnnotationId", "ObjectId", "Ref", "S", "ViewType", "TableSchema", "S", "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 { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = S.Struct({\n id: ObjectId,\n name: S.optional(S.String),\n view: S.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\nexport const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));\nexport interface TableType extends S.Schema.Type<typeof TableType> {}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAIA,yBAAyE;AAEzE,oBAAyB;AAElB,IAAMA,cAAcC,qBAAEC,OAAO;EAClCC,IAAIC;EACJC,MAAMJ,qBAAEK,SAASL,qBAAEM,MAAM;EACzBC,MAAMP,qBAAEK,aAASG,wBAAIC,sBAAAA,CAAAA;;EAErBC,SAASV,qBAAEK,SAASL,qBAAEW,UAAMH;IAAII;;EAAsB,CAAA,CAAA;AACxD,CAAA,EAAGC,YAAY;;EAEb,CAACC,oCAAAA,GAAoB;AACvB,CAAA;AAEO,IAAMC,YAAYhB,YAAYiB,SAAKC,+BAAW;EAAEC,UAAU;EAAuBC,SAAS;AAAQ,CAAA,CAAA;",
|
|
6
|
-
"names": ["TableSchema", "S", "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 { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = S.Struct({\n id: ObjectId,\n name: S.optional(S.String),\n view: S.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\nexport const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));\nexport interface TableType extends S.Schema.Type<typeof TableType> {}\n"],
|
|
5
|
-
"mappings": ";;;AAIA,SAASA,YAAYC,SAASC,mBAAmBC,UAAUC,KAAKC,SAAS;AAEzE,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,EAAEC,OAAO;EAClCC,IAAIC;EACJC,MAAMJ,EAAEK,SAASL,EAAEM,MAAM;EACzBC,MAAMP,EAAEK,SAASG,IAAIC,QAAAA,CAAAA;;EAErBC,SAASV,EAAEK,SAASL,EAAEW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AACxD,CAAA,EAAGC,YAAY;;EAEb,CAACC,iBAAAA,GAAoB;AACvB,CAAA;AAEO,IAAMC,YAAYhB,YAAYiB,KAAKC,WAAW;EAAEC,UAAU;EAAuBC,SAAS;AAAQ,CAAA,CAAA;",
|
|
6
|
-
"names": ["EchoObject", "Expando", "LabelAnnotationId", "ObjectId", "Ref", "S", "ViewType", "TableSchema", "S", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "annotations", "LabelAnnotationId", "TableType", "pipe", "EchoObject", "typename", "version"]
|
|
7
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { type TableModel, type ModalController } from '../../model';
|
|
3
|
-
type RefPanelProps = {
|
|
4
|
-
model: TableModel;
|
|
5
|
-
modals: ModalController;
|
|
6
|
-
};
|
|
7
|
-
export declare const RefPanel: ({ model, modals }: RefPanelProps) => React.JSX.Element | null;
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=RefPanel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RefPanel.d.ts","sourceRoot":"","sources":["../../../../../src/components/Table/RefPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpE,KAAK,aAAa,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC;AAUpE,eAAO,MAAM,QAAQ,sBAAuB,aAAa,6BA6BxD,CAAC"}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
|
|
7
|
-
import { type Space } from '@dxos/react-client/echo';
|
|
8
|
-
import { Popover } from '@dxos/react-ui';
|
|
9
|
-
import { Form } from '@dxos/react-ui-form';
|
|
10
|
-
|
|
11
|
-
import { type TableModel, type ModalController } from '../../model';
|
|
12
|
-
|
|
13
|
-
type RefPanelProps = { model: TableModel; modals: ModalController };
|
|
14
|
-
|
|
15
|
-
const getRefTargetObj = (space?: Space, id?: string) => {
|
|
16
|
-
if (space && id) {
|
|
17
|
-
return space?.db.getObjectById(id);
|
|
18
|
-
} else {
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const RefPanel = ({ model, modals }: RefPanelProps) => {
|
|
24
|
-
const state = modals.state.value;
|
|
25
|
-
const space = model?.space;
|
|
26
|
-
const targetObj = getRefTargetObj(space, state?.type === 'refPanel' ? state.targetId : undefined);
|
|
27
|
-
const schema = space && state?.type === 'refPanel' ? space.db.schemaRegistry.getSchema(state.typename) : undefined;
|
|
28
|
-
|
|
29
|
-
if (!model.view || !model.projection) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<Popover.Root
|
|
35
|
-
modal={false}
|
|
36
|
-
open={state?.type === 'refPanel' && !!targetObj && !!schema}
|
|
37
|
-
onOpenChange={(nextOpen) => {
|
|
38
|
-
if (!nextOpen) {
|
|
39
|
-
return modals.close();
|
|
40
|
-
}
|
|
41
|
-
}}
|
|
42
|
-
>
|
|
43
|
-
<Popover.VirtualTrigger virtualRef={modals.trigger} />
|
|
44
|
-
<Popover.Portal>
|
|
45
|
-
<Popover.Content classNames='md:is-64'>
|
|
46
|
-
{targetObj && schema && <Form readonly values={targetObj} schema={schema} />}
|
|
47
|
-
<Popover.Arrow />
|
|
48
|
-
</Popover.Content>
|
|
49
|
-
</Popover.Portal>
|
|
50
|
-
</Popover.Root>
|
|
51
|
-
);
|
|
52
|
-
};
|