@dxos/react-ui-form 0.8.4-main.e098934 → 0.8.4-main.ead640a
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/index.mjs +422 -284
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +422 -284
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +3 -2
- package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +3 -2
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +2 -2
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +12 -11
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContent.d.ts +5 -5
- package/dist/types/src/components/Form/FormContent.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormContext.d.ts +2 -2
- package/dist/types/src/components/Form/FormContext.d.ts.map +1 -1
- package/dist/types/src/components/Form/Input.d.ts +1 -1
- package/dist/types/src/components/Form/Input.d.ts.map +1 -1
- package/dist/types/src/components/Form/RefField.d.ts +10 -6
- package/dist/types/src/components/Form/RefField.d.ts.map +1 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +3 -2
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/factory.d.ts +1 -1
- package/dist/types/src/components/Form/factory.d.ts.map +1 -1
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +41 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +82 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
- package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
- package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +19 -6
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +7 -6
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useForm.d.ts +2 -2
- package/dist/types/src/hooks/useForm.d.ts.map +1 -1
- package/dist/types/src/hooks/useQueryRefOptions.d.ts +9 -3
- package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +1 -1
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/field.d.ts +1 -1
- package/dist/types/src/util/field.d.ts.map +1 -1
- package/dist/types/src/util/formatting.d.ts +1 -1
- package/dist/types/src/util/formatting.d.ts.map +1 -1
- package/dist/types/src/util/refs.d.ts +1 -1
- package/dist/types/src/util/refs.d.ts.map +1 -1
- package/dist/types/src/util/schema.d.ts +1 -1
- package/dist/types/src/util/schema.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +39 -39
- package/src/components/ControlSection/ControlSection.stories.tsx +3 -4
- package/src/components/ControlSection/ControlSection.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.stories.tsx +6 -5
- package/src/components/FieldEditor/FieldEditor.tsx +5 -2
- package/src/components/Form/ArrayField.tsx +4 -3
- package/src/components/Form/Form.stories.tsx +32 -32
- package/src/components/Form/Form.tsx +13 -5
- package/src/components/Form/FormContent.tsx +30 -10
- package/src/components/Form/FormContext.tsx +3 -3
- package/src/components/Form/Input.tsx +1 -1
- package/src/components/Form/RefField.tsx +48 -64
- package/src/components/Form/custom/GeoPointInput.tsx +1 -1
- package/src/components/Form/custom/SelectOptionsInput.stories.tsx +5 -6
- package/src/components/Form/custom/SelectOptionsInput.tsx +1 -1
- package/src/components/Form/factory.tsx +1 -1
- package/src/components/ObjectPicker/ObjectPicker.stories.tsx +207 -0
- package/src/components/ObjectPicker/ObjectPicker.tsx +161 -0
- package/src/components/ObjectPicker/index.ts +5 -0
- package/src/components/ViewEditor/ViewEditor.stories.tsx +95 -53
- package/src/components/ViewEditor/ViewEditor.test.tsx +4 -3
- package/src/components/ViewEditor/ViewEditor.tsx +270 -229
- package/src/components/index.ts +1 -0
- package/src/components/testing.tsx +2 -2
- package/src/hooks/useForm.ts +7 -4
- package/src/hooks/useQueryRefOptions.ts +15 -6
- package/src/hooks/useRefQueryLookupHandler.ts +3 -3
- package/src/translations.ts +2 -1
- package/src/util/field.ts +1 -1
- package/src/util/formatting.ts +1 -1
- package/src/util/refs.ts +2 -2
- package/src/util/schema.ts +2 -4
|
@@ -2,26 +2,31 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import
|
|
9
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
10
8
|
|
|
11
|
-
import { Filter, Obj, Query, Type } from '@dxos/echo';
|
|
12
|
-
import { type EchoSchema, Format
|
|
13
|
-
import {
|
|
14
|
-
import { withClientProvider } from '@dxos/react-client/testing';
|
|
9
|
+
import { DXN, Filter, Obj, Query, type QueryAST, Tag, Type } from '@dxos/echo';
|
|
10
|
+
import { type EchoSchema, Format } from '@dxos/echo/internal';
|
|
11
|
+
import { useQuery } from '@dxos/react-client/echo';
|
|
12
|
+
import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
|
|
15
13
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
14
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
15
|
+
import { DataType, type ProjectionModel, createView, getTypenameFromQuery } from '@dxos/schema';
|
|
19
16
|
|
|
20
17
|
import { translations } from '../../translations';
|
|
21
18
|
import { TestLayout, TestPanel, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
22
19
|
|
|
23
20
|
import { ViewEditor, type ViewEditorProps } from './ViewEditor';
|
|
24
21
|
|
|
22
|
+
const types = [
|
|
23
|
+
// TODO(burdon): Get label from annotation.
|
|
24
|
+
{ value: Type.getTypename(DataType.Organization), label: 'Organization' },
|
|
25
|
+
{ value: Type.getTypename(DataType.Person), label: 'Person' },
|
|
26
|
+
{ value: Type.getTypename(DataType.Project), label: 'Project' },
|
|
27
|
+
{ value: Type.getTypename(DataType.Employer), label: 'Employer' },
|
|
28
|
+
];
|
|
29
|
+
|
|
25
30
|
// Type definition for debug objects exposed to tests.
|
|
26
31
|
export type ViewEditorDebugObjects = {
|
|
27
32
|
schema: EchoSchema;
|
|
@@ -29,13 +34,16 @@ export type ViewEditorDebugObjects = {
|
|
|
29
34
|
projection: ProjectionModel;
|
|
30
35
|
};
|
|
31
36
|
|
|
32
|
-
type StoryProps = Pick<ViewEditorProps, 'readonly' | '
|
|
37
|
+
type StoryProps = Pick<ViewEditorProps, 'readonly' | 'mode'>;
|
|
33
38
|
|
|
34
39
|
const DefaultStory = (props: StoryProps) => {
|
|
35
|
-
const space =
|
|
40
|
+
const { space } = useClientProvider();
|
|
36
41
|
const [schema, setSchema] = useState<EchoSchema>();
|
|
37
42
|
const [view, setView] = useState<DataType.View>();
|
|
38
|
-
const
|
|
43
|
+
const projectionRef = useRef<ProjectionModel>(null);
|
|
44
|
+
|
|
45
|
+
const tags = useQuery(space, Filter.type(Tag.Tag));
|
|
46
|
+
|
|
39
47
|
useAsyncEffect(async () => {
|
|
40
48
|
if (space) {
|
|
41
49
|
const TestSchema = Schema.Struct({
|
|
@@ -49,65 +57,86 @@ const DefaultStory = (props: StoryProps) => {
|
|
|
49
57
|
}),
|
|
50
58
|
);
|
|
51
59
|
|
|
52
|
-
const
|
|
60
|
+
const AlternateSchema = Schema.Struct({
|
|
61
|
+
title: Schema.String,
|
|
62
|
+
description: Schema.String,
|
|
63
|
+
completed: Schema.Boolean,
|
|
64
|
+
}).pipe(
|
|
65
|
+
Type.Obj({
|
|
66
|
+
typename: 'example.com/type/Alternate',
|
|
67
|
+
version: '0.1.0',
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const [testSchema] = await space.db.schemaRegistry.register([TestSchema, AlternateSchema]);
|
|
53
72
|
const view = createView({
|
|
54
73
|
name: 'Test',
|
|
55
|
-
query: Query.select(Filter.
|
|
56
|
-
jsonSchema: toJsonSchema(TestSchema),
|
|
74
|
+
query: Query.select(Filter.typename(TestSchema.typename)),
|
|
75
|
+
jsonSchema: Type.toJsonSchema(TestSchema),
|
|
57
76
|
presentation: Obj.make(Type.Expando, {}),
|
|
58
77
|
});
|
|
59
|
-
const projection = new ProjectionModel(schema.jsonSchema, view.projection);
|
|
60
78
|
|
|
61
|
-
setSchema(
|
|
79
|
+
setSchema(testSchema);
|
|
62
80
|
setView(view);
|
|
63
|
-
setProjection(projection);
|
|
64
81
|
}
|
|
65
82
|
}, [space]);
|
|
66
83
|
|
|
67
84
|
const updateViewQuery = useCallback(
|
|
68
|
-
(
|
|
69
|
-
if (!schema || !view) {
|
|
85
|
+
async (newQuery: QueryAST.Query, target?: string) => {
|
|
86
|
+
if (!schema || !view || !space) {
|
|
70
87
|
return;
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
if (props.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
if (props.mode === 'query') {
|
|
91
|
+
const queue = target && DXN.tryParse(target) ? target : undefined;
|
|
92
|
+
const query = queue ? Query.fromAst(newQuery).options({ queues: [queue] }) : Query.fromAst(newQuery);
|
|
93
|
+
view.query.ast = query.ast;
|
|
94
|
+
|
|
95
|
+
const typename = getTypenameFromQuery(query.ast);
|
|
96
|
+
const [newSchema] = await space.db.schemaRegistry.query({ typename }).run();
|
|
97
|
+
if (!newSchema) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const newView = createView({
|
|
102
|
+
query,
|
|
103
|
+
jsonSchema: newSchema.jsonSchema,
|
|
104
|
+
presentation: Obj.make(Type.Expando, {}),
|
|
105
|
+
});
|
|
106
|
+
view.projection = Obj.getSnapshot(newView).projection;
|
|
107
|
+
setSchema(() => newSchema);
|
|
85
108
|
} else {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
schema.updateTypename(typename);
|
|
109
|
+
console.log('updateViewQuery', { newQuery });
|
|
110
|
+
view.query.ast = newQuery;
|
|
111
|
+
schema.updateTypename(getTypenameFromQuery(newQuery));
|
|
90
112
|
}
|
|
91
113
|
},
|
|
92
114
|
[view, schema],
|
|
93
115
|
);
|
|
94
116
|
|
|
95
|
-
const handleDelete = useCallback(
|
|
117
|
+
const handleDelete = useCallback(
|
|
118
|
+
(property: string) => projectionRef.current?.deleteFieldProjection(property),
|
|
119
|
+
[projectionRef],
|
|
120
|
+
);
|
|
96
121
|
|
|
97
122
|
// Expose objects on window for test access.
|
|
98
123
|
useEffect(() => {
|
|
99
|
-
if (typeof window !== 'undefined' && schema && view &&
|
|
100
|
-
(window as any)[VIEW_EDITOR_DEBUG_SYMBOL] = {
|
|
124
|
+
if (typeof window !== 'undefined' && schema && view && projectionRef.current) {
|
|
125
|
+
(window as any)[VIEW_EDITOR_DEBUG_SYMBOL] = {
|
|
126
|
+
schema,
|
|
127
|
+
view,
|
|
128
|
+
projection: projectionRef.current,
|
|
129
|
+
} satisfies ViewEditorDebugObjects;
|
|
101
130
|
}
|
|
102
|
-
}, [schema, view
|
|
131
|
+
}, [schema, view]);
|
|
103
132
|
|
|
104
133
|
// NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
|
|
105
134
|
const json = useMemo(
|
|
106
|
-
() => JSON.parse(JSON.stringify({ schema, view, projection })),
|
|
107
|
-
[JSON.stringify(schema), JSON.stringify(view)
|
|
135
|
+
() => JSON.parse(JSON.stringify({ schema, view, projection: projectionRef.current })),
|
|
136
|
+
[JSON.stringify(schema), JSON.stringify(view)],
|
|
108
137
|
);
|
|
109
138
|
|
|
110
|
-
if (!schema || !view
|
|
139
|
+
if (!schema || !view) {
|
|
111
140
|
return <div />;
|
|
112
141
|
}
|
|
113
142
|
|
|
@@ -115,11 +144,14 @@ const DefaultStory = (props: StoryProps) => {
|
|
|
115
144
|
<TestLayout json={json}>
|
|
116
145
|
<TestPanel>
|
|
117
146
|
<ViewEditor
|
|
147
|
+
ref={projectionRef}
|
|
118
148
|
schema={schema}
|
|
119
149
|
view={view}
|
|
120
150
|
registry={space?.db.schemaRegistry}
|
|
121
|
-
|
|
151
|
+
mode={props.mode}
|
|
122
152
|
readonly={props.readonly}
|
|
153
|
+
types={types}
|
|
154
|
+
tags={tags}
|
|
123
155
|
onQueryChanged={updateViewQuery}
|
|
124
156
|
onDelete={handleDelete}
|
|
125
157
|
/>
|
|
@@ -134,13 +166,19 @@ const meta = {
|
|
|
134
166
|
decorators: [
|
|
135
167
|
withClientProvider({
|
|
136
168
|
createSpace: true,
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
169
|
+
types: [Tag.Tag],
|
|
170
|
+
onCreateSpace: ({ space }) => {
|
|
171
|
+
space.db.add(Tag.make({ label: 'Important' }));
|
|
172
|
+
space.db.add(Tag.make({ label: 'Investor' }));
|
|
173
|
+
space.db.add(Tag.make({ label: 'New' }));
|
|
174
|
+
},
|
|
140
175
|
}),
|
|
141
176
|
withTheme,
|
|
142
177
|
],
|
|
143
|
-
parameters: {
|
|
178
|
+
parameters: {
|
|
179
|
+
layout: 'fullscreen',
|
|
180
|
+
translations,
|
|
181
|
+
},
|
|
144
182
|
} satisfies Meta<typeof DefaultStory>;
|
|
145
183
|
|
|
146
184
|
export default meta;
|
|
@@ -150,9 +188,13 @@ type Story = StoryObj<typeof meta>;
|
|
|
150
188
|
export const Default: Story = {};
|
|
151
189
|
|
|
152
190
|
export const Readonly: Story = {
|
|
153
|
-
args: {
|
|
191
|
+
args: {
|
|
192
|
+
readonly: true,
|
|
193
|
+
},
|
|
154
194
|
};
|
|
155
195
|
|
|
156
|
-
export const
|
|
157
|
-
args: {
|
|
196
|
+
export const QueryMode: Story = {
|
|
197
|
+
args: {
|
|
198
|
+
mode: 'query',
|
|
199
|
+
},
|
|
158
200
|
};
|
|
@@ -6,7 +6,7 @@ import { composeStories } from '@storybook/react';
|
|
|
6
6
|
import { cleanup, fireEvent, screen, waitFor } from '@testing-library/react';
|
|
7
7
|
import { afterEach, describe, expect, test } from 'vitest';
|
|
8
8
|
|
|
9
|
-
import { EchoSchema, isInstanceOf } from '@dxos/echo
|
|
9
|
+
import { EchoSchema, isInstanceOf } from '@dxos/echo/internal';
|
|
10
10
|
import { DataType, ProjectionModel } from '@dxos/schema';
|
|
11
11
|
|
|
12
12
|
import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
@@ -134,7 +134,8 @@ describe('ViewEditor', () => {
|
|
|
134
134
|
expect(addedPropertyProjection!.props.property).toBe('added_property');
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
// TODO(mykola): Fix flaky test.
|
|
138
|
+
test('delete property', { retry: 2 }, async () => {
|
|
138
139
|
await Default.run();
|
|
139
140
|
await waitForViewEditor();
|
|
140
141
|
|
|
@@ -200,4 +201,4 @@ describe('ViewEditor', () => {
|
|
|
200
201
|
// Also verify that the field is back in the visible fields list.
|
|
201
202
|
expect(debugObjects.view.projection.fields.filter(({ visible }) => visible !== false).length).toBeGreaterThan(0);
|
|
202
203
|
});
|
|
203
|
-
});
|
|
204
|
+
}, 30_000);
|