@dxos/react-ui-form 0.8.4-main.f5c0578 → 0.8.4-main.fcc0d83b33

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 (246) hide show
  1. package/README.md +0 -1
  2. package/dist/lib/browser/index.mjs +2774 -2137
  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 +2774 -2137
  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 -8
  13. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  14. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +84 -5
  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 -25
  17. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/Form.stories.d.ts +130 -56
  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 +83 -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 -10
  89. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  90. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +86 -8
  91. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  92. package/dist/types/src/components/index.d.ts +4 -2
  93. package/dist/types/src/components/index.d.ts.map +1 -1
  94. package/dist/types/src/components/testing.d.ts +5 -4
  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 -55
  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 -46
  120. package/src/components/FieldEditor/FieldEditor.stories.tsx +49 -31
  121. package/src/components/FieldEditor/FieldEditor.test.tsx +0 -1
  122. package/src/components/FieldEditor/FieldEditor.tsx +86 -91
  123. package/src/components/Form/AUDIT.md +17 -0
  124. package/src/components/Form/Form.stories.tsx +147 -224
  125. package/src/components/Form/Form.tsx +376 -96
  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 +159 -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 +152 -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} +37 -31
  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} +17 -10
  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 +194 -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 +82 -0
  158. package/src/components/Settings/SettingsFieldSet.tsx +257 -0
  159. package/src/components/Settings/SettingsItem.tsx +62 -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 +140 -63
  163. package/src/components/ViewEditor/ViewEditor.test.tsx +12 -15
  164. package/src/components/ViewEditor/ViewEditor.tsx +348 -212
  165. package/src/components/index.ts +4 -3
  166. package/src/components/testing.tsx +31 -12
  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 -59
  172. package/src/util/field-type.ts +60 -0
  173. package/src/util/field.ts +33 -43
  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 -8
  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 -57
  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 -26
  195. package/dist/types/src/components/Form/Input.d.ts.map +0 -1
  196. package/dist/types/src/components/Form/RefField.d.ts +0 -12
  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 -7
  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/components/deprecated/Form.d.ts +0 -15
  211. package/dist/types/src/components/deprecated/Form.d.ts.map +0 -1
  212. package/dist/types/src/components/deprecated/Form.stories.d.ts +0 -13
  213. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +0 -1
  214. package/dist/types/src/components/deprecated/FormInput.d.ts +0 -16
  215. package/dist/types/src/components/deprecated/FormInput.d.ts.map +0 -1
  216. package/dist/types/src/components/deprecated/index.d.ts +0 -2
  217. package/dist/types/src/components/deprecated/index.d.ts.map +0 -1
  218. package/dist/types/src/hooks/useForm.d.ts +0 -67
  219. package/dist/types/src/hooks/useForm.d.ts.map +0 -1
  220. package/dist/types/src/hooks/useQueryRefOptions.d.ts +0 -23
  221. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +0 -1
  222. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +0 -8
  223. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +0 -1
  224. package/dist/types/src/util/schema.d.ts +0 -3
  225. package/dist/types/src/util/schema.d.ts.map +0 -1
  226. package/src/components/ControlSection/ControlSection.stories.tsx +0 -42
  227. package/src/components/ControlSection/ControlSection.tsx +0 -139
  228. package/src/components/Form/ArrayField.tsx +0 -125
  229. package/src/components/Form/Defaults.tsx +0 -204
  230. package/src/components/Form/FormActions.tsx +0 -54
  231. package/src/components/Form/FormContent.tsx +0 -241
  232. package/src/components/Form/FormContext.tsx +0 -110
  233. package/src/components/Form/Input.tsx +0 -51
  234. package/src/components/Form/RefField.tsx +0 -214
  235. package/src/components/Form/custom/GeoPointInput.tsx +0 -72
  236. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +0 -62
  237. package/src/components/Form/custom/index.ts +0 -7
  238. package/src/components/Form/factory.tsx +0 -31
  239. package/src/components/deprecated/Form.stories.tsx +0 -63
  240. package/src/components/deprecated/Form.tsx +0 -119
  241. package/src/components/deprecated/FormInput.tsx +0 -71
  242. package/src/components/deprecated/index.ts +0 -5
  243. package/src/hooks/useForm.ts +0 -293
  244. package/src/hooks/useQueryRefOptions.ts +0 -53
  245. package/src/hooks/useRefQueryLookupHandler.ts +0 -39
  246. package/src/util/schema.ts +0 -14
