@dxos/react-ui-form 0.8.3 → 0.8.4-main.03d5cd7b56
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 +2794 -2163
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +82 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +2794 -2163
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/translations.mjs +84 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +9 -9
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +86 -7
- package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +109 -25
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +130 -56
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField.d.ts +43 -0
- package/dist/types/src/components/Form/FormField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormFieldComponent.d.ts +79 -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 +15 -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 +11 -0
- package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -0
- package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts +84 -0
- package/dist/types/src/components/Form/fields/MarkdownField.stories.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 +22 -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 +84 -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/ObjectForm/ObjectForm.d.ts +9 -0
- package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -0
- package/dist/types/src/components/ObjectForm/index.d.ts +2 -0
- package/dist/types/src/components/ObjectForm/index.d.ts.map +1 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +68 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
- package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +87 -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/ObjectProperties/ObjectProperties.d.ts +9 -0
- package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -0
- package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts +127 -0
- package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts.map +1 -0
- package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts +2 -0
- package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts.map +1 -0
- package/dist/types/src/components/ObjectProperties/index.d.ts +2 -0
- package/dist/types/src/components/ObjectProperties/index.d.ts.map +1 -0
- package/dist/types/src/components/Settings/Settings.d.ts +51 -0
- package/dist/types/src/components/Settings/Settings.d.ts.map +1 -0
- package/dist/types/src/components/Settings/Settings.stories.d.ts +84 -0
- package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -0
- package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +43 -0
- package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +1 -0
- package/dist/types/src/components/Settings/SettingsItem.d.ts +16 -0
- package/dist/types/src/components/Settings/SettingsItem.d.ts.map +1 -0
- package/dist/types/src/components/Settings/SettingsSelectField.d.ts +18 -0
- package/dist/types/src/components/Settings/SettingsSelectField.d.ts.map +1 -0
- package/dist/types/src/components/Settings/index.d.ts +4 -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 +87 -9
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +4 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +5 -4
- 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 +7 -0
- package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +0 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +68 -58
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/field-type.d.ts +19 -0
- package/dist/types/src/util/field-type.d.ts.map +1 -0
- 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 +2 -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 +3 -3
- package/dist/types/src/util/refs.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +57 -48
- package/src/components/FieldEditor/FieldEditor.stories.tsx +53 -32
- package/src/components/FieldEditor/FieldEditor.test.tsx +13 -13
- package/src/components/FieldEditor/FieldEditor.tsx +90 -95
- package/src/components/Form/AUDIT.md +17 -0
- package/src/components/Form/Form.stories.tsx +148 -224
- package/src/components/Form/Form.tsx +375 -95
- package/src/components/Form/FormField.tsx +306 -0
- package/src/components/Form/FormFieldComponent.stories.tsx +65 -0
- package/src/components/Form/FormFieldComponent.tsx +174 -0
- package/src/components/Form/FormFieldSet.tsx +144 -0
- package/src/components/Form/README.md +3 -0
- package/src/components/Form/fields/ArrayField.tsx +155 -0
- package/src/components/Form/fields/BooleanField.tsx +22 -0
- package/src/components/Form/fields/GeoPointField.tsx +121 -0
- package/src/components/Form/fields/MarkdownField.stories.tsx +206 -0
- package/src/components/Form/fields/MarkdownField.tsx +168 -0
- package/src/components/Form/fields/NumberField.tsx +39 -0
- package/src/components/Form/fields/RefField.tsx +229 -0
- package/src/components/Form/fields/SelectField.tsx +65 -0
- package/src/components/Form/fields/SelectOptionField.stories.tsx +66 -0
- package/src/components/Form/{custom/SelectOptionsInput.tsx → fields/SelectOptionField.tsx} +51 -46
- 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} +17 -10
- package/src/components/Form/fields/index.ts +15 -0
- package/src/components/Form/index.ts +3 -4
- package/src/components/ObjectForm/ObjectForm.tsx +114 -0
- package/src/components/{ControlSection → ObjectForm}/index.ts +1 -1
- package/src/components/ObjectPicker/ObjectPicker.stories.tsx +212 -0
- package/src/components/ObjectPicker/ObjectPicker.tsx +202 -0
- package/src/components/ObjectPicker/index.ts +5 -0
- package/src/components/ObjectProperties/ObjectProperties.stories.tsx +362 -0
- package/src/components/ObjectProperties/ObjectProperties.test.tsx +101 -0
- package/src/components/ObjectProperties/ObjectProperties.tsx +141 -0
- package/src/components/ObjectProperties/index.ts +5 -0
- package/src/components/Settings/AUDIT.md +52 -0
- package/src/components/Settings/Settings.stories.tsx +104 -0
- package/src/components/Settings/Settings.tsx +80 -0
- package/src/components/Settings/SettingsFieldSet.tsx +257 -0
- package/src/components/Settings/SettingsItem.tsx +58 -0
- package/src/components/Settings/SettingsSelectField.tsx +59 -0
- package/src/components/Settings/index.ts +7 -0
- package/src/components/ViewEditor/ViewEditor.stories.tsx +146 -62
- package/src/components/ViewEditor/ViewEditor.test.tsx +43 -43
- package/src/components/ViewEditor/ViewEditor.tsx +354 -219
- package/src/components/index.ts +4 -3
- package/src/components/testing.tsx +31 -12
- package/src/hooks/index.ts +2 -3
- package/src/hooks/useFormHandler.ts +380 -0
- package/src/hooks/useKeyHandler.tsx +37 -0
- package/src/index.ts +0 -4
- package/src/translations.ts +74 -60
- package/src/util/field-type.ts +60 -0
- package/src/util/field.ts +33 -43
- package/src/util/formatting.ts +22 -22
- package/src/util/index.ts +2 -1
- package/src/util/properties.ts +18 -0
- package/src/util/refs.ts +17 -19
- package/dist/lib/node/index.cjs +0 -2416
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- 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/ViewEditor/Test.stories.d.ts +0 -10
- package/dist/types/src/components/ViewEditor/Test.stories.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/ViewEditor/Test.stories.tsx +0 -45
- 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,119 +2,203 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { withClientProvider } from '@dxos/react-client/testing';
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
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';
|
|
14
14
|
import { useAsyncEffect } from '@dxos/react-ui';
|
|
15
|
-
import {
|
|
16
|
-
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';
|
|
17
18
|
|
|
19
|
+
import { translations } from '#translations';
|
|
20
|
+
|
|
21
|
+
import { TestLayout, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
18
22
|
import { ViewEditor, type ViewEditorProps } from './ViewEditor';
|
|
19
|
-
|
|
20
|
-
|
|
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
|
+
];
|
|
21
31
|
|
|
22
32
|
// Type definition for debug objects exposed to tests.
|
|
23
33
|
export type ViewEditorDebugObjects = {
|
|
24
34
|
schema: EchoSchema;
|
|
25
|
-
view:
|
|
26
|
-
projection:
|
|
35
|
+
view: View.View;
|
|
36
|
+
projection: ProjectionModel;
|
|
27
37
|
};
|
|
28
38
|
|
|
29
|
-
type
|
|
39
|
+
type DefaultStoryProps = Pick<ViewEditorProps, 'readonly' | 'mode'>;
|
|
30
40
|
|
|
31
|
-
const DefaultStory = (props:
|
|
32
|
-
const space =
|
|
41
|
+
const DefaultStory = (props: DefaultStoryProps) => {
|
|
42
|
+
const { space } = useClientStory();
|
|
33
43
|
const [schema, setSchema] = useState<EchoSchema>();
|
|
34
|
-
const [view, setView] = useState<
|
|
35
|
-
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
|
+
|
|
36
49
|
useAsyncEffect(async () => {
|
|
37
50
|
if (space) {
|
|
38
|
-
|
|
51
|
+
const TestSchema = Schema.Struct({
|
|
39
52
|
name: Schema.String,
|
|
40
53
|
email: Format.Email,
|
|
41
54
|
salary: Format.Currency(),
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
}).pipe(
|
|
56
|
+
Type.object({
|
|
57
|
+
typename: 'com.example.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: 'com.example.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({
|
|
75
|
+
name: 'Test',
|
|
76
|
+
query: Query.select(Filter.type(TestSchema)),
|
|
77
|
+
jsonSchema: JsonSchema.toJsonSchema(TestSchema),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
setSchema(testSchema);
|
|
49
81
|
setView(view);
|
|
50
|
-
setProjection(projection);
|
|
51
82
|
}
|
|
52
83
|
}, [space]);
|
|
53
84
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
(newTypename: string) => {
|
|
58
|
-
if (!schema) {
|
|
85
|
+
const updateViewQuery = useCallback(
|
|
86
|
+
async (newQuery: QueryAST.Query, target?: string) => {
|
|
87
|
+
if (!schema || !view || !space) {
|
|
59
88
|
return;
|
|
60
89
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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.update(view, (view) => {
|
|
95
|
+
view.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.update(view, (view) => {
|
|
109
|
+
view.projection = Obj.getSnapshot(newView).projection as Mutable<typeof view.projection>;
|
|
110
|
+
});
|
|
111
|
+
setSchema(() => newSchema);
|
|
112
|
+
} else {
|
|
113
|
+
Obj.update(view, (view) => {
|
|
114
|
+
view.query.ast = newQuery as Mutable<typeof newQuery>;
|
|
115
|
+
});
|
|
116
|
+
schema.updateTypename(getTypenameFromQuery(newQuery));
|
|
64
117
|
}
|
|
65
|
-
schema.updateTypename(newTypename);
|
|
66
118
|
},
|
|
67
|
-
[
|
|
119
|
+
[view, schema],
|
|
68
120
|
);
|
|
69
121
|
|
|
70
|
-
const handleDelete = useCallback(
|
|
122
|
+
const handleDelete = useCallback(
|
|
123
|
+
(property: string) => projectionRef.current?.deleteFieldProjection(property),
|
|
124
|
+
[projectionRef],
|
|
125
|
+
);
|
|
71
126
|
|
|
72
127
|
// Expose objects on window for test access.
|
|
73
128
|
useEffect(() => {
|
|
74
|
-
if (typeof window !== 'undefined' && schema && view &&
|
|
75
|
-
(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;
|
|
76
135
|
}
|
|
77
|
-
}, [schema, view
|
|
136
|
+
}, [schema, view]);
|
|
78
137
|
|
|
79
138
|
// NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
|
|
80
139
|
const json = useMemo(
|
|
81
|
-
() => JSON.parse(JSON.stringify({ schema, view, projection })),
|
|
82
|
-
[JSON.stringify(schema), JSON.stringify(view)
|
|
140
|
+
() => JSON.parse(JSON.stringify({ schema, view, projection: projectionRef.current })),
|
|
141
|
+
[JSON.stringify(schema), JSON.stringify(view)],
|
|
83
142
|
);
|
|
84
143
|
|
|
85
|
-
if (!schema || !view
|
|
144
|
+
if (!schema || !view) {
|
|
86
145
|
return <div />;
|
|
87
146
|
}
|
|
88
147
|
|
|
89
148
|
return (
|
|
90
149
|
<TestLayout json={json}>
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
+
/>
|
|
101
162
|
</TestLayout>
|
|
102
163
|
);
|
|
103
164
|
};
|
|
104
165
|
|
|
105
|
-
const meta
|
|
166
|
+
const meta = {
|
|
106
167
|
title: 'ui/react-ui-form/ViewEditor',
|
|
107
168
|
render: DefaultStory,
|
|
108
|
-
decorators: [
|
|
109
|
-
|
|
110
|
-
|
|
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>;
|
|
111
187
|
|
|
112
188
|
export default meta;
|
|
113
189
|
|
|
114
|
-
type Story = StoryObj<
|
|
190
|
+
type Story = StoryObj<typeof meta>;
|
|
115
191
|
|
|
116
192
|
export const Default: Story = {};
|
|
117
193
|
|
|
118
194
|
export const Readonly: Story = {
|
|
119
|
-
args: {
|
|
195
|
+
args: {
|
|
196
|
+
readonly: true,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const TagQueryMode: Story = {
|
|
201
|
+
args: {
|
|
202
|
+
mode: 'tag',
|
|
203
|
+
},
|
|
120
204
|
};
|
|
@@ -3,15 +3,16 @@
|
|
|
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';
|
|
11
12
|
|
|
13
|
+
import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
12
14
|
import * as stories from './ViewEditor.stories';
|
|
13
15
|
import { type ViewEditorDebugObjects } from './ViewEditor.stories';
|
|
14
|
-
import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
|
|
15
16
|
|
|
16
17
|
const { Default } = composeStories(stories);
|
|
17
18
|
|
|
@@ -19,8 +20,8 @@ const getViewEditorDebugObjects = (): ViewEditorDebugObjects => {
|
|
|
19
20
|
const debugObjects = (window as any)[VIEW_EDITOR_DEBUG_SYMBOL] as ViewEditorDebugObjects;
|
|
20
21
|
expect(debugObjects).toBeDefined();
|
|
21
22
|
expect(debugObjects.schema).toBeInstanceOf(EchoSchema);
|
|
22
|
-
expect(debugObjects.view).
|
|
23
|
-
expect(debugObjects.projection).toBeInstanceOf(
|
|
23
|
+
expect(isInstanceOf(View.View, debugObjects.view)).toBeTruthy();
|
|
24
|
+
expect(debugObjects.projection).toBeInstanceOf(ProjectionModel);
|
|
24
25
|
return debugObjects;
|
|
25
26
|
};
|
|
26
27
|
|
|
@@ -41,7 +42,7 @@ describe('ViewEditor', () => {
|
|
|
41
42
|
test('renders view editor', async () => {
|
|
42
43
|
await Default.run();
|
|
43
44
|
await waitForViewEditor();
|
|
44
|
-
expect(screen.getByText('
|
|
45
|
+
expect(screen.getByText('Record type')).toBeInTheDocument();
|
|
45
46
|
});
|
|
46
47
|
|
|
47
48
|
test('change property name', async () => {
|
|
@@ -53,12 +54,12 @@ describe('ViewEditor', () => {
|
|
|
53
54
|
const nameField = screen.getByText('name');
|
|
54
55
|
fireEvent.click(nameField);
|
|
55
56
|
|
|
56
|
-
const fieldInput = screen.getByPlaceholderText('
|
|
57
|
+
const fieldInput = screen.getByPlaceholderText('Property name');
|
|
57
58
|
fireEvent.change(fieldInput, { target: { value: 'new_property' } });
|
|
58
59
|
|
|
59
60
|
fireEvent.click(screen.getByTestId('save-button'));
|
|
60
61
|
|
|
61
|
-
// Wait for the changes to propagate to both UI and schema
|
|
62
|
+
// Wait for the changes to propagate to both UI and schema.
|
|
62
63
|
await waitFor(() => {
|
|
63
64
|
expect(screen.getByText('new_property')).toBeInTheDocument();
|
|
64
65
|
});
|
|
@@ -66,18 +67,18 @@ describe('ViewEditor', () => {
|
|
|
66
67
|
// Access the live objects directly from window using symbol.
|
|
67
68
|
const debugObjects = getViewEditorDebugObjects();
|
|
68
69
|
|
|
69
|
-
// Check schema contains new_property
|
|
70
|
+
// Check schema contains new_property.
|
|
70
71
|
const schemaProperties = debugObjects.schema.jsonSchema.properties;
|
|
71
72
|
expect(schemaProperties).toBeDefined();
|
|
72
73
|
expect(schemaProperties!.new_property).toBeDefined();
|
|
73
74
|
expect(schemaProperties!.name).toBeUndefined();
|
|
74
75
|
|
|
75
|
-
// Check view contains new_property field
|
|
76
|
-
const newPropertyField = debugObjects.view.fields.find((field: any) => field.path === 'new_property');
|
|
76
|
+
// Check view contains new_property field.
|
|
77
|
+
const newPropertyField = debugObjects.view.projection.fields.find((field: any) => field.path === 'new_property');
|
|
77
78
|
expect(newPropertyField).toBeDefined();
|
|
78
79
|
expect(newPropertyField!.path).toBe('new_property');
|
|
79
80
|
|
|
80
|
-
// Check projection contains new_property
|
|
81
|
+
// Check projection contains new_property.
|
|
81
82
|
const fieldProjections = debugObjects.projection.getFieldProjections();
|
|
82
83
|
const newPropertyProjection = fieldProjections.find((proj: any) => proj.field.path === 'new_property');
|
|
83
84
|
expect(newPropertyProjection).toBeDefined();
|
|
@@ -88,25 +89,25 @@ describe('ViewEditor', () => {
|
|
|
88
89
|
await Default.run();
|
|
89
90
|
await waitForViewEditor();
|
|
90
91
|
|
|
91
|
-
// Click the add property button
|
|
92
|
+
// Click the add property button. The new field is auto-expanded by handleAdd.
|
|
92
93
|
const addButton = screen.getByText('Add property');
|
|
93
94
|
fireEvent.click(addButton);
|
|
94
95
|
|
|
95
|
-
// Fill out the property field
|
|
96
|
-
const fieldInput = screen.getByPlaceholderText('
|
|
96
|
+
// Fill out the property field.
|
|
97
|
+
const fieldInput = screen.getByPlaceholderText('Property name');
|
|
97
98
|
fireEvent.change(fieldInput, { target: { value: 'added_property' } });
|
|
98
99
|
|
|
99
|
-
// Click the format combo box and select the first option
|
|
100
|
+
// Click the format combo box and select the first option.
|
|
100
101
|
const formatCombo = screen.getByRole('combobox');
|
|
101
102
|
fireEvent.click(formatCombo);
|
|
102
103
|
|
|
103
104
|
const firstOption = screen.getAllByRole('option')[0];
|
|
104
105
|
fireEvent.click(firstOption);
|
|
105
106
|
|
|
106
|
-
// Save the changes
|
|
107
|
+
// Save the changes.
|
|
107
108
|
fireEvent.click(screen.getByTestId('save-button'));
|
|
108
109
|
|
|
109
|
-
// Wait for the changes to propagate
|
|
110
|
+
// Wait for the changes to propagate.
|
|
110
111
|
await waitFor(() => {
|
|
111
112
|
expect(screen.getByText('added_property')).toBeInTheDocument();
|
|
112
113
|
});
|
|
@@ -114,40 +115,43 @@ describe('ViewEditor', () => {
|
|
|
114
115
|
// Access the live objects directly from window using symbol.
|
|
115
116
|
const debugObjects = getViewEditorDebugObjects();
|
|
116
117
|
|
|
117
|
-
// Check schema contains added_property
|
|
118
|
+
// Check schema contains added_property.
|
|
118
119
|
const schemaProperties = debugObjects.schema.jsonSchema.properties;
|
|
119
120
|
expect(schemaProperties).toBeDefined();
|
|
120
121
|
expect(schemaProperties!.added_property).toBeDefined();
|
|
121
122
|
|
|
122
|
-
// Check view contains added_property field
|
|
123
|
-
const addedPropertyField = debugObjects.view.fields.find(
|
|
123
|
+
// Check view contains added_property field.
|
|
124
|
+
const addedPropertyField = debugObjects.view.projection.fields.find(
|
|
125
|
+
(field: any) => field.path === 'added_property',
|
|
126
|
+
);
|
|
124
127
|
expect(addedPropertyField).toBeDefined();
|
|
125
128
|
expect(addedPropertyField!.path).toBe('added_property');
|
|
126
129
|
|
|
127
|
-
// Check projection contains added_property
|
|
130
|
+
// Check projection contains added_property.
|
|
128
131
|
const fieldProjections = debugObjects.projection.getFieldProjections();
|
|
129
132
|
const addedPropertyProjection = fieldProjections.find((proj: any) => proj.field.path === 'added_property');
|
|
130
133
|
expect(addedPropertyProjection).toBeDefined();
|
|
131
134
|
expect(addedPropertyProjection!.props.property).toBe('added_property');
|
|
132
135
|
});
|
|
133
136
|
|
|
134
|
-
|
|
137
|
+
// TODO(mykola): Fix flaky test.
|
|
138
|
+
test('delete property', { retry: 2 }, async () => {
|
|
135
139
|
await Default.run();
|
|
136
140
|
await waitForViewEditor();
|
|
137
141
|
|
|
138
|
-
// Find the delete button for the 'name' property
|
|
142
|
+
// Find the delete button for the 'name' property.
|
|
139
143
|
const nameProperty = screen.getByText('name');
|
|
140
144
|
const propertyRow = nameProperty.closest('[role="listitem"]');
|
|
141
|
-
const deleteButton = propertyRow?.querySelector('
|
|
145
|
+
const deleteButton = propertyRow?.querySelector('[data-testid="field.delete"]');
|
|
142
146
|
|
|
143
147
|
if (!deleteButton) {
|
|
144
148
|
throw new Error('Delete button not found');
|
|
145
149
|
}
|
|
146
150
|
|
|
147
|
-
// Click the delete button
|
|
151
|
+
// Click the delete button.
|
|
148
152
|
fireEvent.click(deleteButton);
|
|
149
153
|
|
|
150
|
-
// Wait for the changes to propagate
|
|
154
|
+
// Wait for the changes to propagate.
|
|
151
155
|
await waitFor(() => {
|
|
152
156
|
expect(screen.queryByText('name')).not.toBeInTheDocument();
|
|
153
157
|
});
|
|
@@ -155,16 +159,16 @@ describe('ViewEditor', () => {
|
|
|
155
159
|
// Access the live objects directly from window using symbol.
|
|
156
160
|
const debugObjects = getViewEditorDebugObjects();
|
|
157
161
|
|
|
158
|
-
// Check schema no longer contains the name property
|
|
162
|
+
// Check schema no longer contains the name property.
|
|
159
163
|
const schemaProperties = debugObjects.schema.jsonSchema.properties;
|
|
160
164
|
expect(schemaProperties).toBeDefined();
|
|
161
165
|
expect(schemaProperties!.name).toBeUndefined();
|
|
162
166
|
|
|
163
|
-
// Check view no longer contains the name field
|
|
164
|
-
const nameField = debugObjects.view.fields.find((field: any) => field.path === 'name');
|
|
167
|
+
// Check view no longer contains the name field.
|
|
168
|
+
const nameField = debugObjects.view.projection.fields.find((field: any) => field.path === 'name');
|
|
165
169
|
expect(nameField).toBeUndefined();
|
|
166
170
|
|
|
167
|
-
// Check projection no longer contains the name property
|
|
171
|
+
// Check projection no longer contains the name property.
|
|
168
172
|
const fieldProjections = debugObjects.projection.getFieldProjections();
|
|
169
173
|
const nameProjection = fieldProjections.find((proj: any) => proj.field.path === 'name');
|
|
170
174
|
expect(nameProjection).toBeUndefined();
|
|
@@ -174,11 +178,11 @@ describe('ViewEditor', () => {
|
|
|
174
178
|
await Default.run();
|
|
175
179
|
await waitForViewEditor();
|
|
176
180
|
|
|
177
|
-
// Click the first hide button
|
|
181
|
+
// Click the first hide button.
|
|
178
182
|
const hideButtons = screen.getAllByTestId('hide-field-button');
|
|
179
183
|
fireEvent.click(hideButtons[0]);
|
|
180
184
|
|
|
181
|
-
// Check that hiddenFields is non-empty
|
|
185
|
+
// Check that hiddenFields is non-empty.
|
|
182
186
|
await waitFor(() => {
|
|
183
187
|
expect(screen.getByTestId('show-field-button')).toBeInTheDocument();
|
|
184
188
|
});
|
|
@@ -186,19 +190,15 @@ describe('ViewEditor', () => {
|
|
|
186
190
|
// Access the live objects directly from window using symbol.
|
|
187
191
|
const debugObjects = getViewEditorDebugObjects();
|
|
188
192
|
|
|
189
|
-
// Check that hiddenFields is non-empty
|
|
190
|
-
expect(debugObjects.view.hiddenFields).toBeDefined();
|
|
191
|
-
expect(debugObjects.view.hiddenFields!.length).toBeGreaterThan(0);
|
|
192
|
-
|
|
193
193
|
// Click the show button
|
|
194
194
|
fireEvent.click(screen.getByTestId('show-field-button'));
|
|
195
195
|
|
|
196
|
-
// Wait for the data to update and check that hiddenFields is empty
|
|
196
|
+
// Wait for the data to update and check that hiddenFields is empty.
|
|
197
197
|
await waitFor(() => {
|
|
198
|
-
expect(debugObjects.view.
|
|
198
|
+
expect(debugObjects.view.projection.fields.filter(({ visible }) => visible === false)!.length).toBe(0);
|
|
199
199
|
});
|
|
200
200
|
|
|
201
|
-
// Also verify that the field is back in the visible fields list
|
|
202
|
-
expect(debugObjects.view.fields.length).toBeGreaterThan(0);
|
|
201
|
+
// Also verify that the field is back in the visible fields list.
|
|
202
|
+
expect(debugObjects.view.projection.fields.filter(({ visible }) => visible !== false).length).toBeGreaterThan(0);
|
|
203
203
|
});
|
|
204
|
-
});
|
|
204
|
+
}, 30_000);
|