@dxos/plugin-space 0.7.5-feature-compute.4d9d99a → 0.7.5-labs.401163d

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 (184) hide show
  1. package/dist/lib/browser/{app-graph-builder-5D2QB43K.mjs → app-graph-builder-GSS3V7IN.mjs} +15 -13
  2. package/dist/lib/browser/app-graph-builder-GSS3V7IN.mjs.map +7 -0
  3. package/dist/lib/browser/{app-graph-serializer-VNWPLPDF.mjs → app-graph-serializer-QDXM5M6K.mjs} +5 -5
  4. package/dist/lib/browser/{chunk-6SWQRWOD.mjs → chunk-DIBLC24B.mjs} +308 -251
  5. package/dist/lib/browser/chunk-DIBLC24B.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-SOXNANA6.mjs → chunk-PQXZCNAU.mjs} +3 -2
  7. package/dist/lib/browser/{chunk-SOXNANA6.mjs.map → chunk-PQXZCNAU.mjs.map} +3 -3
  8. package/dist/lib/browser/{chunk-UH5P4UL3.mjs → chunk-RLZQJD47.mjs} +3 -2
  9. package/dist/lib/browser/chunk-RLZQJD47.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-5TBRONF6.mjs → chunk-SDK7RZI3.mjs} +3 -3
  11. package/dist/lib/browser/{chunk-HCXWKGTE.mjs → chunk-XPZ6IIXF.mjs} +4 -9
  12. package/dist/lib/browser/chunk-XPZ6IIXF.mjs.map +7 -0
  13. package/dist/lib/browser/{chunk-ZBKFJNHH.mjs → chunk-ZL5ZFGBK.mjs} +15 -9
  14. package/dist/lib/browser/chunk-ZL5ZFGBK.mjs.map +7 -0
  15. package/dist/lib/browser/{identity-created-EC5FOCX2.mjs → identity-created-25TK5XNO.mjs} +3 -3
  16. package/dist/lib/browser/index.mjs +14 -13
  17. package/dist/lib/browser/index.mjs.map +3 -3
  18. package/dist/lib/browser/intent-resolver-LNTCXZ57.mjs +537 -0
  19. package/dist/lib/browser/intent-resolver-LNTCXZ57.mjs.map +7 -0
  20. package/dist/lib/browser/meta.json +1 -1
  21. package/dist/lib/browser/{react-root-AZJFNTKK.mjs → react-root-Q7JJDCPB.mjs} +6 -6
  22. package/dist/lib/browser/{react-surface-E2VSYVNZ.mjs → react-surface-BDMYLARO.mjs} +26 -33
  23. package/dist/lib/browser/react-surface-BDMYLARO.mjs.map +7 -0
  24. package/dist/lib/browser/{settings-ASFF5BZL.mjs → settings-K4JPYYEM.mjs} +3 -3
  25. package/dist/lib/browser/{spaces-ready-4SFNS5JQ.mjs → spaces-ready-THYJEJYZ.mjs} +31 -32
  26. package/dist/lib/browser/spaces-ready-THYJEJYZ.mjs.map +7 -0
  27. package/dist/lib/browser/{state-MS4KYJWI.mjs → state-6DCY5YJP.mjs} +3 -3
  28. package/dist/lib/browser/types/index.mjs +2 -4
  29. package/dist/lib/node/{app-graph-builder-ZQ5S62YR.cjs → app-graph-builder-V3RCGDV7.cjs} +60 -58
  30. package/dist/lib/node/app-graph-builder-V3RCGDV7.cjs.map +7 -0
  31. package/dist/lib/node/{app-graph-serializer-72S7P33H.cjs → app-graph-serializer-H4UACG57.cjs} +21 -21
  32. package/dist/lib/node/{chunk-M64YG2FY.cjs → chunk-4AZ2DD4G.cjs} +308 -251
  33. package/dist/lib/node/chunk-4AZ2DD4G.cjs.map +7 -0
  34. package/dist/lib/node/{chunk-DDZYVNVP.cjs → chunk-6MEOP3DH.cjs} +8 -14
  35. package/dist/lib/node/chunk-6MEOP3DH.cjs.map +7 -0
  36. package/dist/lib/node/{chunk-BQRNTKSQ.cjs → chunk-D6BFKOXY.cjs} +8 -8
  37. package/dist/lib/node/{chunk-Z34MTEU7.cjs → chunk-SYVPVU3K.cjs} +66 -60
  38. package/dist/lib/node/chunk-SYVPVU3K.cjs.map +7 -0
  39. package/dist/lib/node/{chunk-56NGXG2A.cjs → chunk-UX3U4RU2.cjs} +9 -8
  40. package/dist/lib/node/chunk-UX3U4RU2.cjs.map +7 -0
  41. package/dist/lib/node/{chunk-AO4EW2RX.cjs → chunk-WZR6OAN3.cjs} +6 -5
  42. package/dist/lib/node/{chunk-AO4EW2RX.cjs.map → chunk-WZR6OAN3.cjs.map} +3 -3
  43. package/dist/lib/node/{identity-created-IMDS4A6A.cjs → identity-created-7G5U7R36.cjs} +7 -7
  44. package/dist/lib/node/index.cjs +93 -92
  45. package/dist/lib/node/index.cjs.map +3 -3
  46. package/dist/lib/node/intent-resolver-CDE4M3TW.cjs +536 -0
  47. package/dist/lib/node/intent-resolver-CDE4M3TW.cjs.map +7 -0
  48. package/dist/lib/node/meta.json +1 -1
  49. package/dist/lib/node/{react-root-RB3OM3QG.cjs → react-root-JN6AIHMS.cjs} +12 -12
  50. package/dist/lib/node/{react-surface-TLKQEHHT.cjs → react-surface-XSK2QEQV.cjs} +72 -76
  51. package/dist/lib/node/react-surface-XSK2QEQV.cjs.map +7 -0
  52. package/dist/lib/node/{settings-QLCKAUHK.cjs → settings-TEELGWS4.cjs} +8 -8
  53. package/dist/lib/node/{spaces-ready-RZTKEXOL.cjs → spaces-ready-L4MJTFQ6.cjs} +39 -40
  54. package/dist/lib/node/spaces-ready-L4MJTFQ6.cjs.map +7 -0
  55. package/dist/lib/node/{state-4UIOUKLJ.cjs → state-WPZC4JXB.cjs} +8 -8
  56. package/dist/lib/node/types/index.cjs +16 -18
  57. package/dist/lib/node/types/index.cjs.map +2 -2
  58. package/dist/lib/node-esm/{app-graph-builder-CD6IYPSS.mjs → app-graph-builder-VFHK7OQI.mjs} +15 -13
  59. package/dist/lib/node-esm/app-graph-builder-VFHK7OQI.mjs.map +7 -0
  60. package/dist/lib/node-esm/{app-graph-serializer-CFXS6ZE2.mjs → app-graph-serializer-PIPJVXYZ.mjs} +5 -5
  61. package/dist/lib/node-esm/{chunk-M4XTHK35.mjs → chunk-4UX5WGKJ.mjs} +3 -3
  62. package/dist/lib/node-esm/{chunk-CLGCKZ2D.mjs → chunk-AAQRELDK.mjs} +4 -9
  63. package/dist/lib/node-esm/chunk-AAQRELDK.mjs.map +7 -0
  64. package/dist/lib/node-esm/{chunk-CMKML5IN.mjs → chunk-FTVEA5LO.mjs} +308 -251
  65. package/dist/lib/node-esm/chunk-FTVEA5LO.mjs.map +7 -0
  66. package/dist/lib/node-esm/{chunk-7FUVU45N.mjs → chunk-ICCM4YRJ.mjs} +3 -2
  67. package/dist/lib/node-esm/{chunk-7FUVU45N.mjs.map → chunk-ICCM4YRJ.mjs.map} +3 -3
  68. package/dist/lib/node-esm/{chunk-375RB3CZ.mjs → chunk-LGL4A5B5.mjs} +3 -2
  69. package/dist/lib/node-esm/chunk-LGL4A5B5.mjs.map +7 -0
  70. package/dist/lib/node-esm/{chunk-FUMGYUD3.mjs → chunk-RCZRYXI3.mjs} +15 -9
  71. package/dist/lib/node-esm/chunk-RCZRYXI3.mjs.map +7 -0
  72. package/dist/lib/node-esm/{identity-created-SJYZZ7Q3.mjs → identity-created-7THGZ7EW.mjs} +3 -3
  73. package/dist/lib/node-esm/index.mjs +14 -13
  74. package/dist/lib/node-esm/index.mjs.map +3 -3
  75. package/dist/lib/node-esm/intent-resolver-7L3GJAZE.mjs +538 -0
  76. package/dist/lib/node-esm/intent-resolver-7L3GJAZE.mjs.map +7 -0
  77. package/dist/lib/node-esm/meta.json +1 -1
  78. package/dist/lib/node-esm/{react-root-WKJWCHXR.mjs → react-root-BNA6PBFZ.mjs} +6 -6
  79. package/dist/lib/node-esm/{react-surface-RVEHOSAD.mjs → react-surface-FTI2LQNL.mjs} +26 -33
  80. package/dist/lib/node-esm/react-surface-FTI2LQNL.mjs.map +7 -0
  81. package/dist/lib/node-esm/{settings-WLVEO4JM.mjs → settings-KXYUZBLN.mjs} +3 -3
  82. package/dist/lib/node-esm/{spaces-ready-ITGYYT5A.mjs → spaces-ready-ZC2R73H3.mjs} +31 -32
  83. package/dist/lib/node-esm/spaces-ready-ZC2R73H3.mjs.map +7 -0
  84. package/dist/lib/node-esm/{state-BMISGQ2O.mjs → state-5GH2D5U4.mjs} +3 -3
  85. package/dist/lib/node-esm/types/index.mjs +2 -4
  86. package/dist/types/src/SpacePlugin.d.ts +5 -1
  87. package/dist/types/src/SpacePlugin.d.ts.map +1 -1
  88. package/dist/types/src/capabilities/app-graph-builder.d.ts +22 -22
  89. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  90. package/dist/types/src/capabilities/capabilities.d.ts +6 -0
  91. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  92. package/dist/types/src/capabilities/index.d.ts +34 -33
  93. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  94. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -1
  95. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  96. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  97. package/dist/types/src/capabilities/spaces-ready.d.ts.map +1 -1
  98. package/dist/types/src/components/BaseObjectSettings.d.ts.map +1 -1
  99. package/dist/types/src/components/CreateDialog/CreateObjectPanel.d.ts +4 -3
  100. package/dist/types/src/components/CreateDialog/CreateObjectPanel.d.ts.map +1 -1
  101. package/dist/types/src/components/CreateDialog/CreateSpaceDialog.d.ts.map +1 -1
  102. package/dist/types/src/components/JoinDialog.d.ts.map +1 -1
  103. package/dist/types/src/components/SpacePresence.d.ts.map +1 -1
  104. package/dist/types/src/components/SpaceSettings/SpaceSettingsDialog.d.ts.map +1 -1
  105. package/dist/types/src/components/SpaceSettings/SpaceSettingsPanel.d.ts +3 -4
  106. package/dist/types/src/components/SpaceSettings/SpaceSettingsPanel.d.ts.map +1 -1
  107. package/dist/types/src/components/SpaceSettings/SpaceSettingsPanel.stories.d.ts.map +1 -1
  108. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts.map +1 -1
  109. package/dist/types/src/meta.d.ts +1 -0
  110. package/dist/types/src/meta.d.ts.map +1 -1
  111. package/dist/types/src/types/types.d.ts +2 -5
  112. package/dist/types/src/types/types.d.ts.map +1 -1
  113. package/dist/types/src/util.d.ts +1 -0
  114. package/dist/types/src/util.d.ts.map +1 -1
  115. package/dist/types/tsconfig.tsbuildinfo +1 -1
  116. package/package.json +39 -37
  117. package/src/SpacePlugin.tsx +11 -6
  118. package/src/capabilities/app-graph-builder.ts +9 -8
  119. package/src/capabilities/capabilities.ts +4 -1
  120. package/src/capabilities/intent-resolver.ts +410 -312
  121. package/src/capabilities/react-surface.tsx +22 -30
  122. package/src/capabilities/spaces-ready.ts +20 -21
  123. package/src/components/AwaitingObject.tsx +5 -5
  124. package/src/components/BaseObjectSettings.tsx +7 -0
  125. package/src/components/CreateDialog/CreateObjectDialog.tsx +15 -15
  126. package/src/components/CreateDialog/CreateObjectPanel.tsx +115 -116
  127. package/src/components/CreateDialog/CreateSpaceDialog.tsx +18 -9
  128. package/src/components/JoinDialog.tsx +27 -19
  129. package/src/components/SpacePluginSettings.tsx +3 -3
  130. package/src/components/SpacePresence.stories.tsx +2 -2
  131. package/src/components/SpacePresence.tsx +2 -3
  132. package/src/components/SpaceSettings/SpaceSettingsDialog.tsx +16 -1
  133. package/src/components/SpaceSettings/SpaceSettingsPanel.stories.tsx +5 -1
  134. package/src/components/SpaceSettings/SpaceSettingsPanel.tsx +15 -8
  135. package/src/components/SyncStatus/InlineSyncStatus.tsx +2 -2
  136. package/src/components/SyncStatus/SyncStatus.tsx +2 -1
  137. package/src/meta.ts +1 -0
  138. package/src/types/types.ts +2 -7
  139. package/src/util.tsx +9 -4
  140. package/dist/lib/browser/app-graph-builder-5D2QB43K.mjs.map +0 -7
  141. package/dist/lib/browser/chunk-6SWQRWOD.mjs.map +0 -7
  142. package/dist/lib/browser/chunk-HCXWKGTE.mjs.map +0 -7
  143. package/dist/lib/browser/chunk-UH5P4UL3.mjs.map +0 -7
  144. package/dist/lib/browser/chunk-ZBKFJNHH.mjs.map +0 -7
  145. package/dist/lib/browser/intent-resolver-VBL572N7.mjs +0 -459
  146. package/dist/lib/browser/intent-resolver-VBL572N7.mjs.map +0 -7
  147. package/dist/lib/browser/react-surface-E2VSYVNZ.mjs.map +0 -7
  148. package/dist/lib/browser/spaces-ready-4SFNS5JQ.mjs.map +0 -7
  149. package/dist/lib/node/app-graph-builder-ZQ5S62YR.cjs.map +0 -7
  150. package/dist/lib/node/chunk-56NGXG2A.cjs.map +0 -7
  151. package/dist/lib/node/chunk-DDZYVNVP.cjs.map +0 -7
  152. package/dist/lib/node/chunk-M64YG2FY.cjs.map +0 -7
  153. package/dist/lib/node/chunk-Z34MTEU7.cjs.map +0 -7
  154. package/dist/lib/node/intent-resolver-S4HZABYI.cjs +0 -458
  155. package/dist/lib/node/intent-resolver-S4HZABYI.cjs.map +0 -7
  156. package/dist/lib/node/react-surface-TLKQEHHT.cjs.map +0 -7
  157. package/dist/lib/node/spaces-ready-RZTKEXOL.cjs.map +0 -7
  158. package/dist/lib/node-esm/app-graph-builder-CD6IYPSS.mjs.map +0 -7
  159. package/dist/lib/node-esm/chunk-375RB3CZ.mjs.map +0 -7
  160. package/dist/lib/node-esm/chunk-CLGCKZ2D.mjs.map +0 -7
  161. package/dist/lib/node-esm/chunk-CMKML5IN.mjs.map +0 -7
  162. package/dist/lib/node-esm/chunk-FUMGYUD3.mjs.map +0 -7
  163. package/dist/lib/node-esm/intent-resolver-OIQH7HN7.mjs +0 -460
  164. package/dist/lib/node-esm/intent-resolver-OIQH7HN7.mjs.map +0 -7
  165. package/dist/lib/node-esm/react-surface-RVEHOSAD.mjs.map +0 -7
  166. package/dist/lib/node-esm/spaces-ready-ITGYYT5A.mjs.map +0 -7
  167. /package/dist/lib/browser/{app-graph-serializer-VNWPLPDF.mjs.map → app-graph-serializer-QDXM5M6K.mjs.map} +0 -0
  168. /package/dist/lib/browser/{chunk-5TBRONF6.mjs.map → chunk-SDK7RZI3.mjs.map} +0 -0
  169. /package/dist/lib/browser/{identity-created-EC5FOCX2.mjs.map → identity-created-25TK5XNO.mjs.map} +0 -0
  170. /package/dist/lib/browser/{react-root-AZJFNTKK.mjs.map → react-root-Q7JJDCPB.mjs.map} +0 -0
  171. /package/dist/lib/browser/{settings-ASFF5BZL.mjs.map → settings-K4JPYYEM.mjs.map} +0 -0
  172. /package/dist/lib/browser/{state-MS4KYJWI.mjs.map → state-6DCY5YJP.mjs.map} +0 -0
  173. /package/dist/lib/node/{app-graph-serializer-72S7P33H.cjs.map → app-graph-serializer-H4UACG57.cjs.map} +0 -0
  174. /package/dist/lib/node/{chunk-BQRNTKSQ.cjs.map → chunk-D6BFKOXY.cjs.map} +0 -0
  175. /package/dist/lib/node/{identity-created-IMDS4A6A.cjs.map → identity-created-7G5U7R36.cjs.map} +0 -0
  176. /package/dist/lib/node/{react-root-RB3OM3QG.cjs.map → react-root-JN6AIHMS.cjs.map} +0 -0
  177. /package/dist/lib/node/{settings-QLCKAUHK.cjs.map → settings-TEELGWS4.cjs.map} +0 -0
  178. /package/dist/lib/node/{state-4UIOUKLJ.cjs.map → state-WPZC4JXB.cjs.map} +0 -0
  179. /package/dist/lib/node-esm/{app-graph-serializer-CFXS6ZE2.mjs.map → app-graph-serializer-PIPJVXYZ.mjs.map} +0 -0
  180. /package/dist/lib/node-esm/{chunk-M4XTHK35.mjs.map → chunk-4UX5WGKJ.mjs.map} +0 -0
  181. /package/dist/lib/node-esm/{identity-created-SJYZZ7Q3.mjs.map → identity-created-7THGZ7EW.mjs.map} +0 -0
  182. /package/dist/lib/node-esm/{react-root-WKJWCHXR.mjs.map → react-root-BNA6PBFZ.mjs.map} +0 -0
  183. /package/dist/lib/node-esm/{settings-WLVEO4JM.mjs.map → settings-KXYUZBLN.mjs.map} +0 -0
  184. /package/dist/lib/node-esm/{state-BMISGQ2O.mjs.map → state-5GH2D5U4.mjs.map} +0 -0