@@ -2,126 +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 { Schema } from 'effect';
9
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
10
-
11
- import { Obj, Type } from '@dxos/echo';
12
- import { type EchoSchema, Format, TypedObject, toJsonSchema } from '@dxos/echo-schema';
13
- import { Filter, useQuery, 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 { DataType, ProjectionModel, createView } from '@dxos/schema';
17
- 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';
18
18
 
19
- import { translations } from '../../translations';
20
- import { TestLayout, TestPanel, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
19
+ import { translations } from '#translations';
21
20
 
21
+ import { TestLayout, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
22
22
  import { ViewEditor, type ViewEditorProps } from './ViewEditor';
23
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
+
24
32
  // Type definition for debug objects exposed to tests.
25
33
  export type ViewEditorDebugObjects = {
26
34
  schema: EchoSchema;
27
- view: DataType.View;
35
+ view: View.View;
28
36
  projection: ProjectionModel;
29
37
  };
30
38
 
31
- type StoryProps = Pick<ViewEditorProps, 'readonly'>;
39
+ type DefaultStoryProps = Pick<ViewEditorProps, 'readonly' | 'mode'>;
32
40
 
33
- const DefaultStory = (props: StoryProps) => {
34
- const space = useSpace();
41
+ const DefaultStory = (props: DefaultStoryProps) => {
42
+ const { space } = useClientStory();
35
43
  const [schema, setSchema] = useState<EchoSchema>();
36
- const [view, setView] = useState<DataType.View>();
37
- 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
+
38
49
  useAsyncEffect(async () => {
39
50
  if (space) {
40
- class TestSchema extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
51
+ const TestSchema = Schema.Struct({
41
52
  name: Schema.String,
42
53
  email: Format.Email,
43
54
  salary: Format.Currency(),
44
- }) {}
45
-
46
- const [schema] = await space.db.schemaRegistry.register([TestSchema]);
47
- 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({
48
75
  name: 'Test',
49
- typename: schema.typename,
50
- jsonSchema: toJsonSchema(TestSchema),
51
- presentation: Obj.make(Type.Expando, {}),
76
+ query: Query.select(Filter.type(TestSchema)),
77
+ jsonSchema: JsonSchema.toJsonSchema(TestSchema),
52
78
  });
53
- const projection = new ProjectionModel(schema.jsonSchema, view.projection);
54
79
 
55
- setSchema(schema);
80
+ setSchema(testSchema);
56
81
  setView(view);
57
- setProjection(projection);
58
82
  }
59
83
  }, [space]);
60
84
 
61
- const views = useQuery(space, Filter.type(DataType.View));
62
- const currentTypename = useMemo(() => view?.query?.typename, [view]);
63
- const updateViewTypename = useCallback(
64
- (newTypename: string) => {
65
- if (!schema) {
85
+ const updateViewQuery = useCallback(
86
+ async (newQuery: QueryAST.Query, target?: string) => {
87
+ if (!schema || !view || !space) {
66
88
  return;
67
89
  }
68
- const matchingViews = views.filter((view) => view.query.typename === currentTypename);
69
- for (const view of matchingViews) {
70
- view.query.typename = newTypename;
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));
71
117
  }
72
- schema.updateTypename(newTypename);
73
118
  },
74
- [views, schema],
119
+ [view, schema],
75
120
  );
76
121
 
77
- const handleDelete = useCallback((property: string) => projection?.deleteFieldProjection(property), [projection]);
122
+ const handleDelete = useCallback(
123
+ (property: string) => projectionRef.current?.deleteFieldProjection(property),
124
+ [projectionRef],
125
+ );
78
126
 
79
127
  // Expose objects on window for test access.
80
128
  useEffect(() => {
81
- if (typeof window !== 'undefined' && schema && view && projection) {
82
- (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;
83
135
  }
84
- }, [schema, view, projection]);
136
+ }, [schema, view]);
85
137
 
86
138
  // NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
87
139
  const json = useMemo(
88
- () => JSON.parse(JSON.stringify({ schema, view, projection })),
89
- [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)],
90
142
  );
91
143
 
92
- if (!schema || !view || !projection) {
144
+ if (!schema || !view) {
93
145
  return <div />;
94
146
  }
95
147
 
96
148
  return (
97
149
  <TestLayout json={json}>
98
- <TestPanel>
99
- <ViewEditor
100
- schema={schema}
101
- view={view}
102
- registry={space?.db.schemaRegistry}
103
- readonly={props.readonly}
104
- onTypenameChanged={updateViewTypename}
105
- onDelete={handleDelete}
106
- />
107
- </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
+ />
108
162
  </TestLayout>
109
163
  );
110
164
  };
111
165
 
112
- const meta: Meta<StoryProps> = {
166
+ const meta = {
113
167
  title: 'ui/react-ui-form/ViewEditor',
114
168
  render: DefaultStory,
115
- decorators: [withClientProvider({ createSpace: true }), withLayout({ fullscreen: true }), withTheme],
116
- parameters: { translations },
117
- };
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>;
118
187
 
119
188
  export default meta;
120
189
 
121
- type Story = StoryObj<StoryProps>;
190
+ type Story = StoryObj<typeof meta>;
122
191
 
123
192
  export const Default: Story = {};
124
193
 
125
194
  export const Readonly: Story = {
126
- args: { readonly: true },
195
+ args: {
196
+ readonly: true,
197
+ },
198
+ };
199
+
200
+ export const TagQueryMode: Story = {
201
+ args: {
202
+ mode: 'tag',
203
+ },
127
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
 
@@ -189,19 +190,15 @@ describe('ViewEditor', () => {
189
190
  // Access the live objects directly from window using symbol.
190
191
  const debugObjects = getViewEditorDebugObjects();
191
192
 
192
- // Check that hiddenFields is non-empty.
193
- expect(debugObjects.view.projection.hiddenFields).toBeDefined();
194
- expect(debugObjects.view.projection.hiddenFields!.length).toBeGreaterThan(0);
195
-
196
193
  // Click the show button
197
194
  fireEvent.click(screen.getByTestId('show-field-button'));
198
195
 
199
196
  // Wait for the data to update and check that hiddenFields is empty.
200
197
  await waitFor(() => {
201
- expect(debugObjects.view.projection.hiddenFields!.length).toBe(0);
198
+ expect(debugObjects.view.projection.fields.filter(({ visible }) => visible === false)!.length).toBe(0);
202
199
  });
203
200
 
204
201
  // Also verify that the field is back in the visible fields list.
205
- expect(debugObjects.view.projection.fields.length).toBeGreaterThan(0);
202
+ expect(debugObjects.view.projection.fields.filter(({ visible }) => visible !== false).length).toBeGreaterThan(0);
206
203
  });
207
- });
204
+ }, 30_000);