@dxos/react-ui-form 0.8.4-main.c1de068 → 0.8.4-main.c85a9c8dae
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/README.md +0 -1
- package/dist/lib/browser/index.mjs +2314 -2078
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +2314 -2078
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +8 -7
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +82 -5
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +81 -25
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +127 -55
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField.d.ts +37 -0
- package/dist/types/src/components/Form/FormField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormFieldComponent.d.ts +78 -0
- package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts +9 -0
- package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormFieldSet.d.ts +19 -0
- package/dist/types/src/components/Form/FormFieldSet.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/ArrayField.d.ts +18 -0
- package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/BooleanField.d.ts +4 -0
- package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/GeoPointField.d.ts +5 -0
- package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/MarkdownField.d.ts +4 -0
- package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/NumberField.d.ts +4 -0
- package/dist/types/src/components/Form/fields/NumberField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/RefField.d.ts +14 -0
- package/dist/types/src/components/Form/fields/RefField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/SelectField.d.ts +10 -0
- package/dist/types/src/components/Form/fields/SelectField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +5 -0
- package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts +82 -0
- package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/TextAreaField.d.ts +4 -0
- package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/TextField.d.ts +4 -0
- package/dist/types/src/components/Form/fields/TextField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/TupleField.d.ts +6 -0
- package/dist/types/src/components/Form/fields/TupleField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/index.d.ts +12 -0
- package/dist/types/src/components/Form/fields/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/index.d.ts +2 -4
- package/dist/types/src/components/Form/index.d.ts.map +1 -1
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +46 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +85 -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/Settings/Settings.d.ts +56 -0
- package/dist/types/src/components/Settings/Settings.d.ts.map +1 -0
- package/dist/types/src/components/Settings/Settings.stories.d.ts +81 -0
- package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -0
- package/dist/types/src/components/Settings/index.d.ts +2 -0
- package/dist/types/src/components/Settings/index.d.ts.map +1 -0
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +22 -10
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +84 -8
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +2 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +4 -3
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -3
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useFormHandler.d.ts +82 -0
- package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useKeyHandler.d.ts +6 -0
- package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +19 -10
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/field.d.ts +3 -3
- package/dist/types/src/util/field.d.ts.map +1 -1
- package/dist/types/src/util/formatting.d.ts +2 -2
- package/dist/types/src/util/formatting.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/properties.d.ts +7 -0
- package/dist/types/src/util/properties.d.ts.map +1 -0
- package/dist/types/src/util/refs.d.ts +2 -3
- package/dist/types/src/util/refs.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +51 -42
- package/src/components/FieldEditor/FieldEditor.stories.tsx +51 -32
- package/src/components/FieldEditor/FieldEditor.test.tsx +3 -2
- package/src/components/FieldEditor/FieldEditor.tsx +87 -83
- package/src/components/Form/Form.stories.tsx +156 -219
- package/src/components/Form/Form.tsx +347 -96
- package/src/components/Form/FormField.tsx +294 -0
- package/src/components/Form/FormFieldComponent.stories.tsx +65 -0
- package/src/components/Form/FormFieldComponent.tsx +172 -0
- package/src/components/Form/FormFieldSet.tsx +123 -0
- package/src/components/Form/README.md +3 -0
- package/src/components/Form/fields/ArrayField.tsx +149 -0
- package/src/components/Form/fields/BooleanField.tsx +22 -0
- package/src/components/Form/fields/GeoPointField.tsx +120 -0
- package/src/components/Form/fields/MarkdownField.tsx +78 -0
- package/src/components/Form/fields/NumberField.tsx +39 -0
- package/src/components/Form/fields/RefField.tsx +189 -0
- package/src/components/Form/fields/SelectField.tsx +65 -0
- package/src/components/Form/fields/SelectOptionField.stories.tsx +64 -0
- package/src/components/Form/{custom/SelectOptionsInput.tsx → fields/SelectOptionField.tsx} +46 -41
- package/src/components/Form/fields/TextAreaField.tsx +38 -0
- package/src/components/Form/fields/TextField.tsx +38 -0
- package/src/components/Form/{custom/TupleInput.tsx → fields/TupleField.tsx} +16 -9
- package/src/components/Form/fields/index.ts +15 -0
- package/src/components/Form/index.ts +3 -4
- package/src/components/ObjectPicker/ObjectPicker.stories.tsx +210 -0
- package/src/components/ObjectPicker/ObjectPicker.tsx +175 -0
- package/src/components/{ControlSection → ObjectPicker}/index.ts +1 -1
- package/src/components/Settings/Settings.stories.tsx +56 -0
- package/src/components/Settings/Settings.tsx +230 -0
- package/src/components/Settings/index.ts +5 -0
- package/src/components/ViewEditor/ViewEditor.stories.tsx +140 -62
- package/src/components/ViewEditor/ViewEditor.test.tsx +17 -18
- package/src/components/ViewEditor/ViewEditor.tsx +341 -202
- package/src/components/index.ts +2 -3
- package/src/components/testing.tsx +22 -11
- package/src/hooks/index.ts +2 -3
- package/src/hooks/useFormHandler.ts +380 -0
- package/src/hooks/useKeyHandler.tsx +37 -0
- package/src/translations.ts +21 -12
- package/src/util/field.ts +33 -43
- package/src/util/formatting.ts +22 -22
- package/src/util/index.ts +1 -1
- package/src/util/properties.ts +18 -0
- package/src/util/refs.ts +12 -18
- package/dist/types/src/components/ControlSection/ControlSection.d.ts +0 -23
- package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +0 -1
- package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +0 -8
- package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +0 -1
- package/dist/types/src/components/ControlSection/index.d.ts +0 -2
- package/dist/types/src/components/ControlSection/index.d.ts.map +0 -1
- package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
- package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
- package/dist/types/src/components/Form/Defaults.d.ts +0 -14
- package/dist/types/src/components/Form/Defaults.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormActions.d.ts +0 -9
- package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormContent.d.ts +0 -57
- package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormContext.d.ts +0 -23
- package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
- package/dist/types/src/components/Form/Input.d.ts +0 -26
- package/dist/types/src/components/Form/Input.d.ts.map +0 -1
- package/dist/types/src/components/Form/RefField.d.ts +0 -12
- package/dist/types/src/components/Form/RefField.d.ts.map +0 -1
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +0 -4
- package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +0 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +0 -4
- package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +0 -1
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +0 -7
- package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +0 -1
- package/dist/types/src/components/Form/custom/TupleInput.d.ts +0 -6
- package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +0 -1
- package/dist/types/src/components/Form/custom/index.d.ts +0 -4
- package/dist/types/src/components/Form/custom/index.d.ts.map +0 -1
- package/dist/types/src/components/Form/factory.d.ts +0 -8
- package/dist/types/src/components/Form/factory.d.ts.map +0 -1
- package/dist/types/src/components/deprecated/Form.d.ts +0 -15
- package/dist/types/src/components/deprecated/Form.d.ts.map +0 -1
- package/dist/types/src/components/deprecated/Form.stories.d.ts +0 -13
- package/dist/types/src/components/deprecated/Form.stories.d.ts.map +0 -1
- package/dist/types/src/components/deprecated/FormInput.d.ts +0 -16
- package/dist/types/src/components/deprecated/FormInput.d.ts.map +0 -1
- package/dist/types/src/components/deprecated/index.d.ts +0 -2
- package/dist/types/src/components/deprecated/index.d.ts.map +0 -1
- package/dist/types/src/hooks/useForm.d.ts +0 -67
- package/dist/types/src/hooks/useForm.d.ts.map +0 -1
- package/dist/types/src/hooks/useQueryRefOptions.d.ts +0 -23
- package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +0 -1
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +0 -8
- package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +0 -1
- package/dist/types/src/util/schema.d.ts +0 -3
- package/dist/types/src/util/schema.d.ts.map +0 -1
- package/src/components/ControlSection/ControlSection.stories.tsx +0 -41
- package/src/components/ControlSection/ControlSection.tsx +0 -139
- package/src/components/Form/ArrayField.tsx +0 -124
- package/src/components/Form/Defaults.tsx +0 -203
- package/src/components/Form/FormActions.tsx +0 -53
- package/src/components/Form/FormContent.tsx +0 -240
- package/src/components/Form/FormContext.tsx +0 -110
- package/src/components/Form/Input.tsx +0 -51
- package/src/components/Form/RefField.tsx +0 -213
- package/src/components/Form/custom/GeoPointInput.tsx +0 -72
- package/src/components/Form/custom/SelectOptionsInput.stories.tsx +0 -61
- package/src/components/Form/custom/index.ts +0 -7
- package/src/components/Form/factory.tsx +0 -31
- package/src/components/deprecated/Form.stories.tsx +0 -62
- package/src/components/deprecated/Form.tsx +0 -119
- package/src/components/deprecated/FormInput.tsx +0 -71
- package/src/components/deprecated/index.ts +0 -5
- package/src/hooks/useForm.ts +0 -291
- package/src/hooks/useQueryRefOptions.ts +0 -53
- package/src/hooks/useRefQueryLookupHandler.ts +0 -39
- package/src/util/schema.ts +0 -14
|
@@ -2,125 +2,203 @@
|
|
|
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, useMemo,
|
|
10
|
-
|
|
11
|
-
import { Obj, Type } from '@dxos/echo';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { DXN, Filter, JsonSchema, Obj, Query, type QueryAST, Tag, Type } from '@dxos/echo';
|
|
10
|
+
import { type View } from '@dxos/echo';
|
|
11
|
+
import { type EchoSchema, Format, type Mutable } from '@dxos/echo/internal';
|
|
12
|
+
import { useQuery } from '@dxos/react-client/echo';
|
|
13
|
+
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
15
14
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
16
|
+
import { type ProjectionModel, ViewModel, getTypenameFromQuery } from '@dxos/schema';
|
|
17
|
+
import { Employer, Organization, Person, Pipeline } from '@dxos/types';
|
|
18
18
|
|
|
19
|
-
import { ViewEditor, type ViewEditorProps } from './ViewEditor';
|
|
20
19
|
import { translations } from '../../translations';
|
|
21
|
-
import { TestLayout,
|
|
20
|
+
import { TestLayout, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
21
|
+
|
|
22
|
+
import { ViewEditor, type ViewEditorProps } from './ViewEditor';
|
|
23
|
+
|
|
24
|
+
const types = [
|
|
25
|
+
// TODO(burdon): Get label from annotation.
|
|
26
|
+
{ value: Organization.Organization.typename, label: 'Organization' },
|
|
27
|
+
{ value: Person.Person.typename, label: 'Person' },
|
|
28
|
+
{ value: Pipeline.Pipeline.typename, label: 'Project' },
|
|
29
|
+
{ value: Employer.Employer.typename, label: 'Employer' },
|
|
30
|
+
];
|
|
22
31
|
|
|
23
32
|
// Type definition for debug objects exposed to tests.
|
|
24
33
|
export type ViewEditorDebugObjects = {
|
|
25
34
|
schema: EchoSchema;
|
|
26
|
-
view:
|
|
35
|
+
view: View.View;
|
|
27
36
|
projection: ProjectionModel;
|
|
28
37
|
};
|
|
29
38
|
|
|
30
|
-
type StoryProps = Pick<ViewEditorProps, 'readonly'>;
|
|
39
|
+
type StoryProps = Pick<ViewEditorProps, 'readonly' | 'mode'>;
|
|
31
40
|
|
|
32
41
|
const DefaultStory = (props: StoryProps) => {
|
|
33
|
-
const space =
|
|
42
|
+
const { space } = useClientStory();
|
|
34
43
|
const [schema, setSchema] = useState<EchoSchema>();
|
|
35
|
-
const [view, setView] = useState<
|
|
36
|
-
const
|
|
44
|
+
const [view, setView] = useState<View.View>();
|
|
45
|
+
const projectionRef = useRef<ProjectionModel>(null);
|
|
46
|
+
|
|
47
|
+
const tags = useQuery(space?.db, Filter.type(Tag.Tag));
|
|
48
|
+
|
|
37
49
|
useAsyncEffect(async () => {
|
|
38
50
|
if (space) {
|
|
39
|
-
|
|
51
|
+
const TestSchema = Schema.Struct({
|
|
40
52
|
name: Schema.String,
|
|
41
53
|
email: Format.Email,
|
|
42
54
|
salary: Format.Currency(),
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
}).pipe(
|
|
56
|
+
Type.object({
|
|
57
|
+
typename: 'example.com/type/Test',
|
|
58
|
+
version: '0.1.0',
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const AlternateSchema = Schema.Struct({
|
|
63
|
+
title: Schema.String,
|
|
64
|
+
description: Schema.String,
|
|
65
|
+
completed: Schema.Boolean,
|
|
66
|
+
}).pipe(
|
|
67
|
+
Type.object({
|
|
68
|
+
typename: 'example.com/type/Alternate',
|
|
69
|
+
version: '0.1.0',
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const [testSchema] = await space.db.schemaRegistry.register([TestSchema, AlternateSchema]);
|
|
74
|
+
const view = ViewModel.make({
|
|
47
75
|
name: 'Test',
|
|
48
|
-
|
|
49
|
-
jsonSchema: toJsonSchema(TestSchema),
|
|
50
|
-
presentation: Obj.make(Type.Expando, {}),
|
|
76
|
+
query: Query.select(Filter.type(TestSchema)),
|
|
77
|
+
jsonSchema: JsonSchema.toJsonSchema(TestSchema),
|
|
51
78
|
});
|
|
52
|
-
const projection = new ProjectionModel(schema.jsonSchema, view.projection);
|
|
53
79
|
|
|
54
|
-
setSchema(
|
|
80
|
+
setSchema(testSchema);
|
|
55
81
|
setView(view);
|
|
56
|
-
setProjection(projection);
|
|
57
82
|
}
|
|
58
83
|
}, [space]);
|
|
59
84
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
(newTypename: string) => {
|
|
64
|
-
if (!schema) {
|
|
85
|
+
const updateViewQuery = useCallback(
|
|
86
|
+
async (newQuery: QueryAST.Query, target?: string) => {
|
|
87
|
+
if (!schema || !view || !space) {
|
|
65
88
|
return;
|
|
66
89
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
|
|
91
|
+
if (props.mode === 'tag') {
|
|
92
|
+
const queue = target && DXN.tryParse(target) ? target : undefined;
|
|
93
|
+
const query = queue ? Query.fromAst(newQuery).from({ queues: [queue] }) : Query.fromAst(newQuery);
|
|
94
|
+
Obj.change(view, (v) => {
|
|
95
|
+
v.query.ast = query.ast as Mutable<typeof query.ast>;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const typename = getTypenameFromQuery(query.ast);
|
|
99
|
+
const [newSchema] = await space.db.schemaRegistry.query({ typename }).run();
|
|
100
|
+
if (!newSchema) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const newView = ViewModel.make({
|
|
105
|
+
query,
|
|
106
|
+
jsonSchema: newSchema.jsonSchema,
|
|
107
|
+
});
|
|
108
|
+
Obj.change(view, (v) => {
|
|
109
|
+
v.projection = Obj.getSnapshot(newView).projection as Mutable<typeof v.projection>;
|
|
110
|
+
});
|
|
111
|
+
setSchema(() => newSchema);
|
|
112
|
+
} else {
|
|
113
|
+
Obj.change(view, (v) => {
|
|
114
|
+
v.query.ast = newQuery as Mutable<typeof newQuery>;
|
|
115
|
+
});
|
|
116
|
+
schema.updateTypename(getTypenameFromQuery(newQuery));
|
|
70
117
|
}
|
|
71
|
-
schema.updateTypename(newTypename);
|
|
72
118
|
},
|
|
73
|
-
[
|
|
119
|
+
[view, schema],
|
|
74
120
|
);
|
|
75
121
|
|
|
76
|
-
const handleDelete = useCallback(
|
|
122
|
+
const handleDelete = useCallback(
|
|
123
|
+
(property: string) => projectionRef.current?.deleteFieldProjection(property),
|
|
124
|
+
[projectionRef],
|
|
125
|
+
);
|
|
77
126
|
|
|
78
127
|
// Expose objects on window for test access.
|
|
79
128
|
useEffect(() => {
|
|
80
|
-
if (typeof window !== 'undefined' && schema && view &&
|
|
81
|
-
(window as any)[VIEW_EDITOR_DEBUG_SYMBOL] = {
|
|
129
|
+
if (typeof window !== 'undefined' && schema && view && projectionRef.current) {
|
|
130
|
+
(window as any)[VIEW_EDITOR_DEBUG_SYMBOL] = {
|
|
131
|
+
schema,
|
|
132
|
+
view,
|
|
133
|
+
projection: projectionRef.current,
|
|
134
|
+
} satisfies ViewEditorDebugObjects;
|
|
82
135
|
}
|
|
83
|
-
}, [schema, view
|
|
136
|
+
}, [schema, view]);
|
|
84
137
|
|
|
85
138
|
// NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
|
|
86
139
|
const json = useMemo(
|
|
87
|
-
() => JSON.parse(JSON.stringify({ schema, view, projection })),
|
|
88
|
-
[JSON.stringify(schema), JSON.stringify(view)
|
|
140
|
+
() => JSON.parse(JSON.stringify({ schema, view, projection: projectionRef.current })),
|
|
141
|
+
[JSON.stringify(schema), JSON.stringify(view)],
|
|
89
142
|
);
|
|
90
143
|
|
|
91
|
-
if (!schema || !view
|
|
144
|
+
if (!schema || !view) {
|
|
92
145
|
return <div />;
|
|
93
146
|
}
|
|
94
147
|
|
|
95
148
|
return (
|
|
96
149
|
<TestLayout json={json}>
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
150
|
+
<ViewEditor
|
|
151
|
+
ref={projectionRef}
|
|
152
|
+
schema={schema}
|
|
153
|
+
view={view}
|
|
154
|
+
registry={space?.db.schemaRegistry}
|
|
155
|
+
mode={props.mode}
|
|
156
|
+
readonly={props.readonly}
|
|
157
|
+
types={types}
|
|
158
|
+
tags={tags}
|
|
159
|
+
onQueryChanged={updateViewQuery}
|
|
160
|
+
onDelete={handleDelete}
|
|
161
|
+
/>
|
|
107
162
|
</TestLayout>
|
|
108
163
|
);
|
|
109
164
|
};
|
|
110
165
|
|
|
111
|
-
const meta
|
|
166
|
+
const meta = {
|
|
112
167
|
title: 'ui/react-ui-form/ViewEditor',
|
|
113
168
|
render: DefaultStory,
|
|
114
|
-
decorators: [
|
|
115
|
-
|
|
116
|
-
|
|
169
|
+
decorators: [
|
|
170
|
+
withClientProvider({
|
|
171
|
+
createSpace: true,
|
|
172
|
+
types: [Tag.Tag],
|
|
173
|
+
onCreateSpace: ({ space }) => {
|
|
174
|
+
space.db.add(Tag.make({ label: 'Important' }));
|
|
175
|
+
space.db.add(Tag.make({ label: 'Investor' }));
|
|
176
|
+
space.db.add(Tag.make({ label: 'New' }));
|
|
177
|
+
},
|
|
178
|
+
}),
|
|
179
|
+
withTheme(),
|
|
180
|
+
withLayout({ layout: 'fullscreen' }),
|
|
181
|
+
],
|
|
182
|
+
parameters: {
|
|
183
|
+
layout: 'fullscreen',
|
|
184
|
+
translations,
|
|
185
|
+
},
|
|
186
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
117
187
|
|
|
118
188
|
export default meta;
|
|
119
189
|
|
|
120
|
-
type Story = StoryObj<
|
|
190
|
+
type Story = StoryObj<typeof meta>;
|
|
121
191
|
|
|
122
192
|
export const Default: Story = {};
|
|
123
193
|
|
|
124
194
|
export const Readonly: Story = {
|
|
125
|
-
args: {
|
|
195
|
+
args: {
|
|
196
|
+
readonly: true,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const TagQueryMode: Story = {
|
|
201
|
+
args: {
|
|
202
|
+
mode: 'tag',
|
|
203
|
+
},
|
|
126
204
|
};
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { composeStories } from '@storybook/react';
|
|
6
|
-
import {
|
|
6
|
+
import { cleanup, fireEvent, screen, waitFor } from '@testing-library/react';
|
|
7
7
|
import { afterEach, describe, expect, test } from 'vitest';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { View } from '@dxos/echo';
|
|
10
|
+
import { EchoSchema, isInstanceOf } from '@dxos/echo/internal';
|
|
11
|
+
import { ProjectionModel } from '@dxos/schema';
|
|
12
|
+
|
|
13
|
+
import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
11
14
|
|
|
12
15
|
import * as stories from './ViewEditor.stories';
|
|
13
16
|
import { type ViewEditorDebugObjects } from './ViewEditor.stories';
|
|
14
|
-
import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
15
17
|
|
|
16
18
|
const { Default } = composeStories(stories);
|
|
17
19
|
|
|
@@ -19,7 +21,7 @@ const getViewEditorDebugObjects = (): ViewEditorDebugObjects => {
|
|
|
19
21
|
const debugObjects = (window as any)[VIEW_EDITOR_DEBUG_SYMBOL] as ViewEditorDebugObjects;
|
|
20
22
|
expect(debugObjects).toBeDefined();
|
|
21
23
|
expect(debugObjects.schema).toBeInstanceOf(EchoSchema);
|
|
22
|
-
expect(isInstanceOf(
|
|
24
|
+
expect(isInstanceOf(View.View, debugObjects.view)).toBeTruthy();
|
|
23
25
|
expect(debugObjects.projection).toBeInstanceOf(ProjectionModel);
|
|
24
26
|
return debugObjects;
|
|
25
27
|
};
|
|
@@ -41,7 +43,7 @@ describe('ViewEditor', () => {
|
|
|
41
43
|
test('renders view editor', async () => {
|
|
42
44
|
await Default.run();
|
|
43
45
|
await waitForViewEditor();
|
|
44
|
-
expect(screen.getByText('
|
|
46
|
+
expect(screen.getByText('Record type')).toBeInTheDocument();
|
|
45
47
|
});
|
|
46
48
|
|
|
47
49
|
test('change property name', async () => {
|
|
@@ -53,7 +55,7 @@ describe('ViewEditor', () => {
|
|
|
53
55
|
const nameField = screen.getByText('name');
|
|
54
56
|
fireEvent.click(nameField);
|
|
55
57
|
|
|
56
|
-
const fieldInput = screen.getByPlaceholderText('
|
|
58
|
+
const fieldInput = screen.getByPlaceholderText('Property name');
|
|
57
59
|
fireEvent.change(fieldInput, { target: { value: 'new_property' } });
|
|
58
60
|
|
|
59
61
|
fireEvent.click(screen.getByTestId('save-button'));
|
|
@@ -88,12 +90,12 @@ describe('ViewEditor', () => {
|
|
|
88
90
|
await Default.run();
|
|
89
91
|
await waitForViewEditor();
|
|
90
92
|
|
|
91
|
-
// Click the add property button.
|
|
93
|
+
// Click the add property button. The new field is auto-expanded by handleAdd.
|
|
92
94
|
const addButton = screen.getByText('Add property');
|
|
93
95
|
fireEvent.click(addButton);
|
|
94
96
|
|
|
95
97
|
// Fill out the property field.
|
|
96
|
-
const fieldInput = screen.getByPlaceholderText('
|
|
98
|
+
const fieldInput = screen.getByPlaceholderText('Property name');
|
|
97
99
|
fireEvent.change(fieldInput, { target: { value: 'added_property' } });
|
|
98
100
|
|
|
99
101
|
// Click the format combo box and select the first option.
|
|
@@ -133,14 +135,15 @@ describe('ViewEditor', () => {
|
|
|
133
135
|
expect(addedPropertyProjection!.props.property).toBe('added_property');
|
|
134
136
|
});
|
|
135
137
|
|
|
136
|
-
|
|
138
|
+
// TODO(mykola): Fix flaky test.
|
|
139
|
+
test('delete property', { retry: 2 }, async () => {
|
|
137
140
|
await Default.run();
|
|
138
141
|
await waitForViewEditor();
|
|
139
142
|
|
|
140
143
|
// Find the delete button for the 'name' property.
|
|
141
144
|
const nameProperty = screen.getByText('name');
|
|
142
145
|
const propertyRow = nameProperty.closest('[role="listitem"]');
|
|
143
|
-
const deleteButton = propertyRow?.querySelector('
|
|
146
|
+
const deleteButton = propertyRow?.querySelector('[data-testid="field.delete"]');
|
|
144
147
|
|
|
145
148
|
if (!deleteButton) {
|
|
146
149
|
throw new Error('Delete button not found');
|
|
@@ -188,19 +191,15 @@ describe('ViewEditor', () => {
|
|
|
188
191
|
// Access the live objects directly from window using symbol.
|
|
189
192
|
const debugObjects = getViewEditorDebugObjects();
|
|
190
193
|
|
|
191
|
-
// Check that hiddenFields is non-empty.
|
|
192
|
-
expect(debugObjects.view.projection.hiddenFields).toBeDefined();
|
|
193
|
-
expect(debugObjects.view.projection.hiddenFields!.length).toBeGreaterThan(0);
|
|
194
|
-
|
|
195
194
|
// Click the show button
|
|
196
195
|
fireEvent.click(screen.getByTestId('show-field-button'));
|
|
197
196
|
|
|
198
197
|
// Wait for the data to update and check that hiddenFields is empty.
|
|
199
198
|
await waitFor(() => {
|
|
200
|
-
expect(debugObjects.view.projection.
|
|
199
|
+
expect(debugObjects.view.projection.fields.filter(({ visible }) => visible === false)!.length).toBe(0);
|
|
201
200
|
});
|
|
202
201
|
|
|
203
202
|
// Also verify that the field is back in the visible fields list.
|
|
204
|
-
expect(debugObjects.view.projection.fields.length).toBeGreaterThan(0);
|
|
203
|
+
expect(debugObjects.view.projection.fields.filter(({ visible }) => visible !== false).length).toBeGreaterThan(0);
|
|
205
204
|
});
|
|
206
|
-
});
|
|
205
|
+
}, 30_000);
|