@@ -5,32 +5,18 @@
5
5
  import React, { useCallback, useMemo, useState } from 'react';
6
6
 
7
7
  import { Surface, isSurfaceAvailable, usePluginManager } from '@dxos/app-framework';
8
- import { type TypedObject, getObjectAnnotation, S } from '@dxos/echo-schema';
9
- import { type SpaceId, type Space, isSpace } from '@dxos/react-client/echo';
10
- import { Icon, IconButton, Input, toLocalizedString, useTranslation } from '@dxos/react-ui';
11
- import { Form, InputHeader, type InputProps } from '@dxos/react-ui-form';
8
+ import { type TypedObject, getObjectAnnotation, type ObjectAnnotation, S } from '@dxos/echo-schema';
9
+ import { type SpaceId, type Space } from '@dxos/react-client/echo';
10
+ import { Icon, type ThemedClassName, toLocalizedString, useTranslation } from '@dxos/react-ui';
11
+ import { Form, type InputProps } from '@dxos/react-ui-form';
12
12
  import { SearchList } from '@dxos/react-ui-searchlist';
13
- import { nonNullable, type MaybePromise } from '@dxos/util';
13
+ import { mx } from '@dxos/react-ui-theme';
14
+ import { isNonNullable, type MaybePromise } from '@dxos/util';
14
15
 
