@dxos/react-ui-form 0.8.4-main.dedc0f3 → 0.8.4-main.dfabb4ec29

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.
Files changed (234) hide show
  1. package/README.md +0 -1
  2. package/dist/lib/browser/index.mjs +2772 -2208
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/translations.mjs +82 -0
  6. package/dist/lib/browser/translations.mjs.map +7 -0
  7. package/dist/lib/node-esm/index.mjs +2772 -2208
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/lib/node-esm/translations.mjs +84 -0
  11. package/dist/lib/node-esm/translations.mjs.map +7 -0
  12. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +8 -7
  13. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  14. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +69 -60
  15. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Form.d.ts +109 -26
  17. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/Form.stories.d.ts +116 -138
  19. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormField.d.ts +43 -0
  21. package/dist/types/src/components/Form/FormField.d.ts.map +1 -0
  22. package/dist/types/src/components/Form/FormFieldComponent.d.ts +79 -0
  23. package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +1 -0
  24. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts +9 -0
  25. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/Form/FormFieldSet.d.ts +15 -0
  27. package/dist/types/src/components/Form/FormFieldSet.d.ts.map +1 -0
  28. package/dist/types/src/components/Form/fields/ArrayField.d.ts +18 -0
  29. package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +1 -0
  30. package/dist/types/src/components/Form/fields/BooleanField.d.ts +4 -0
  31. package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +1 -0
  32. package/dist/types/src/components/Form/fields/GeoPointField.d.ts +5 -0
  33. package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +1 -0
  34. package/dist/types/src/components/Form/fields/MarkdownField.d.ts +11 -0
  35. package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -0
  36. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts +84 -0
  37. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts.map +1 -0
  38. package/dist/types/src/components/Form/fields/NumberField.d.ts +4 -0
  39. package/dist/types/src/components/Form/fields/NumberField.d.ts.map +1 -0
  40. package/dist/types/src/components/Form/fields/RefField.d.ts +22 -0
  41. package/dist/types/src/components/Form/fields/RefField.d.ts.map +1 -0
  42. package/dist/types/src/components/Form/fields/SelectField.d.ts +10 -0
  43. package/dist/types/src/components/Form/fields/SelectField.d.ts.map +1 -0
  44. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +5 -0
  45. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +1 -0
  46. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts +84 -0
  47. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +1 -0
  48. package/dist/types/src/components/Form/fields/TextAreaField.d.ts +4 -0
  49. package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +1 -0
  50. package/dist/types/src/components/Form/fields/TextField.d.ts +4 -0
  51. package/dist/types/src/components/Form/fields/TextField.d.ts.map +1 -0
  52. package/dist/types/src/components/Form/fields/TupleField.d.ts +6 -0
  53. package/dist/types/src/components/Form/fields/TupleField.d.ts.map +1 -0
  54. package/dist/types/src/components/Form/fields/index.d.ts +12 -0
  55. package/dist/types/src/components/Form/fields/index.d.ts.map +1 -0
  56. package/dist/types/src/components/Form/index.d.ts +2 -4
  57. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  58. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts +9 -0
  59. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -0
  60. package/dist/types/src/components/ObjectForm/index.d.ts +2 -0
  61. package/dist/types/src/components/ObjectForm/index.d.ts.map +1 -0
  62. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +68 -0
  63. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
  64. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +87 -0
  65. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
  66. package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
  67. package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
  68. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts +9 -0
  69. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -0
  70. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts +127 -0
  71. package/dist/types/src/components/ObjectProperties/ObjectProperties.stories.d.ts.map +1 -0
  72. package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts +2 -0
  73. package/dist/types/src/components/ObjectProperties/ObjectProperties.test.d.ts.map +1 -0
  74. package/dist/types/src/components/ObjectProperties/index.d.ts +2 -0
  75. package/dist/types/src/components/ObjectProperties/index.d.ts.map +1 -0
  76. package/dist/types/src/components/Settings/Settings.d.ts +51 -0
  77. package/dist/types/src/components/Settings/Settings.d.ts.map +1 -0
  78. package/dist/types/src/components/Settings/Settings.stories.d.ts +84 -0
  79. package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -0
  80. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +43 -0
  81. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +1 -0
  82. package/dist/types/src/components/Settings/SettingsItem.d.ts +16 -0
  83. package/dist/types/src/components/Settings/SettingsItem.d.ts.map +1 -0
  84. package/dist/types/src/components/Settings/SettingsSelectField.d.ts +18 -0
  85. package/dist/types/src/components/Settings/SettingsSelectField.d.ts.map +1 -0
  86. package/dist/types/src/components/Settings/index.d.ts +4 -0
  87. package/dist/types/src/components/Settings/index.d.ts.map +1 -0
  88. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +22 -11
  89. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  90. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +72 -65
  91. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  92. package/dist/types/src/components/index.d.ts +4 -1
  93. package/dist/types/src/components/index.d.ts.map +1 -1
  94. package/dist/types/src/components/testing.d.ts +4 -6
  95. package/dist/types/src/components/testing.d.ts.map +1 -1
  96. package/dist/types/src/hooks/index.d.ts +2 -3
  97. package/dist/types/src/hooks/index.d.ts.map +1 -1
  98. package/dist/types/src/hooks/useFormHandler.d.ts +82 -0
  99. package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -0
  100. package/dist/types/src/hooks/useKeyHandler.d.ts +7 -0
  101. package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -0
  102. package/dist/types/src/index.d.ts +0 -2
  103. package/dist/types/src/index.d.ts.map +1 -1
  104. package/dist/types/src/translations.d.ts +65 -59
  105. package/dist/types/src/translations.d.ts.map +1 -1
  106. package/dist/types/src/util/field-type.d.ts +19 -0
  107. package/dist/types/src/util/field-type.d.ts.map +1 -0
  108. package/dist/types/src/util/field.d.ts +3 -3
  109. package/dist/types/src/util/field.d.ts.map +1 -1
  110. package/dist/types/src/util/formatting.d.ts +2 -2
  111. package/dist/types/src/util/formatting.d.ts.map +1 -1
  112. package/dist/types/src/util/index.d.ts +2 -1
  113. package/dist/types/src/util/index.d.ts.map +1 -1
  114. package/dist/types/src/util/properties.d.ts +7 -0
  115. package/dist/types/src/util/properties.d.ts.map +1 -0
  116. package/dist/types/src/util/refs.d.ts +3 -3
  117. package/dist/types/src/util/refs.d.ts.map +1 -1
  118. package/dist/types/tsconfig.tsbuildinfo +1 -1
  119. package/package.json +56 -50
  120. package/src/components/FieldEditor/FieldEditor.stories.tsx +46 -26
  121. package/src/components/FieldEditor/FieldEditor.test.tsx +0 -1
  122. package/src/components/FieldEditor/FieldEditor.tsx +80 -80
  123. package/src/components/Form/AUDIT.md +17 -0
  124. package/src/components/Form/Form.stories.tsx +142 -254
  125. package/src/components/Form/Form.tsx +375 -99
  126. package/src/components/Form/FormField.tsx +306 -0
  127. package/src/components/Form/FormFieldComponent.stories.tsx +65 -0
  128. package/src/components/Form/FormFieldComponent.tsx +174 -0
  129. package/src/components/Form/FormFieldSet.tsx +144 -0
  130. package/src/components/Form/README.md +3 -0
  131. package/src/components/Form/fields/ArrayField.tsx +155 -0
  132. package/src/components/Form/fields/BooleanField.tsx +22 -0
  133. package/src/components/Form/fields/GeoPointField.tsx +121 -0
  134. package/src/components/Form/fields/MarkdownField.stories.tsx +206 -0
  135. package/src/components/Form/fields/MarkdownField.tsx +168 -0
  136. package/src/components/Form/fields/NumberField.tsx +39 -0
  137. package/src/components/Form/fields/RefField.tsx +229 -0
  138. package/src/components/Form/fields/SelectField.tsx +65 -0
  139. package/src/components/Form/fields/SelectOptionField.stories.tsx +66 -0
  140. package/src/components/Form/{custom/SelectOptionsInput.tsx → fields/SelectOptionField.tsx} +31 -25
  141. package/src/components/Form/fields/TextAreaField.tsx +38 -0
  142. package/src/components/Form/fields/TextField.tsx +38 -0
  143. package/src/components/Form/{custom/TupleInput.tsx → fields/TupleField.tsx} +16 -9
  144. package/src/components/Form/fields/index.ts +15 -0
  145. package/src/components/Form/index.ts +3 -4
  146. package/src/components/ObjectForm/ObjectForm.tsx +114 -0
  147. package/src/components/{ControlSection → ObjectForm}/index.ts +1 -1
  148. package/src/components/ObjectPicker/ObjectPicker.stories.tsx +212 -0
  149. package/src/components/ObjectPicker/ObjectPicker.tsx +202 -0
  150. package/src/components/ObjectPicker/index.ts +5 -0
  151. package/src/components/ObjectProperties/ObjectProperties.stories.tsx +362 -0
  152. package/src/components/ObjectProperties/ObjectProperties.test.tsx +101 -0
  153. package/src/components/ObjectProperties/ObjectProperties.tsx +141 -0
  154. package/src/components/ObjectProperties/index.ts +5 -0
  155. package/src/components/Settings/AUDIT.md +52 -0
  156. package/src/components/Settings/Settings.stories.tsx +104 -0
  157. package/src/components/Settings/Settings.tsx +80 -0
  158. package/src/components/Settings/SettingsFieldSet.tsx +257 -0
  159. package/src/components/Settings/SettingsItem.tsx +58 -0
  160. package/src/components/Settings/SettingsSelectField.tsx +59 -0
  161. package/src/components/Settings/index.ts +7 -0
  162. package/src/components/ViewEditor/ViewEditor.stories.tsx +126 -75
  163. package/src/components/ViewEditor/ViewEditor.test.tsx +10 -9
  164. package/src/components/ViewEditor/ViewEditor.tsx +326 -195
  165. package/src/components/index.ts +4 -1
  166. package/src/components/testing.tsx +24 -11
  167. package/src/hooks/index.ts +2 -3
  168. package/src/hooks/useFormHandler.ts +380 -0
  169. package/src/hooks/useKeyHandler.tsx +37 -0
  170. package/src/index.ts +0 -4
  171. package/src/translations.ts +70 -64
  172. package/src/util/field-type.ts +60 -0
  173. package/src/util/field.ts +25 -25
  174. package/src/util/formatting.ts +22 -22
  175. package/src/util/index.ts +2 -1
  176. package/src/util/properties.ts +18 -0
  177. package/src/util/refs.ts +17 -19
  178. package/dist/types/src/components/ControlSection/ControlSection.d.ts +0 -23
  179. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +0 -1
  180. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +0 -83
  181. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +0 -1
  182. package/dist/types/src/components/ControlSection/index.d.ts +0 -2
  183. package/dist/types/src/components/ControlSection/index.d.ts.map +0 -1
  184. package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
  185. package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
  186. package/dist/types/src/components/Form/Defaults.d.ts +0 -14
  187. package/dist/types/src/components/Form/Defaults.d.ts.map +0 -1
  188. package/dist/types/src/components/Form/FormActions.d.ts +0 -9
  189. package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
  190. package/dist/types/src/components/Form/FormContent.d.ts +0 -63
  191. package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
  192. package/dist/types/src/components/Form/FormContext.d.ts +0 -23
  193. package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
  194. package/dist/types/src/components/Form/Input.d.ts +0 -29
  195. package/dist/types/src/components/Form/Input.d.ts.map +0 -1
  196. package/dist/types/src/components/Form/RefField.d.ts +0 -18
  197. package/dist/types/src/components/Form/RefField.d.ts.map +0 -1
  198. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +0 -4
  199. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +0 -1
  200. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +0 -4
  201. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +0 -1
  202. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +0 -78
  203. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +0 -1
  204. package/dist/types/src/components/Form/custom/TupleInput.d.ts +0 -6
  205. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +0 -1
  206. package/dist/types/src/components/Form/custom/index.d.ts +0 -4
  207. package/dist/types/src/components/Form/custom/index.d.ts.map +0 -1
  208. package/dist/types/src/components/Form/factory.d.ts +0 -8
  209. package/dist/types/src/components/Form/factory.d.ts.map +0 -1
  210. package/dist/types/src/hooks/useForm.d.ts +0 -67
  211. package/dist/types/src/hooks/useForm.d.ts.map +0 -1
  212. package/dist/types/src/hooks/useQueryRefOptions.d.ts +0 -23
  213. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +0 -1
  214. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +0 -8
  215. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +0 -1
  216. package/dist/types/src/util/schema.d.ts +0 -3
  217. package/dist/types/src/util/schema.d.ts.map +0 -1
  218. package/src/components/ControlSection/ControlSection.stories.tsx +0 -39
  219. package/src/components/ControlSection/ControlSection.tsx +0 -153
  220. package/src/components/Form/ArrayField.tsx +0 -124
  221. package/src/components/Form/Defaults.tsx +0 -205
  222. package/src/components/Form/FormActions.tsx +0 -54
  223. package/src/components/Form/FormContent.tsx +0 -302
  224. package/src/components/Form/FormContext.tsx +0 -110
  225. package/src/components/Form/Input.tsx +0 -54
  226. package/src/components/Form/RefField.tsx +0 -299
  227. package/src/components/Form/custom/GeoPointInput.tsx +0 -80
  228. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +0 -62
  229. package/src/components/Form/custom/index.ts +0 -7
  230. package/src/components/Form/factory.tsx +0 -31
  231. package/src/hooks/useForm.ts +0 -293
  232. package/src/hooks/useQueryRefOptions.ts +0 -53
  233. package/src/hooks/useRefQueryLookupHandler.ts +0 -39
  234. package/src/util/schema.ts +0 -14
@@ -2,123 +2,163 @@
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 { Schema } from 'effect';
9
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
10
-
11
- import { Filter, Obj, Query, Type } from '@dxos/echo';
12
- import { type EchoSchema, Format, TypedObject, toJsonSchema } from '@dxos/echo-schema';
13
- import { useSpace } from '@dxos/react-client/echo';
14
- import { withClientProvider } from '@dxos/react-client/testing';
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 { QueryParser, createFilter } from '@dxos/react-ui-components';
17
- import { type DataType, ProjectionModel, createView, typenameFromQuery } from '@dxos/schema';
18
- import { withLayout, withTheme } from '@dxos/storybook-utils';
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';
19
18
 
20
- import { translations } from '../../translations';
21
- import { TestLayout, TestPanel, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
19
+ import { translations } from '#translations';
22
20
 
21
+ import { TestLayout, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
23
22
  import { ViewEditor, type ViewEditorProps } from './ViewEditor';
24
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
+ ];
31
+
25
32
  // Type definition for debug objects exposed to tests.
26
33
  export type ViewEditorDebugObjects = {
27
34
  schema: EchoSchema;
28
- view: DataType.View;
35
+ view: View.View;
29
36
  projection: ProjectionModel;
30
37
  };
31
38
 
32
- type StoryProps = Pick<ViewEditorProps, 'readonly' | 'kind'>;
39
+ type DefaultStoryProps = Pick<ViewEditorProps, 'readonly' | 'mode'>;
33
40
 
34
- const DefaultStory = (props: StoryProps) => {
35
- const space = useSpace();
41
+ const DefaultStory = (props: DefaultStoryProps) => {
42
+ const { space } = useClientStory();
36
43
  const [schema, setSchema] = useState<EchoSchema>();
37
- const [view, setView] = useState<DataType.View>();
38
- const [projection, setProjection] = useState<ProjectionModel>();
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
+
39
49
  useAsyncEffect(async () => {
40
50
  if (space) {
41
- class TestSchema extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
51
+ const TestSchema = Schema.Struct({
42
52
  name: Schema.String,
43
53
  email: Format.Email,
44
54
  salary: Format.Currency(),
45
- }) {}
46
-
47
- const [schema] = await space.db.schemaRegistry.register([TestSchema]);
48
- const view = createView({
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({
49
75
  name: 'Test',
50
- typename: schema.typename,
51
- jsonSchema: toJsonSchema(TestSchema),
52
- presentation: Obj.make(Type.Expando, {}),
76
+ query: Query.select(Filter.type(TestSchema)),
77
+ jsonSchema: JsonSchema.toJsonSchema(TestSchema),
53
78
  });
54
- const projection = new ProjectionModel(schema.jsonSchema, view.projection);
55
79
 
56
- setSchema(schema);
80
+ setSchema(testSchema);
57
81
  setView(view);
58
- setProjection(projection);
59
82
  }
60
83
  }, [space]);
61
84
 
62
85
  const updateViewQuery = useCallback(
63
- (newQueryString: string) => {
64
- if (!schema || !view) {
86
+ async (newQuery: QueryAST.Query, target?: string) => {
87
+ if (!schema || !view || !space) {
65
88
  return;
66
89
  }
67
90
 
68
- if (props.kind === 'advanced') {
69
- try {
70
- const parser = new QueryParser(newQueryString);
71
- // TODO(wittjosiah): When this fails it should show validation errors in the UI.
72
- const newQuery = Query.select(createFilter(parser.parse()));
73
- view.query = newQuery.ast;
74
-
75
- const typename = typenameFromQuery(newQuery.ast);
76
- if (typename) {
77
- schema.updateTypename(typename);
78
- }
79
- } catch {}
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);
80
112
  } else {
81
- const typename = newQueryString;
82
- const newQuery = Query.select(Filter.typename(typename));
83
- view.query = newQuery.ast;
84
- schema.updateTypename(typename);
113
+ Obj.update(view, (view) => {
114
+ view.query.ast = newQuery as Mutable<typeof newQuery>;
115
+ });
116
+ schema.updateTypename(getTypenameFromQuery(newQuery));
85
117
  }
86
118
  },
87
119
  [view, schema],
88
120
  );
89
121
 
90
- const handleDelete = useCallback((property: string) => projection?.deleteFieldProjection(property), [projection]);
122
+ const handleDelete = useCallback(
123
+ (property: string) => projectionRef.current?.deleteFieldProjection(property),
124
+ [projectionRef],
125
+ );
91
126
 
92
127
  // Expose objects on window for test access.
93
128
  useEffect(() => {
94
- if (typeof window !== 'undefined' && schema && view && projection) {
95
- (window as any)[VIEW_EDITOR_DEBUG_SYMBOL] = { schema, view, projection } satisfies ViewEditorDebugObjects;
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;
96
135
  }
97
- }, [schema, view, projection]);
136
+ }, [schema, view]);
98
137
 
99
138
  // NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
100
139
  const json = useMemo(
101
- () => JSON.parse(JSON.stringify({ schema, view, projection })),
102
- [JSON.stringify(schema), JSON.stringify(view), JSON.stringify(projection)],
140
+ () => JSON.parse(JSON.stringify({ schema, view, projection: projectionRef.current })),
141
+ [JSON.stringify(schema), JSON.stringify(view)],
103
142
  );
104
143
 
105
- if (!schema || !view || !projection) {
144
+ if (!schema || !view) {
106
145
  return <div />;
107
146
  }
108
147
 
109
148
  return (
110
149
  <TestLayout json={json}>
111
- <TestPanel>
112
- <ViewEditor
113
- schema={schema}
114
- view={view}
115
- registry={space?.db.schemaRegistry}
116
- kind={props.kind}
117
- readonly={props.readonly}
118
- onQueryChanged={updateViewQuery}
119
- onDelete={handleDelete}
120
- />
121
- </TestPanel>
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
+ />
122
162
  </TestLayout>
123
163
  );
124
164
  };
@@ -129,13 +169,20 @@ const meta = {
129
169
  decorators: [
130
170
  withClientProvider({
131
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
+ },
132
178
  }),
133
- withLayout({
134
- fullscreen: true,
135
- }),
136
- withTheme,
179
+ withTheme(),
180
+ withLayout({ layout: 'fullscreen' }),
137
181
  ],
138
- parameters: { translations },
182
+ parameters: {
183
+ layout: 'fullscreen',
184
+ translations,
185
+ },
139
186
  } satisfies Meta<typeof DefaultStory>;
140
187
 
141
188
  export default meta;
@@ -145,9 +192,13 @@ type Story = StoryObj<typeof meta>;
145
192
  export const Default: Story = {};
146
193
 
147
194
  export const Readonly: Story = {
148
- args: { readonly: true },
195
+ args: {
196
+ readonly: true,
197
+ },
149
198
  };
150
199
 
151
- export const Advanced: Story = {
152
- args: { kind: 'advanced' },
200
+ export const TagQueryMode: Story = {
201
+ args: {
202
+ mode: 'tag',
203
+ },
153
204
  };
@@ -6,11 +6,11 @@ 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-schema';
10
- import { DataType, ProjectionModel } from '@dxos/schema';
9
+ import { View } from '@dxos/echo';
10
+ import { EchoSchema, isInstanceOf } from '@dxos/echo/internal';
11
+ import { ProjectionModel } from '@dxos/schema';
11
12
 
12
13
  import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
13
-
14
14
  import * as stories from './ViewEditor.stories';
15
15
  import { type ViewEditorDebugObjects } from './ViewEditor.stories';
16
16
 
@@ -20,7 +20,7 @@ const getViewEditorDebugObjects = (): ViewEditorDebugObjects => {
20
20
  const debugObjects = (window as any)[VIEW_EDITOR_DEBUG_SYMBOL] as ViewEditorDebugObjects;
21
21
  expect(debugObjects).toBeDefined();
22
22
  expect(debugObjects.schema).toBeInstanceOf(EchoSchema);
23
- expect(isInstanceOf(DataType.View, debugObjects.view)).toBeTruthy();
23
+ expect(isInstanceOf(View.View, debugObjects.view)).toBeTruthy();
24
24
  expect(debugObjects.projection).toBeInstanceOf(ProjectionModel);
25
25
  return debugObjects;
26
26
  };
@@ -54,7 +54,7 @@ describe('ViewEditor', () => {
54
54
  const nameField = screen.getByText('name');
55
55
  fireEvent.click(nameField);
56
56
 
57
- const fieldInput = screen.getByPlaceholderText('Field name.');
57
+ const fieldInput = screen.getByPlaceholderText('Property name');
58
58
  fireEvent.change(fieldInput, { target: { value: 'new_property' } });
59
59
 
60
60
  fireEvent.click(screen.getByTestId('save-button'));
@@ -89,12 +89,12 @@ describe('ViewEditor', () => {
89
89
  await Default.run();
90
90
  await waitForViewEditor();
91
91
 
92
- // Click the add property button.
92
+ // Click the add property button. The new field is auto-expanded by handleAdd.
93
93
  const addButton = screen.getByText('Add property');
94
94
  fireEvent.click(addButton);
95
95
 
96
96
  // Fill out the property field.
97
- const fieldInput = screen.getByPlaceholderText('Field name.');
97
+ const fieldInput = screen.getByPlaceholderText('Property name');
98
98
  fireEvent.change(fieldInput, { target: { value: 'added_property' } });
99
99
 
100
100
  // Click the format combo box and select the first option.
@@ -134,7 +134,8 @@ describe('ViewEditor', () => {
134
134
  expect(addedPropertyProjection!.props.property).toBe('added_property');
135
135
  });
136
136
 
137
- test('delete property', async () => {
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);