15
16
  import { SPACE_PLUGIN } from '../../meta';
16
17
  import { type CollectionType } from '../../types';
17
18
  import { getSpaceDisplayName } from '../../util';
18
19
 
19
- export type CreateObjectPanelProps = {
20
- schemas: TypedObject[];
21
- spaces: Space[];
22
- typename?: string;
23
- target?: Space | CollectionType;
24
- name?: string;
25
- defaultSpaceId?: SpaceId;
26
- resolve?: (typename: string) => Record<string, any>;
27
- onCreateObject?: (params: {
28
- schema: TypedObject;
29
- target: Space | CollectionType;
30
- data: Record<string, any>;
31
- }) => MaybePromise<void>;
32
- };
33
-
34
20
  // TODO(ZaymonFC): Move this if you find yourself needing it elsewhere.
35
21
  /**
36
22
  * Creates a surface input component based on plugin context.
@@ -41,9 +27,8 @@ const useInputSurfaceLookup = (baseData?: Record<string, any>) => {
41
27
  const pluginManager = usePluginManager();
42
28
 
43
29
  return useCallback(
44
- ({ prop, schema, inputProps }: { prop: string; schema: S.Schema<any>; inputProps: InputProps<any> }) => {
30
+ ({ prop, schema, inputProps }: { prop: string; schema: S.Schema<any>; inputProps: InputProps }) => {
45
31
  const composedData = { prop, schema, ...baseData };
46
-
47
32
  if (!isSurfaceAvailable(pluginManager.context, { role: 'form-input', data: composedData })) {
48
33
  return undefined;
49
34
  }
@@ -54,7 +39,23 @@ const useInputSurfaceLookup = (baseData?: Record<string, any>) => {
54
39
  );
55
40
  };
56
41
 
42
+ export type CreateObjectPanelProps = ThemedClassName<{
43
+ schemas: TypedObject[];
44
+ spaces: Space[];
45
+ typename?: string;
46
+ target?: Space | CollectionType;
47
+ name?: string;
48
+ defaultSpaceId?: SpaceId;
49
+ resolve?: (typename: string) => Record<string, any>;
50
+ onCreateObject?: (params: {
51
+ schema: TypedObject;
52
+ target: Space | CollectionType;
53
+ data: Record<string, any>;
54
+ }) => MaybePromise<void>;
55
+ }>;
56
+
57
57
  export const CreateObjectPanel = ({
58
+ classNames,
58
59
  schemas,
59
60
  spaces,
60
61
  typename: initialTypename,
@@ -68,10 +69,14 @@ export const CreateObjectPanel = ({
68
69
  const [typename, setTypename] = useState<string | undefined>(initialTypename);
69
70
  const [target, setTarget] = useState<Space | CollectionType | undefined>(initialTarget);
70
71
  const schema = schemas.find((schema) => getObjectAnnotation(schema)?.typename === typename);
71
- const options = schemas.map(getObjectAnnotation).filter(nonNullable);
72
-
73
- const handleClearSchema = useCallback(() => setTypename(undefined), []);
74
- const handleClearTarget = useCallback(() => setTarget(undefined), []);
72
+ const options: ObjectAnnotation[] = schemas
73
+ .map(getObjectAnnotation)
74
+ .filter(isNonNullable)
75
+ .sort((a, b) => {
76
+ const nameA = t('typename label', { ns: a.typename, defaultValue: a.typename });
77
+ const nameB = t('typename label', { ns: b.typename, defaultValue: b.typename });
78
+ return nameA.localeCompare(nameB);
79
+ });
75
80
 
76
81
  const handleCreateObject = useCallback(
77
82
  async (props: Record<string, any>) => {
@@ -90,117 +95,111 @@ export const CreateObjectPanel = ({
90
95
  return resolve?.(typename);
91
96
  }, [resolve, typename]);
92
97
 
93
- // TODO(wittjosiah): All of these inputs should be rolled into a `Form` once it supports the necessary variants.
94
- const schemaInput = (
95
- <SearchList.Root label={t('schema input label')} classNames='flex flex-col grow overflow-hidden'>
98
+ const inputSurfaceLookup = useInputSurfaceLookup({ target });
99
+
100
+ const form = useMemo(() => {
101
+ // TODO(ZaymonFC): Move this default object creation schema somewhere?
102
+ const schema = (metadata?.creationSchema ?? S.Struct({ name: S.optional(S.String) })) as S.Schema<any>;
103
+
104
+ return (
105
+ <Form
106
+ classNames='!p-0'
107
+ autoFocus
108
+ values={{ name: initialName }}
109
+ schema={schema}
110
+ testId='create-object-form'
111
+ onSave={handleCreateObject}
112
+ lookupComponent={inputSurfaceLookup}
113
+ />
114
+ );
115
+ }, [initialName, handleCreateObject, metadata]);
116
+
117
+ // TODO(wittjosiah): These inputs should be rolled into a `Form` once it supports the necessary variants.
118
+ return (
119
+ <div role='form' className={mx('flex flex-col gap-2', classNames)}>
120
+ {!schema ? (
121
+ <SelectSchema options={options} resolve={resolve} onChange={setTypename} />
122
+ ) : !target ? (
123
+ <SelectSpace spaces={spaces} defaultSpaceId={defaultSpaceId} onChange={setTarget} />
124
+ ) : (
125
+ form
126
+ )}
127
+ </div>
128
+ );
129
+ };
130
+
131
+ const SelectSpace = ({
132
+ spaces,
133
+ defaultSpaceId,
134
+ onChange,
135
+ }: { onChange: (space: Space) => void } & Pick<CreateObjectPanelProps, 'spaces' | 'defaultSpaceId'>) => {
136
+ const { t } = useTranslation(SPACE_PLUGIN);
137
+
138
+ return (
139
+ <SearchList.Root label={t('space input label')} classNames='flex flex-col grow overflow-hidden'>
96
140
  <SearchList.Input
97
141
  autoFocus
98
- data-testid='create-object-form.schema-input'
99
- placeholder={t('schema input placeholder')}
142
+ data-testid='create-object-form.space-input'
143
+ placeholder={t('space input placeholder')}
100
144
  classNames='px-1 my-2'
101
145
  />
102
146
  <SearchList.Content classNames='max-bs-[24rem] overflow-auto'>
103
- {options.map((option) => (
104
- <SearchList.Item
105
- key={option.typename}
106
- value={t('typename label', { ns: option.typename, defaultValue: option.typename })}
107
- onSelect={() => setTypename(option.typename)}
108
- classNames='flex items-center gap-2'
109
- >
110
- <span className='flex gap-2 items-center grow truncate'>
111
- <Icon icon={resolve?.(option.typename).icon ?? 'ph--placeholder--regular'} size={5} />
112
- {t('typename label', { ns: option.typename, defaultValue: option.typename })}
113
- </span>
114
- </SearchList.Item>
115
- ))}
147
+ {spaces
148
+ .sort((a, b) => {
149
+ const aName = toLocalizedString(getSpaceDisplayName(a, { personal: a.id === defaultSpaceId }), t);
150
+ const bName = toLocalizedString(getSpaceDisplayName(b, { personal: b.id === defaultSpaceId }), t);
151
+ return aName.localeCompare(bName);
152
+ })
153
+ .map((space) => (
154
+ <SearchList.Item
155
+ key={space.id}
156
+ value={toLocalizedString(getSpaceDisplayName(space, { personal: space.id === defaultSpaceId }), t)}
157
+ onSelect={() => onChange(space)}
158
+ classNames='flex items-center gap-2'
159
+ >
160
+ <span className='grow truncate'>
161
+ {toLocalizedString(getSpaceDisplayName(space, { personal: space.id === defaultSpaceId }), t)}
162
+ </span>
163
+ </SearchList.Item>
164
+ ))}
116
165
  </SearchList.Content>
117
166
  </SearchList.Root>
118
167
  );
168
+ };
119
169
 
120
- const spaceInput = (
121
- <SearchList.Root label={t('space input label')} classNames='flex flex-col grow overflow-hidden'>
170
+ const SelectSchema = ({
171
+ options,
172
+ resolve,
173
+ onChange,
174
+ }: {
175
+ options: ObjectAnnotation[];
176
+ onChange: (type: string) => void;
177
+ } & Pick<CreateObjectPanelProps, 'resolve'>) => {
178
+ const { t } = useTranslation(SPACE_PLUGIN);
179
+
180
+ return (
181
+ <SearchList.Root label={t('schema input label')} classNames='flex flex-col grow overflow-hidden'>
122
182
  <SearchList.Input
123
183
  autoFocus
124
- data-testid='create-object-form.space-input'
125
- placeholder={t('space input placeholder')}
184
+ data-testid='create-object-form.schema-input'
185
+ placeholder={t('schema input placeholder')}
126
186
  classNames='px-1 my-2'
127
187
  />
128
188
  <SearchList.Content classNames='max-bs-[24rem] overflow-auto'>
129
- {spaces.map((space) => (
189
+ {options.map((option) => (
130
190
  <SearchList.Item
131
- key={space.id}
132
- value={toLocalizedString(getSpaceDisplayName(space, { personal: space.id === defaultSpaceId }), t)}
133
- onSelect={() => setTarget(space)}
191
+ key={option.typename}
192
+ value={t('typename label', { ns: option.typename, defaultValue: option.typename })}
193
+ onSelect={() => onChange(option.typename)}
134
194
  classNames='flex items-center gap-2'
135
195
  >
136
- <span className='grow truncate'>
137
- {toLocalizedString(getSpaceDisplayName(space, { personal: space.id === defaultSpaceId }), t)}
196
+ <span className='flex gap-2 items-center grow truncate'>
197
+ <Icon icon={resolve?.(option.typename).icon ?? 'ph--placeholder--regular'} size={5} />
198
+ {t('typename label', { ns: option.typename, defaultValue: option.typename })}
138
199
  </span>
139
200
  </SearchList.Item>
140
201
  ))}
141
202
  </SearchList.Content>
142
203
  </SearchList.Root>
143
204
  );
144
-
145
- const inputSurfaceLookup = useInputSurfaceLookup({ target });
146
-
147
- const form = useMemo(() => {
148
- // TODO(ZaymonFC): Move this default object creation schema somewhere?
149
- const schema = (metadata?.creationSchema ?? S.Struct({ name: S.optional(S.String) })) as S.Schema<any>;
150
-
151
- return (
152
- <Form
153
- autoFocus
154
- values={{ name: initialName }}
155
- schema={schema}
156
- testId='create-object-form'
157
- onSave={handleCreateObject}
158
- lookupComponent={inputSurfaceLookup}
159
- />
160
- );
161
- }, [initialName, handleCreateObject, metadata]);
162
-
163
- return (
164
- <div role='form' className='flex flex-col gap-2'>
165
- {target && (
166
- <div role='none'>
167
- <Input.Root>
168
- <InputHeader>
169
- <Input.Label>
170
- {t(isSpace(target) ? 'creating in space label' : 'creating in collection label')}
171
- </Input.Label>
172
- </InputHeader>
173
- <div role='none' className='flex gap-2'>
174
- <Input.TextInput
175
- disabled
176
- value={
177
- isSpace(target)
178
- ? toLocalizedString(getSpaceDisplayName(target, { personal: target.id === defaultSpaceId }), t)
179
- : target.name || t('unnamed collection label')
180
- }
181
- />
182
- <IconButton iconOnly icon='ph--x--regular' label={t('clear input label')} onClick={handleClearTarget} />
183
- </div>
184
- </Input.Root>
185
- </div>
186
- )}
187
- {schema && (
188
- <div role='none'>
189
- <Input.Root>
190
- <InputHeader>
191
- <Input.Label>{t('creating object type label')}</Input.Label>
192
- </InputHeader>
193
- <div role='none' className='flex gap-2'>
194
- <Input.TextInput
195
- disabled
196
- value={t('typename label', { ns: schema.typename, defaultValue: schema.typename })}
197
- />
198
- <IconButton iconOnly icon='ph--x--regular' label={t('clear input label')} onClick={handleClearSchema} />
199
- </div>
200
- </Input.Root>
201
- </div>
202
- )}
203
- {!schema ? schemaInput : !target ? spaceInput : form}
204
- </div>
205
- );
206
205
  };
@@ -2,9 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Effect } from 'effect';
5
6
  import React, { useCallback, useRef } from 'react';
6
7
 
7
- import { createIntent, useIntentDispatcher } from '@dxos/app-framework';
8
+ import { createIntent, LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
8
9
  import { type S } from '@dxos/echo-schema';
9
10
  import { Button, Dialog, Icon, useTranslation } from '@dxos/react-ui';
10
11
  import { Form } from '@dxos/react-ui-form';
@@ -20,15 +21,16 @@ const initialValues: FormValues = { edgeReplication: true };
20
21
  export const CreateSpaceDialog = () => {
21
22
  const closeRef = useRef<HTMLButtonElement | null>(null);
22
23
  const { t } = useTranslation(SPACE_PLUGIN);
23
- const { dispatchPromise: dispatch } = useIntentDispatcher();
24
+ const { dispatch } = useIntentDispatcher();
24
25
 
25
26
  const handleCreateSpace = useCallback(
26
27
  async (data: FormValues) => {
27
- const result = await dispatch(createIntent(SpaceAction.Create, data));
28
- const target = result.data?.space;
29
- if (target) {
30
- await dispatch(createIntent(SpaceAction.OpenCreateObject, { target }));
31
- }
28
+ const program = Effect.gen(function* () {
29
+ const { space } = yield* dispatch(createIntent(SpaceAction.Create, data));
30
+ yield* dispatch(createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: space.id }));
31
+ yield* dispatch(createIntent(SpaceAction.OpenCreateObject, { target: space }));
32
+ });
33
+ await Effect.runPromise(program);
32
34
  },
33
35
  [dispatch],
34
36
  );
@@ -36,7 +38,7 @@ export const CreateSpaceDialog = () => {
36
38
  return (
37
39
  // TODO(wittjosiah): The tablist dialog pattern is copied from @dxos/plugin-manager.
38
40
  // Consider factoring it out to the tabs package.
39
- <Dialog.Content classNames='p-0 bs-content min-bs-[15rem] max-bs-full md:max-is-[40rem] overflow-hidden'>
41
+ <Dialog.Content classNames='p-0 bs-content min-bs-[16rem] max-bs-full md:max-is-[32rem] overflow-hidden'>
40
42
  <div role='none' className='flex justify-between pbs-2 pis-2 pie-2 @md:pbs-4 @md:pis-4 @md:pie-4'>
41
43
  <Dialog.Title>{t('create space dialog title')}</Dialog.Title>
42
44
  <Dialog.Close asChild>
@@ -46,7 +48,14 @@ export const CreateSpaceDialog = () => {
46
48
  </Dialog.Close>
47
49
  </div>
48
50
  <div className='p-4'>
49
- <Form testId='create-space-form' values={initialValues} schema={SpaceForm} onSave={handleCreateSpace} />
51
+ <Form
52
+ testId='create-space-form'
53
+ classNames='!p-0'
54
+ autoFocus
55
+ values={initialValues}
56
+ schema={SpaceForm}
57
+ onSave={handleCreateSpace}
58
+ />
50
59
  </div>
51
60
  </Dialog.Content>
52
61
  );
@@ -4,12 +4,12 @@
4
4
 
5
5
  import React, { useCallback } from 'react';
6
6
 
7
- import { createIntent, LayoutAction, NavigationAction, useIntentDispatcher } from '@dxos/app-framework';
8
- import { useGraph } from '@dxos/plugin-graph';
7
+ import { createIntent, LayoutAction, useAppGraph, useIntentDispatcher } from '@dxos/app-framework';
8
+ import { log } from '@dxos/log';
9
9
  import { ObservabilityAction } from '@dxos/plugin-observability/types';
10
- import { useSpaces } from '@dxos/react-client/echo';
10
+ import { useClient } from '@dxos/react-client';
11
11
  import { type InvitationResult } from '@dxos/react-client/invitations';
12
- import { Dialog, useTranslation } from '@dxos/react-ui';
12
+ import { Dialog } from '@dxos/react-ui';
13
13
  import { JoinPanel, type JoinPanelProps } from '@dxos/shell/react';
14
14
 
15
15
  import { SPACE_PLUGIN } from '../meta';
@@ -21,47 +21,55 @@ export type JoinDialogProps = JoinPanelProps & {
21
21
  };
22
22
 
23
23
  export const JoinDialog = ({ navigableCollections, onDone, ...props }: JoinDialogProps) => {
24
- const { t } = useTranslation(SPACE_PLUGIN);
25
24
  const { dispatchPromise: dispatch } = useIntentDispatcher();
26
- const spaces = useSpaces();
27
- const { graph } = useGraph();
25
+ const client = useClient();
26
+ const { graph } = useAppGraph();
28
27
 
29
28
  const handleDone = useCallback(
30
29
  async (result: InvitationResult | null) => {
31
30
  if (result?.spaceKey) {
32
31
  await Promise.all([
33
32
  dispatch(
34
- createIntent(LayoutAction.SetLayout, {
35
- element: 'toast',
33
+ createIntent(LayoutAction.AddToast, {
34
+ part: 'toast',
36
35
  subject: {
37
36
  id: `${SPACE_PLUGIN}/join-success`,
38
37
  duration: 5_000,
39
- title: t('join success label'),
40
- closeLabel: t('dismiss label'),
38
+ title: ['join success label', { ns: SPACE_PLUGIN }],
39
+ closeLabel: ['dismiss label', { ns: SPACE_PLUGIN }],
41
40
  },
42
41
  }),
43
42
  ),
44
43
  dispatch(
45
- createIntent(LayoutAction.SetLayout, {
46
- element: 'dialog',
47
- state: false,
44
+ createIntent(LayoutAction.UpdateDialog, {
45
+ part: 'dialog',
46
+ options: {
47
+ state: false,
48
+ },
48
49
  }),
49
50
  ),
50
51
  ]);
51
52
  }
52
53
 
53
- const space = spaces.find(({ key }) => result?.spaceKey?.equals(key));
54
+ const space = result?.spaceKey ? client.spaces.get(result.spaceKey) : undefined;
55
+ if (!space) {
56
+ log.warn('Space not found', result?.spaceKey);
57
+ return;
58
+ }
59
+
60
+ await dispatch(createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: space.id }));
61
+
54
62
  // TODO(wittjosiah): If navigableCollections is false and there's no target,
55
63
  // should try to navigate to the first object of the space replicates.
56
64
  // Potentially this could also be done on the inviters side to ensure there's always a target.
57
65
  const target = result?.target || (navigableCollections ? space?.id : undefined);
58
66
  if (target) {
59
- // Wait for up to 1 second before navigating to the target node.
67
+ // Wait before navigating to the target node.
60
68
  // If the target has not yet replicated, this will trigger a loading toast.
61
69
  await graph.waitForPath({ target }).catch(() => {});
62
70
  await Promise.all([
63
- dispatch(createIntent(NavigationAction.Open, { activeParts: { main: [target] } })),
64
- dispatch(createIntent(NavigationAction.Expose, { id: target })),
71
+ dispatch(createIntent(LayoutAction.Open, { part: 'main', subject: [target] })),
72
+ dispatch(createIntent(LayoutAction.Expose, { part: 'navigation', subject: target })),
65
73
  ]);
66
74
  }
67
75
 
@@ -73,7 +81,7 @@ export const JoinDialog = ({ navigableCollections, onDone, ...props }: JoinDialo
73
81
  );
74
82
  }
75
83
  },
76
- [dispatch, spaces],
84
+ [dispatch, client, graph],
77
85
  );
78
86
 
79
87
  return (
@@ -5,7 +5,7 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Input, useTranslation } from '@dxos/react-ui';
8
- import { DeprecatedFormInput } from '@dxos/react-ui-form';
8
+ import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
9
9
 
10
10
  import { SPACE_PLUGIN } from '../meta';
11
11
  import { type SpaceSettingsProps } from '../types';
@@ -14,10 +14,10 @@ export const SpacePluginSettings = ({ settings }: { settings: SpaceSettingsProps
14
14
  const { t } = useTranslation(SPACE_PLUGIN);
15
15
 
16
16
  return (
17
- <>
17
+ <DeprecatedFormContainer>
18
18
  <DeprecatedFormInput label={t('show hidden spaces label')}>
19
19
  <Input.Switch checked={settings.showHidden} onCheckedChange={(checked) => (settings.showHidden = !!checked)} />
20
20
  </DeprecatedFormInput>
21
- </>
21
+ </DeprecatedFormContainer>
22
22
  );
23
23
  };
@@ -7,7 +7,7 @@ import '@dxos-theme';
7
7
  import { type Meta } from '@storybook/react';
8
8
  import React from 'react';
9
9
 
10
- import { PublicKey } from '@dxos/keys';
10
+ import { IdentityDid, PublicKey } from '@dxos/keys';
11
11
  import { HaloSpaceMember, SpaceMember } from '@dxos/react-client/echo';
12
12
  import { withLayout, withTheme } from '@dxos/storybook-utils';
13
13
 
@@ -17,7 +17,7 @@ import translations from '../translations';
17
17
  const nViewers = (n: number, currentlyAttended = true): Member[] =>
18
18
  Array.from({ length: n }, () => ({
19
19
  role: HaloSpaceMember.Role.ADMIN,
20
- identity: { identityKey: PublicKey.random() },
20
+ identity: { did: IdentityDid.random(), identityKey: PublicKey.random() },
21
21
  presence: SpaceMember.PresenceState.ONLINE,
22
22
  lastSeen: Date.now(),
23
23
  currentlyAttended,
@@ -4,10 +4,9 @@
4
4
 
5
5
  import React, { useCallback, useEffect, useState } from 'react';
6
6
 
7
- import { useCapability } from '@dxos/app-framework';
7
+ import { useAppGraph, useCapability } from '@dxos/app-framework';
8
8
  import { generateName } from '@dxos/display-name';
9
9
  import { type Expando } from '@dxos/echo-schema';
10
- import { useGraph } from '@dxos/plugin-graph';
11
10
  import { PublicKey, useClient } from '@dxos/react-client';
12
11
  import { getSpace, useMembers, type SpaceMember, fullyQualifiedId } from '@dxos/react-client/echo';
13
12
  import { type Identity, useIdentity } from '@dxos/react-client/halo';
@@ -210,7 +209,7 @@ export const SmallPresenceLive = ({ id, open, viewers }: SmallPresenceLiveProps)
210
209
  // TODO(wittjosiah): If the attended node is deep in the graph and the graph is not fully loaded
211
210
  // this will result in an empty path until the graph is connected.
212
211
  // TODO(wittjosiah): Consider using this indicator for all open nodes instead of just attended.
213
- const { graph } = useGraph();
212
+ const { graph } = useAppGraph();
214
213
  const attended = useAttended();
215
214
  const startOfAttention = attended.at(-1);
216
215
  const path = usePath(graph, startOfAttention);
@@ -2,14 +2,16 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useState } from 'react';
5
+ import React, { useMemo, useState } from 'react';
6
6
 
7
+ import { Surface, useCapabilities } from '@dxos/app-framework';
7
8
  import { useClient } from '@dxos/react-client';
8
9
  import { Button, Clipboard, Dialog, Icon, toLocalizedString, useTranslation } from '@dxos/react-ui';
9
10
  import { Tabs, type TabsRootProps, type TabsActivePart } from '@dxos/react-ui-tabs';
10
11
  import { SpacePanel, type SpacePanelProps } from '@dxos/shell/react';
11
12
 
12
13
  import { SpaceSettingsPanel, type SpaceSettingsPanelProps } from './SpaceSettingsPanel';
14
+ import { SpaceCapabilities } from '../../capabilities';
13
15
  import { SPACE_PLUGIN } from '../../meta';
14
16
  import { COMPOSER_SPACE_LOCK, getSpaceDisplayName } from '../../util';
15
17
 
@@ -36,6 +38,8 @@ export const SpaceSettingsDialog = ({
36
38
  const [selected, setSelected] = useState<SpaceSettingsTab>(initialTab);
37
39
  const locked = space.properties[COMPOSER_SPACE_LOCK];
38
40
  const name = getSpaceDisplayName(space, { personal: client.spaces.default === space, namesCache });
41
+ const panels = useCapabilities(SpaceCapabilities.SettingsPanel);
42
+ const data = useMemo(() => ({ subject: space }), [space]);
39
43
 
40
44
  return (
41
45
  // TODO(wittjosiah): The tablist dialog pattern is copied from @dxos/plugin-manager.
@@ -84,6 +88,11 @@ export const SpaceSettingsDialog = ({
84
88
  <Tabs.Tab value='members' disabled={locked}>
85
89
  {t('members tab label')}
86
90
  </Tabs.Tab>
91
+ {panels.map((panel) => (
92
+ <Tabs.Tab key={panel.id} value={panel.id}>
93
+ {toLocalizedString(panel.label, t)}
94
+ </Tabs.Tab>
95
+ ))}
87
96
  </div>
88
97
  </Tabs.Tablist>
89
98
  </div>
@@ -98,6 +107,12 @@ export const SpaceSettingsDialog = ({
98
107
  <SpacePanel space={space} hideHeading target={target} createInvitationUrl={createInvitationUrl} />
99
108
  </Clipboard.Provider>
100
109
  </Tabs.Tabpanel>
110
+
111
+ {panels.map((panel) => (
112
+ <Tabs.Tabpanel key={panel.id} value={panel.id} classNames='pli-3 @md:pli-5 max-bs-dvh overflow-y-auto'>
113
+ <Surface role={`space-settings--${panel.id}`} data={data} />
114
+ </Tabs.Tabpanel>
115
+ ))}
101
116
  </Tabs.Viewport>
102
117
  </Tabs.Root>
103
118
  </Dialog.Content>
@@ -15,7 +15,11 @@ import translations from '../../translations';
15
15
 
16
16
  const Story = (args: Partial<SpaceSettingsPanelProps>) => {
17
17
  const { space } = useClientProvider();
18
- return <SpaceSettingsPanel {...args} space={space!} classNames='p-2 border border-primary-500 rounded' />;
18
+ return (
19
+ <div role='none' className='p-2 border border-primary-500 rounded'>
20
+ <SpaceSettingsPanel {...args} space={space!} />
21
+ </div>
22
+ );
19
23
  };
20
24
 
21
25
  const meta: Meta = {
@@ -8,17 +8,17 @@ import { log } from '@dxos/log';
8
8
  import { EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
9
9
  import { useClient } from '@dxos/react-client';
10
10
  import { type Space } from '@dxos/react-client/echo';
11
- import { type ThemedClassName, Input, useTranslation } from '@dxos/react-ui';
12
- import { DeprecatedFormInput } from '@dxos/react-ui-form';
13
- import { mx } from '@dxos/react-ui-theme';
11
+ import { Input, useTranslation } from '@dxos/react-ui';
12
+ import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
13
+ import { HuePickerBlock } from '@dxos/react-ui-pickers';
14
14
 
15
15
  import { SPACE_PLUGIN } from '../../meta';
16
16
 
17
- export type SpaceSettingsPanelProps = ThemedClassName<{
17
+ export type SpaceSettingsPanelProps = {
18
18
  space: Space;
19
- }>;
19
+ };
20
20
 
21
- export const SpaceSettingsPanel = ({ classNames, space }: SpaceSettingsPanelProps) => {
21
+ export const SpaceSettingsPanel = ({ space }: SpaceSettingsPanelProps) => {
22
22
  const { t } = useTranslation(SPACE_PLUGIN);
23
23
 
24
24
  const client = useClient();
@@ -41,7 +41,7 @@ export const SpaceSettingsPanel = ({ classNames, space }: SpaceSettingsPanelProp
41
41
  );
42
42
 
43
43
  return (
44
- <div role='form' className={mx('flex flex-col', classNames)}>
44
+ <DeprecatedFormContainer>
45
45
  <DeprecatedFormInput label={t('name label')}>
46
46
  <Input.TextInput
47
47
  placeholder={t('unnamed space label')}
@@ -51,11 +51,18 @@ export const SpaceSettingsPanel = ({ classNames, space }: SpaceSettingsPanelProp
51
51
  }}
52
52
  />
53
53
  </DeprecatedFormInput>
54
+ <DeprecatedFormInput label={t('hue label')}>
55
+ <HuePickerBlock
56
+ hue={space.properties.hue}
57
+ onChangeHue={(nextHue) => (space.properties.hue = nextHue)}
58
+ onClickClear={() => (space.properties.hue = undefined)}
59
+ />
60
+ </DeprecatedFormInput>
54
61
  {edgeEnabled && (
55
62
  <DeprecatedFormInput label={t('edge replication label')}>
56
63
  <Input.Switch checked={edgeReplication} onCheckedChange={toggleEdgeReplication} />
57
64
  </DeprecatedFormInput>
58
65
  )}
59
- </div>
66
+ </DeprecatedFormContainer>
60
67
  );
61
68
  };
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React, { useEffect, useState } from 'react';
6
6
 
7
- import { useGraph } from '@dxos/plugin-graph';
7
+ import { useAppGraph } from '@dxos/app-framework';
8
8
  import { QueryEdgeStatusResponse } from '@dxos/protocols/proto/dxos/client/services';
9
9
  import { EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
10
10
  import { useClient } from '@dxos/react-client';
@@ -38,7 +38,7 @@ export const InlineSyncStatus = ({ space, open }: { space: Space; open?: boolean
38
38
  // TODO(wittjosiah): If the attended node is deep in the graph and the graph is not fully loaded
39
39
  // this will result in an empty path until the graph is connected.
40
40
  // TODO(wittjosiah): Consider using this indicator for all open nodes instead of just attended.
41
- const { graph } = useGraph();
41
+ const { graph } = useAppGraph();
42
42
  const attended = useAttended();
43
43
  const startOfAttention = attended.at(-1);
44
44
  const path = usePath(graph, startOfAttention);
@@ -66,8 +66,9 @@ export const SyncStatusIndicator = ({ state, saved }: { state: SpaceSyncStateMap
66
66
  <StatusBar.Button title={title}>{icon}</StatusBar.Button>
67
67
  </Popover.Trigger>
68
68
  <Popover.Portal>
69
- <Popover.Content sideOffset={16}>
69
+ <Popover.Content>
70
70
  <SyncStatusDetail state={state} summary={summary} debug={false} />
71
+ <Popover.Arrow />
71
72
  </Popover.Content>
72
73
  </Popover.Portal>
73
74
  </Popover.Root>