@dxos/plugin-space 0.8.1 → 0.8.2-main.12df754

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 (230) hide show
  1. package/dist/lib/browser/{app-graph-builder-GMFCSOLG.mjs → app-graph-builder-J4PN5HOM.mjs} +60 -6
  2. package/dist/lib/browser/app-graph-builder-J4PN5HOM.mjs.map +7 -0
  3. package/dist/lib/browser/{app-graph-serializer-DSF2U3A5.mjs → app-graph-serializer-6WIAFHYK.mjs} +8 -8
  4. package/dist/lib/browser/app-graph-serializer-6WIAFHYK.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-LO5UL6RU.mjs → chunk-FSHDAPFY.mjs} +60 -141
  6. package/dist/lib/browser/chunk-FSHDAPFY.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-AYW4IDRT.mjs → chunk-KDNV4YRD.mjs} +11 -3
  8. package/dist/lib/browser/chunk-KDNV4YRD.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-JZXWPMLA.mjs → chunk-MHTZAZT2.mjs} +497 -639
  10. package/dist/lib/browser/chunk-MHTZAZT2.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-5BDV575R.mjs → chunk-MIJHUABE.mjs} +20 -8
  12. package/dist/lib/browser/chunk-MIJHUABE.mjs.map +7 -0
  13. package/dist/lib/browser/{identity-created-JR7BNXFH.mjs → identity-created-DVHNLGYU.mjs} +4 -4
  14. package/dist/lib/browser/identity-created-DVHNLGYU.mjs.map +7 -0
  15. package/dist/lib/browser/index.mjs +11 -29
  16. package/dist/lib/browser/index.mjs.map +3 -3
  17. package/dist/lib/browser/{intent-resolver-RKYILWWQ.mjs → intent-resolver-72IWBVYE.mjs} +23 -27
  18. package/dist/lib/browser/intent-resolver-72IWBVYE.mjs.map +7 -0
  19. package/dist/lib/browser/meta.json +1 -1
  20. package/dist/lib/browser/{react-root-6H7NX2M2.mjs → react-root-DRVM5ACV.mjs} +4 -4
  21. package/dist/lib/browser/{react-surface-7AGLOVMK.mjs → react-surface-KODNQYDN.mjs} +139 -48
  22. package/dist/lib/browser/react-surface-KODNQYDN.mjs.map +7 -0
  23. package/dist/lib/browser/{settings-PJPTJUPE.mjs → settings-2UIV5WX5.mjs} +4 -4
  24. package/dist/lib/browser/settings-2UIV5WX5.mjs.map +7 -0
  25. package/dist/lib/browser/{spaces-ready-BSSP7HHG.mjs → spaces-ready-3URIMLCR.mjs} +5 -5
  26. package/dist/lib/browser/spaces-ready-3URIMLCR.mjs.map +7 -0
  27. package/dist/lib/browser/{state-X7VLCC6E.mjs → state-CYV6QCTN.mjs} +1 -3
  28. package/dist/lib/browser/state-CYV6QCTN.mjs.map +7 -0
  29. package/dist/lib/browser/types/index.mjs +7 -1
  30. package/dist/lib/node/{app-graph-builder-DPY7AUZE.cjs → app-graph-builder-3BNPC5GB.cjs} +82 -29
  31. package/dist/lib/node/app-graph-builder-3BNPC5GB.cjs.map +7 -0
  32. package/dist/lib/node/{app-graph-serializer-JELGJUAY.cjs → app-graph-serializer-GOLCQHFQ.cjs} +20 -20
  33. package/dist/lib/node/app-graph-serializer-GOLCQHFQ.cjs.map +7 -0
  34. package/dist/lib/node/{chunk-WDEIFDTX.cjs → chunk-3UKLWXNJ.cjs} +17 -6
  35. package/dist/lib/node/chunk-3UKLWXNJ.cjs.map +7 -0
  36. package/dist/lib/node/{chunk-PU2EYH4E.cjs → chunk-EI3ZPOLJ.cjs} +24 -12
  37. package/dist/lib/node/chunk-EI3ZPOLJ.cjs.map +7 -0
  38. package/dist/lib/node/{chunk-3GKCNADA.cjs → chunk-GPZPEQXP.cjs} +482 -622
  39. package/dist/lib/node/chunk-GPZPEQXP.cjs.map +7 -0
  40. package/dist/lib/node/{chunk-TUZWEPGX.cjs → chunk-U63V2254.cjs} +84 -167
  41. package/dist/lib/node/chunk-U63V2254.cjs.map +7 -0
  42. package/dist/lib/node/{identity-created-XU4HFV2T.cjs → identity-created-YYTW4K3Z.cjs} +6 -6
  43. package/dist/lib/node/identity-created-YYTW4K3Z.cjs.map +7 -0
  44. package/dist/lib/node/index.cjs +69 -87
  45. package/dist/lib/node/index.cjs.map +3 -3
  46. package/dist/lib/node/{intent-resolver-VJ7YV74L.cjs → intent-resolver-KA56XGUX.cjs} +75 -79
  47. package/dist/lib/node/intent-resolver-KA56XGUX.cjs.map +7 -0
  48. package/dist/lib/node/meta.json +1 -1
  49. package/dist/lib/node/{react-root-TEL5RW3N.cjs → react-root-6WGN5WRQ.cjs} +8 -8
  50. package/dist/lib/node/{react-surface-2H3S5TY5.cjs → react-surface-37AVZFPL.cjs} +163 -74
  51. package/dist/lib/node/react-surface-37AVZFPL.cjs.map +7 -0
  52. package/dist/lib/node/{settings-WVFP2UEP.cjs → settings-HJROTHC4.cjs} +7 -7
  53. package/dist/lib/node/settings-HJROTHC4.cjs.map +7 -0
  54. package/dist/lib/node/{spaces-ready-7DNZSUOG.cjs → spaces-ready-IWDDIAAD.cjs} +12 -12
  55. package/dist/lib/node/spaces-ready-IWDDIAAD.cjs.map +7 -0
  56. package/dist/lib/node/{state-5KX6WBJH.cjs → state-JLN7TGRR.cjs} +4 -6
  57. package/dist/lib/node/state-JLN7TGRR.cjs.map +7 -0
  58. package/dist/lib/node/types/index.cjs +18 -12
  59. package/dist/lib/node/types/index.cjs.map +2 -2
  60. package/dist/lib/node-esm/{app-graph-builder-42IGWRPL.mjs → app-graph-builder-OVMSUAX3.mjs} +60 -6
  61. package/dist/lib/node-esm/app-graph-builder-OVMSUAX3.mjs.map +7 -0
  62. package/dist/lib/node-esm/{app-graph-serializer-FXONFKOE.mjs → app-graph-serializer-AZXSO7HK.mjs} +8 -8
  63. package/dist/lib/node-esm/app-graph-serializer-AZXSO7HK.mjs.map +7 -0
  64. package/dist/lib/node-esm/{chunk-FC4UHDPL.mjs → chunk-35OHQARN.mjs} +11 -3
  65. package/dist/lib/node-esm/chunk-35OHQARN.mjs.map +7 -0
  66. package/dist/lib/node-esm/{chunk-BEWBZ4Q4.mjs → chunk-ABKX22IP.mjs} +497 -639
  67. package/dist/lib/node-esm/chunk-ABKX22IP.mjs.map +7 -0
  68. package/dist/lib/node-esm/{chunk-3ZOUV4DF.mjs → chunk-DUA32XUX.mjs} +20 -8
  69. package/dist/lib/node-esm/chunk-DUA32XUX.mjs.map +7 -0
  70. package/dist/lib/node-esm/{chunk-ZGLK25WQ.mjs → chunk-TVN6VHTT.mjs} +60 -141
  71. package/dist/lib/node-esm/chunk-TVN6VHTT.mjs.map +7 -0
  72. package/dist/lib/node-esm/{identity-created-WJKAS2PV.mjs → identity-created-MP4GLXHO.mjs} +4 -4
  73. package/dist/lib/node-esm/identity-created-MP4GLXHO.mjs.map +7 -0
  74. package/dist/lib/node-esm/index.mjs +11 -29
  75. package/dist/lib/node-esm/index.mjs.map +3 -3
  76. package/dist/lib/node-esm/{intent-resolver-ZFNSA4CM.mjs → intent-resolver-SG2ECM5R.mjs} +23 -27
  77. package/dist/lib/node-esm/intent-resolver-SG2ECM5R.mjs.map +7 -0
  78. package/dist/lib/node-esm/meta.json +1 -1
  79. package/dist/lib/node-esm/{react-root-PRBJMWLQ.mjs → react-root-MSUT6S2S.mjs} +4 -4
  80. package/dist/lib/node-esm/{react-surface-RCZG2PNF.mjs → react-surface-G73SO23W.mjs} +139 -48
  81. package/dist/lib/node-esm/react-surface-G73SO23W.mjs.map +7 -0
  82. package/dist/lib/node-esm/{settings-FJZPC2TV.mjs → settings-KCLKPJVY.mjs} +4 -4
  83. package/dist/lib/node-esm/settings-KCLKPJVY.mjs.map +7 -0
  84. package/dist/lib/node-esm/{spaces-ready-7X5PGB2V.mjs → spaces-ready-Z3SXKWX2.mjs} +5 -5
  85. package/dist/lib/node-esm/spaces-ready-Z3SXKWX2.mjs.map +7 -0
  86. package/dist/lib/node-esm/{state-Z6E2YTNC.mjs → state-YZPY5T5A.mjs} +1 -3
  87. package/dist/lib/node-esm/state-YZPY5T5A.mjs.map +7 -0
  88. package/dist/lib/node-esm/types/index.mjs +7 -1
  89. package/dist/types/src/SpacePlugin.d.ts.map +1 -1
  90. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  91. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  92. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  93. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  94. package/dist/types/src/components/CreateDialog/CreateObjectDialog.d.ts +2 -2
  95. package/dist/types/src/components/CreateDialog/CreateObjectDialog.d.ts.map +1 -1
  96. package/dist/types/src/components/CreateDialog/CreateObjectPanel.d.ts.map +1 -1
  97. package/dist/types/src/components/CreateDialog/CreateSpaceDialog.d.ts.map +1 -1
  98. package/dist/types/src/components/MembersContainer.d.ts.map +1 -1
  99. package/dist/types/src/components/ObjectSettings/AdvancedObjectSettings.d.ts.map +1 -0
  100. package/dist/types/src/components/ObjectSettings/BaseObjectSettings.d.ts.map +1 -0
  101. package/dist/types/src/components/ObjectSettings/ForeignKeys.d.ts.map +1 -0
  102. package/dist/types/src/components/ObjectSettings/ObjectSettingsContainer.d.ts.map +1 -0
  103. package/dist/types/src/components/ObjectSettings/index.d.ts.map +1 -0
  104. package/dist/types/src/components/PopoverAddSpace.d.ts.map +1 -1
  105. package/dist/types/src/components/PopoverRenameObject.d.ts +2 -2
  106. package/dist/types/src/components/PopoverRenameObject.d.ts.map +1 -1
  107. package/dist/types/src/components/SchemaContainer.d.ts +13 -0
  108. package/dist/types/src/components/SchemaContainer.d.ts.map +1 -0
  109. package/dist/types/src/components/SpacePluginSettings.d.ts.map +1 -1
  110. package/dist/types/src/components/SpacePresence.d.ts.map +1 -1
  111. package/dist/types/src/components/SpaceSettings/SpaceSettingsContainer.d.ts +0 -2
  112. package/dist/types/src/components/SpaceSettings/SpaceSettingsContainer.d.ts.map +1 -1
  113. package/dist/types/src/components/SpaceSettings/SpaceSettingsContainer.stories.d.ts +7 -0
  114. package/dist/types/src/components/SpaceSettings/SpaceSettingsContainer.stories.d.ts.map +1 -0
  115. package/dist/types/src/components/SpaceSettings/index.d.ts +0 -1
  116. package/dist/types/src/components/SpaceSettings/index.d.ts.map +1 -1
  117. package/dist/types/src/components/SyncStatus/InlineSyncStatus.d.ts.map +1 -1
  118. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts +1 -8
  119. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts.map +1 -1
  120. package/dist/types/src/components/index.d.ts +2 -1
  121. package/dist/types/src/components/index.d.ts.map +1 -1
  122. package/dist/types/src/hooks/index.d.ts +1 -0
  123. package/dist/types/src/hooks/index.d.ts.map +1 -1
  124. package/dist/types/src/hooks/useInputSurfaceLookup.d.ts +14 -0
  125. package/dist/types/src/hooks/useInputSurfaceLookup.d.ts.map +1 -0
  126. package/dist/types/src/translations.d.ts +45 -9
  127. package/dist/types/src/translations.d.ts.map +1 -1
  128. package/dist/types/src/types/types.d.ts +12 -13
  129. package/dist/types/src/types/types.d.ts.map +1 -1
  130. package/dist/types/src/util.d.ts +27 -5
  131. package/dist/types/src/util.d.ts.map +1 -1
  132. package/package.json +44 -43
  133. package/src/SpacePlugin.tsx +2 -12
  134. package/src/capabilities/app-graph-builder.ts +43 -4
  135. package/src/capabilities/app-graph-serializer.ts +4 -4
  136. package/src/capabilities/identity-created.ts +2 -2
  137. package/src/capabilities/intent-resolver.ts +14 -20
  138. package/src/capabilities/react-surface.tsx +120 -38
  139. package/src/capabilities/settings.ts +2 -2
  140. package/src/capabilities/spaces-ready.ts +2 -2
  141. package/src/capabilities/state.ts +0 -2
  142. package/src/components/CreateDialog/CreateObjectDialog.stories.tsx +2 -2
  143. package/src/components/CreateDialog/CreateObjectDialog.tsx +3 -3
  144. package/src/components/CreateDialog/CreateObjectPanel.tsx +3 -25
  145. package/src/components/CreateDialog/CreateSpaceDialog.tsx +4 -0
  146. package/src/components/MembersContainer.tsx +57 -39
  147. package/src/components/PopoverAddSpace.tsx +8 -2
  148. package/src/components/PopoverRenameObject.tsx +2 -2
  149. package/src/components/SchemaContainer.tsx +59 -0
  150. package/src/components/SpacePluginSettings.tsx +27 -2
  151. package/src/components/SpacePresence.tsx +29 -25
  152. package/src/components/SpaceSettings/{SpacePropertiesForm.stories.tsx → SpaceSettingsContainer.stories.tsx} +6 -6
  153. package/src/components/SpaceSettings/SpaceSettingsContainer.tsx +157 -39
  154. package/src/components/SpaceSettings/index.ts +0 -1
  155. package/src/components/SyncStatus/InlineSyncStatus.tsx +5 -7
  156. package/src/components/SyncStatus/SyncStatus.tsx +6 -69
  157. package/src/components/index.ts +2 -1
  158. package/src/hooks/index.ts +1 -0
  159. package/src/hooks/useInputSurfaceLookup.tsx +31 -0
  160. package/src/translations.ts +18 -5
  161. package/src/types/types.ts +8 -7
  162. package/src/util.tsx +43 -103
  163. package/dist/lib/browser/app-graph-builder-GMFCSOLG.mjs.map +0 -7
  164. package/dist/lib/browser/app-graph-serializer-DSF2U3A5.mjs.map +0 -7
  165. package/dist/lib/browser/chunk-5BDV575R.mjs.map +0 -7
  166. package/dist/lib/browser/chunk-AYW4IDRT.mjs.map +0 -7
  167. package/dist/lib/browser/chunk-JZXWPMLA.mjs.map +0 -7
  168. package/dist/lib/browser/chunk-LO5UL6RU.mjs.map +0 -7
  169. package/dist/lib/browser/identity-created-JR7BNXFH.mjs.map +0 -7
  170. package/dist/lib/browser/intent-resolver-RKYILWWQ.mjs.map +0 -7
  171. package/dist/lib/browser/react-surface-7AGLOVMK.mjs.map +0 -7
  172. package/dist/lib/browser/settings-PJPTJUPE.mjs.map +0 -7
  173. package/dist/lib/browser/spaces-ready-BSSP7HHG.mjs.map +0 -7
  174. package/dist/lib/browser/state-X7VLCC6E.mjs.map +0 -7
  175. package/dist/lib/node/app-graph-builder-DPY7AUZE.cjs.map +0 -7
  176. package/dist/lib/node/app-graph-serializer-JELGJUAY.cjs.map +0 -7
  177. package/dist/lib/node/chunk-3GKCNADA.cjs.map +0 -7
  178. package/dist/lib/node/chunk-PU2EYH4E.cjs.map +0 -7
  179. package/dist/lib/node/chunk-TUZWEPGX.cjs.map +0 -7
  180. package/dist/lib/node/chunk-WDEIFDTX.cjs.map +0 -7
  181. package/dist/lib/node/identity-created-XU4HFV2T.cjs.map +0 -7
  182. package/dist/lib/node/intent-resolver-VJ7YV74L.cjs.map +0 -7
  183. package/dist/lib/node/react-surface-2H3S5TY5.cjs.map +0 -7
  184. package/dist/lib/node/settings-WVFP2UEP.cjs.map +0 -7
  185. package/dist/lib/node/spaces-ready-7DNZSUOG.cjs.map +0 -7
  186. package/dist/lib/node/state-5KX6WBJH.cjs.map +0 -7
  187. package/dist/lib/node-esm/app-graph-builder-42IGWRPL.mjs.map +0 -7
  188. package/dist/lib/node-esm/app-graph-serializer-FXONFKOE.mjs.map +0 -7
  189. package/dist/lib/node-esm/chunk-3ZOUV4DF.mjs.map +0 -7
  190. package/dist/lib/node-esm/chunk-BEWBZ4Q4.mjs.map +0 -7
  191. package/dist/lib/node-esm/chunk-FC4UHDPL.mjs.map +0 -7
  192. package/dist/lib/node-esm/chunk-ZGLK25WQ.mjs.map +0 -7
  193. package/dist/lib/node-esm/identity-created-WJKAS2PV.mjs.map +0 -7
  194. package/dist/lib/node-esm/intent-resolver-ZFNSA4CM.mjs.map +0 -7
  195. package/dist/lib/node-esm/react-surface-RCZG2PNF.mjs.map +0 -7
  196. package/dist/lib/node-esm/settings-FJZPC2TV.mjs.map +0 -7
  197. package/dist/lib/node-esm/spaces-ready-7X5PGB2V.mjs.map +0 -7
  198. package/dist/lib/node-esm/state-Z6E2YTNC.mjs.map +0 -7
  199. package/dist/types/src/components/ObjectSettingsContainer/AdvancedObjectSettings.d.ts.map +0 -1
  200. package/dist/types/src/components/ObjectSettingsContainer/BaseObjectSettings.d.ts.map +0 -1
  201. package/dist/types/src/components/ObjectSettingsContainer/ForeignKeys.d.ts.map +0 -1
  202. package/dist/types/src/components/ObjectSettingsContainer/ObjectSettingsContainer.d.ts.map +0 -1
  203. package/dist/types/src/components/ObjectSettingsContainer/index.d.ts.map +0 -1
  204. package/dist/types/src/components/SpaceSettings/SpacePropertiesForm.d.ts +0 -7
  205. package/dist/types/src/components/SpaceSettings/SpacePropertiesForm.d.ts.map +0 -1
  206. package/dist/types/src/components/SpaceSettings/SpacePropertiesForm.stories.d.ts +0 -7
  207. package/dist/types/src/components/SpaceSettings/SpacePropertiesForm.stories.d.ts.map +0 -1
  208. package/dist/types/src/components/SyncStatus/Space.d.ts +0 -13
  209. package/dist/types/src/components/SyncStatus/Space.d.ts.map +0 -1
  210. package/dist/types/src/components/SyncStatus/SyncStatusDetail.stories.d.ts +0 -9
  211. package/dist/types/src/components/SyncStatus/SyncStatusDetail.stories.d.ts.map +0 -1
  212. package/dist/types/src/components/SyncStatus/sync-state.d.ts +0 -18
  213. package/dist/types/src/components/SyncStatus/sync-state.d.ts.map +0 -1
  214. package/src/components/SpaceSettings/SpacePropertiesForm.tsx +0 -136
  215. package/src/components/SyncStatus/Space.tsx +0 -133
  216. package/src/components/SyncStatus/SyncStatusDetail.stories.tsx +0 -89
  217. package/src/components/SyncStatus/sync-state.ts +0 -101
  218. /package/dist/lib/browser/{react-root-6H7NX2M2.mjs.map → react-root-DRVM5ACV.mjs.map} +0 -0
  219. /package/dist/lib/node/{react-root-TEL5RW3N.cjs.map → react-root-6WGN5WRQ.cjs.map} +0 -0
  220. /package/dist/lib/node-esm/{react-root-PRBJMWLQ.mjs.map → react-root-MSUT6S2S.mjs.map} +0 -0
  221. /package/dist/types/src/components/{ObjectSettingsContainer → ObjectSettings}/AdvancedObjectSettings.d.ts +0 -0
  222. /package/dist/types/src/components/{ObjectSettingsContainer → ObjectSettings}/BaseObjectSettings.d.ts +0 -0
  223. /package/dist/types/src/components/{ObjectSettingsContainer → ObjectSettings}/ForeignKeys.d.ts +0 -0
  224. /package/dist/types/src/components/{ObjectSettingsContainer → ObjectSettings}/ObjectSettingsContainer.d.ts +0 -0
  225. /package/dist/types/src/components/{ObjectSettingsContainer → ObjectSettings}/index.d.ts +0 -0
  226. /package/src/components/{ObjectSettingsContainer → ObjectSettings}/AdvancedObjectSettings.tsx +0 -0
  227. /package/src/components/{ObjectSettingsContainer → ObjectSettings}/BaseObjectSettings.tsx +0 -0
  228. /package/src/components/{ObjectSettingsContainer → ObjectSettings}/ForeignKeys.tsx +0 -0
  229. /package/src/components/{ObjectSettingsContainer → ObjectSettings}/ObjectSettingsContainer.tsx +0 -0
  230. /package/src/components/{ObjectSettingsContainer → ObjectSettings}/index.ts +0 -0
@@ -2,62 +2,180 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useMemo } from 'react';
5
+ import { pipe, Schema as S } from 'effect';
6
+ import React, { type ChangeEvent, useCallback, useMemo, useState } from 'react';
6
7
 
7
- import { Surface, useCapabilities, useCapability } from '@dxos/app-framework';
8
- import { type Space } from '@dxos/react-client/echo';
9
- import { toLocalizedString, useTranslation } from '@dxos/react-ui';
10
- import { ControlSectionHeading } from '@dxos/react-ui-form';
11
- import { Accordion } from '@dxos/react-ui-list';
8
+ import { chain, createIntent, LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
9
+ import { log } from '@dxos/log';
10
+ import { EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
11
+ import { useClient } from '@dxos/react-client';
12
+ import { SpaceState, type Space } from '@dxos/react-client/echo';
13
+ import { Button, Input, useMulticastObservable, useTranslation } from '@dxos/react-ui';
14
+ import {
15
+ Form,
16
+ type InputComponent,
17
+ ControlItem,
18
+ ControlItemInput,
19
+ ControlSection,
20
+ ControlPage,
21
+ } from '@dxos/react-ui-form';
22
+ import { HuePicker, IconPicker } from '@dxos/react-ui-pickers';
12
23
  import { StackItem } from '@dxos/react-ui-stack';
13
- import { byPosition } from '@dxos/util';
14
24
 
15
- import { SpaceCapabilities } from '../../capabilities';
16
25
  import { SPACE_PLUGIN } from '../../meta';
26
+ import { SpaceAction, SpaceForm } from '../../types';
17
27
 
18
- export const SPACE_SETTINGS_DIALOG = `${SPACE_PLUGIN}/SpaceSettingsDialog`;
19
-
20
- export type SpaceSettingsTab = 'members' | 'settings';
28
+ const FormSchema = SpaceForm.pipe(S.extend(S.Struct({ archived: S.Boolean.annotations({ title: 'Archive space' }) })));
21
29
 
22
30
  export type SpaceSettingsContainerProps = {
23
31
  space: Space;
24
32
  };
25
33
 
34
+ // TODO(wittjosiah): Handle space migrations here?
26
35
  export const SpaceSettingsContainer = ({ space }: SpaceSettingsContainerProps) => {
27
36
  const { t } = useTranslation(SPACE_PLUGIN);
28
- const state = useCapability(SpaceCapabilities.MutableState);
29
- const items = useCapabilities(SpaceCapabilities.SettingsSection).toSorted(byPosition);
30
- const data = useMemo(() => ({ subject: space }), [space]);
37
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
38
+ const client = useClient();
39
+ const archived = useMulticastObservable(space.state) === SpaceState.SPACE_INACTIVE;
40
+ const [edgeReplication, setEdgeReplication] = useState(
41
+ space.internal.data.edgeReplication === EdgeReplicationSetting.ENABLED,
42
+ );
43
+ const toggleEdgeReplication = useCallback(
44
+ async (next: boolean) => {
45
+ setEdgeReplication(next);
46
+ await space?.internal
47
+ .setEdgeReplicationPreference(next ? EdgeReplicationSetting.ENABLED : EdgeReplicationSetting.DISABLED)
48
+ .catch((err: unknown) => {
49
+ log.catch(err);
50
+ setEdgeReplication(!next);
51
+ });
52
+ },
53
+ [space],
54
+ );
31
55
 
32
- const handleOpenSectionChange = useCallback(
33
- (sections: string[]) => {
34
- state.spaceSettingsOpenSections.splice(0, state.spaceSettingsOpenSections.length, ...sections);
56
+ const handleSave = useCallback(
57
+ (properties: S.Schema.Type<typeof FormSchema>) => {
58
+ void toggleEdgeReplication(properties.edgeReplication);
59
+ if (properties.name !== space.properties.name) {
60
+ space.properties.name = properties.name;
61
+ }
62
+ if (properties.icon !== space.properties.icon) {
63
+ space.properties.icon = properties.icon;
64
+ }
65
+ if (properties.hue !== space.properties.hue) {
66
+ space.properties.hue = properties.hue;
67
+ }
68
+ if (properties.archived && !archived) {
69
+ void dispatch(
70
+ pipe(
71
+ createIntent(SpaceAction.Close, { space }),
72
+ chain(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: client.spaces.default.id }),
73
+ ),
74
+ );
75
+ } else if (!properties.archived && archived) {
76
+ void dispatch(createIntent(SpaceAction.Open, { space }));
77
+ }
35
78
  },
36
- [state],
79
+ [space, toggleEdgeReplication, archived],
80
+ );
81
+
82
+ const values = useMemo(
83
+ () => ({
84
+ name: space.properties.name,
85
+ icon: space.properties.icon,
86
+ hue: space.properties.hue,
87
+ edgeReplication,
88
+ archived,
89
+ }),
90
+ [space.properties.name, space.properties.icon, space.properties.hue, edgeReplication, archived],
91
+ );
92
+
93
+ const customElements: Partial<Record<string, InputComponent>> = useMemo(
94
+ () => ({
95
+ name: ({ type, label, getValue, onValueChange }) => {
96
+ const handleChange = useCallback(
97
+ ({ target: { value } }: ChangeEvent<HTMLInputElement>) => onValueChange(type, value),
98
+ [onValueChange, type],
99
+ );
100
+ return (
101
+ <ControlItemInput title={label} description={t('display name description')}>
102
+ <Input.TextInput
103
+ value={getValue()}
104
+ onChange={handleChange}
105
+ placeholder={t('display name input placeholder')}
106
+ classNames='min-is-64'
107
+ />
108
+ </ControlItemInput>
109
+ );
110
+ },
111
+ icon: ({ type, label, getValue, onValueChange }) => {
112
+ const handleChange = useCallback((nextEmoji: string) => onValueChange(type, nextEmoji), [onValueChange, type]);
113
+ const handleEmojiReset = useCallback(() => onValueChange(type, undefined), [onValueChange, type]);
114
+ return (
115
+ <ControlItem title={label} description={t('icon description')}>
116
+ <IconPicker
117
+ value={getValue()}
118
+ onChange={handleChange}
119
+ onReset={handleEmojiReset}
120
+ classNames='justify-self-end'
121
+ iconSize={5}
122
+ />
123
+ </ControlItem>
124
+ );
125
+ },
126
+ hue: ({ type, label, getValue, onValueChange }) => {
127
+ const handleChange = useCallback((nextHue: string) => onValueChange(type, nextHue), [onValueChange, type]);
128
+ const handleHueReset = useCallback(() => onValueChange(type, undefined), [onValueChange, type]);
129
+ return (
130
+ <ControlItem title={label} description={t('hue description')}>
131
+ <HuePicker
132
+ value={getValue()}
133
+ onChange={handleChange}
134
+ onReset={handleHueReset}
135
+ classNames='[--hue-preview-size:1.25rem] justify-self-end'
136
+ />
137
+ </ControlItem>
138
+ );
139
+ },
140
+ edgeReplication: ({ type, label, getValue, onValueChange }) => {
141
+ const handleChange = useCallback((checked: boolean) => onValueChange(type, checked), [onValueChange, type]);
142
+ return (
143
+ <ControlItemInput title={label} description={t('edge replication description')}>
144
+ <Input.Switch checked={getValue()} onCheckedChange={handleChange} classNames='justify-self-end' />
145
+ </ControlItemInput>
146
+ );
147
+ },
148
+ archived: ({ type, label, getValue, onValueChange }) => {
149
+ const handleChange = useCallback(() => onValueChange(type, !getValue()), [onValueChange, type, getValue]);
150
+ return (
151
+ <ControlItemInput title={label} description={t('archive space description')}>
152
+ <Button disabled={space === client.spaces.default} onClick={handleChange}>
153
+ {getValue() ? t('unarchive space label') : t('archive space label')}
154
+ </Button>
155
+ </ControlItemInput>
156
+ );
157
+ },
158
+ }),
159
+ [t, space],
37
160
  );
38
161
 
39
162
  return (
40
- <StackItem.Content classNames='p-2 block overflow-y-auto'>
41
- <Accordion.Root<SpaceCapabilities.SettingsSection>
42
- items={items}
43
- value={state.spaceSettingsOpenSections}
44
- onValueChange={handleOpenSectionChange}
45
- >
46
- {({ items }) => (
47
- <>
48
- {items.map((item) => (
49
- <Accordion.Item key={item.id} item={item} classNames='container-max-width'>
50
- <Accordion.ItemHeader classNames='pie-6' asChild>
51
- <ControlSectionHeading title={toLocalizedString(item.label, t)} />
52
- </Accordion.ItemHeader>
53
- <Accordion.ItemBody>
54
- <Surface role={`space-settings--${item.id}`} data={data} />
55
- </Accordion.ItemBody>
56
- </Accordion.Item>
57
- ))}
58
- </>
59
- )}
60
- </Accordion.Root>
163
+ <StackItem.Content classNames='block overflow-y-auto pli-2'>
164
+ <ControlPage>
165
+ <ControlSection
166
+ title={t('space properties settings verbose label', { ns: SPACE_PLUGIN })}
167
+ description={t('space properties settings description', { ns: SPACE_PLUGIN })}
168
+ >
169
+ <Form
170
+ schema={FormSchema}
171
+ values={values}
172
+ autoSave
173
+ onSave={handleSave}
174
+ Custom={customElements}
175
+ classNames='p-0 container-max-width [&_[role="form"]]:grid [&_[role="form"]]:grid-cols-1 md:[&_[role="form"]]:grid-cols-[1fr_min-content] [&_[role="form"]]:gap-4'
176
+ />
177
+ </ControlSection>
178
+ </ControlPage>
61
179
  </StackItem.Content>
62
180
  );
63
181
  };
@@ -2,5 +2,4 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './SpacePropertiesForm';
6
5
  export * from './SpaceSettingsContainer';
@@ -5,21 +5,19 @@
5
5
  import React, { useEffect, useState } from 'react';
6
6
 
7
7
  import { useAppGraph } from '@dxos/app-framework';
8
- import { QueryEdgeStatusResponse } from '@dxos/protocols/proto/dxos/client/services';
8
+ import { EdgeStatus } 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';
11
- import { type Space } from '@dxos/react-client/echo';
11
+ import { type Space, useSpaceSyncState } from '@dxos/react-client/echo';
12
12
  import { Tooltip, useTranslation } from '@dxos/react-ui';
13
13
  import { AttentionGlyph, useAttended, useAttention } from '@dxos/react-ui-attention';
14
14
 
15
- import { useSpaceSyncState } from './sync-state';
16
15
  import { usePath } from '../../hooks';
17
16
  import { SPACE_PLUGIN } from '../../meta';
18
17
 
19
- const useEdgeStatus = (): QueryEdgeStatusResponse.EdgeStatus => {
20
- const [status, setStatus] = useState(QueryEdgeStatusResponse.EdgeStatus.NOT_CONNECTED);
18
+ const useEdgeStatus = (): EdgeStatus => {
19
+ const [status, setStatus] = useState(EdgeStatus.NOT_CONNECTED);
21
20
  const client = useClient();
22
-
23
21
  useEffect(() => {
24
22
  client.services.services.EdgeAgentService?.queryEdgeStatus().subscribe(({ status }) => {
25
23
  setStatus(status);
@@ -44,7 +42,7 @@ export const InlineSyncStatus = ({ space, open }: { space: Space; open?: boolean
44
42
  const path = usePath(graph, startOfAttention);
45
43
  const containsAttended = !open && !isAttended && id && path ? path.includes(id) : false;
46
44
 
47
- const connectedToEdge = useEdgeStatus() === QueryEdgeStatusResponse.EdgeStatus.CONNECTED;
45
+ const connectedToEdge = useEdgeStatus() === EdgeStatus.CONNECTED;
48
46
  // TODO(wittjosiah): This is not reactive.
49
47
  const edgeSyncEnabled = space.internal.data.edgeReplication === EdgeReplicationSetting.ENABLED;
50
48
  const syncState = useSpaceSyncState(space);
@@ -2,22 +2,19 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useEffect, useState } from 'react';
5
+ import React, { useEffect, useState } from 'react';
6
6
 
7
7
  import { StatusBar } from '@dxos/plugin-status-bar';
8
8
  import { useClient } from '@dxos/react-client';
9
- import { type SpaceId } from '@dxos/react-client/echo';
10
- import { Icon, Input, Popover, useTranslation } from '@dxos/react-ui';
11
- import { type ThemedClassName } from '@dxos/react-ui';
12
- import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
13
- import { mx } from '@dxos/react-ui-theme';
9
+ import { getSyncSummary, type SpaceSyncStateMap, useSyncState } from '@dxos/react-client/echo';
10
+ import { Icon, useTranslation } from '@dxos/react-ui';
14
11
 
15
- import { SpaceRowContainer, SYNC_STALLED_TIMEOUT } from './Space';
16
12
  import { createClientSaveTracker } from './save-tracker';
17
13
  import { getIcon, getStatus } from './status';
18
- import { type PeerSyncState, type SpaceSyncStateMap, getSyncSummary, useSyncState } from './sync-state';
19
14
  import { SPACE_PLUGIN } from '../../meta';
20
15
 
16
+ const SYNC_STALLED_TIMEOUT = 5_000;
17
+
21
18
  export const SyncStatus = () => {
22
19
  const client = useClient();
23
20
  const state = useSyncState();
@@ -57,65 +54,5 @@ export const SyncStatusIndicator = ({ state, saved }: { state: SpaceSyncStateMap
57
54
  const title = t(`${status} label`);
58
55
  const icon = <Icon icon={getIcon(status)} size={4} classNames={classNames} />;
59
56
 
60
- if (offline) {
61
- return <StatusBar.Item title={title}>{icon}</StatusBar.Item>;
62
- } else {
63
- return (
64
- <Popover.Root>
65
- <Popover.Trigger asChild>
66
- <StatusBar.Button title={title}>{icon}</StatusBar.Button>
67
- </Popover.Trigger>
68
- <Popover.Portal>
69
- <Popover.Content>
70
- <SyncStatusDetail state={state} summary={summary} debug={false} />
71
- <Popover.Arrow />
72
- </Popover.Content>
73
- </Popover.Portal>
74
- </Popover.Root>
75
- );
76
- }
77
- };
78
-
79
- export type SyncStatusDetailProps = ThemedClassName<{
80
- state: SpaceSyncStateMap;
81
- summary: PeerSyncState;
82
- debug?: boolean;
83
- }>;
84
-
85
- // TODO(wittjosiah): This currently does not show `differentDocuments` at all.
86
- export const SyncStatusDetail = ({ classNames, state, summary, debug }: SyncStatusDetailProps) => {
87
- const [showAll, setShowAll] = useState(false);
88
- const { t } = useTranslation(SPACE_PLUGIN);
89
- const entries = Object.entries(state)
90
- .filter(([_, value]) => showAll || value.missingOnLocal + value.missingOnRemote > 0)
91
- .toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
92
-
93
- const handleCheckedChange = useCallback((state: boolean) => setShowAll(state), [setShowAll]);
94
-
95
- // TODO(burdon): Normalize to max document count?
96
- return (
97
- <div className={mx('flex flex-col gap-3 p-2 text-xs min-w-[400px]', classNames)}>
98
- <div role='none' className='flex items-center'>
99
- <h1 className='flex-1'>{t('sync status title')}</h1>
100
- <div className='flex items-center gap-2'>
101
- <Input.Root>
102
- <Input.Label classNames='text-xs'>{t('show all label')}</Input.Label>
103
- <Input.Checkbox checked={showAll} onCheckedChange={handleCheckedChange} />
104
- </Input.Root>
105
- </div>
106
- </div>
107
- <div className='flex flex-col gap-2'>
108
- {entries.length === 0 && (
109
- <div role='none' className='flex justify-center'>
110
- {/* TODO(wittjosiah): This text should be updated once status includes different documents. */}
111
- {t('no sync status label')}
112
- </div>
113
- )}
114
- {entries.map(([spaceId, state]) => (
115
- <SpaceRowContainer key={spaceId} spaceId={spaceId as SpaceId} state={state} />
116
- ))}
117
- </div>
118
- {debug && <SyntaxHighlighter language='json'>{JSON.stringify(summary, null, 2)}</SyntaxHighlighter>}
119
- </div>
120
- );
57
+ return <StatusBar.Item title={title}>{icon}</StatusBar.Item>;
121
58
  };
@@ -9,11 +9,12 @@ export * from './CollectionSection';
9
9
  export * from './JoinDialog';
10
10
  export * from './MembersContainer';
11
11
  export * from './MenuFooter';
12
- export * from './ObjectSettingsContainer';
12
+ export * from './ObjectSettings';
13
13
  export * from './PersistenceStatus';
14
14
  export * from './PopoverAddSpace';
15
15
  export * from './PopoverRenameObject';
16
16
  export * from './PopoverRenameSpace';
17
+ export * from './SchemaContainer';
17
18
  export * from './ShareSpaceButton';
18
19
  export * from './SpacePresence';
19
20
  export * from './SpacePluginSettings';
@@ -2,4 +2,5 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ export * from './useInputSurfaceLookup';
5
6
  export * from './usePath';
@@ -0,0 +1,31 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Schema as S } from 'effect';
6
+ import React, { useCallback } from 'react';
7
+
8
+ import { usePluginManager, isSurfaceAvailable, Surface } from '@dxos/app-framework';
9
+ import { type InputProps } from '@dxos/react-ui-form';
10
+
11
+ // TODO(ZaymonFC): Move this if you find yourself needing it elsewhere.
12
+ /**
13
+ * Creates a surface input component based on plugin context.
14
+ * @param baseData Additional data that will be merged with form data and passed to the surface.
15
+ * This allows providing more context to the surface than what's available from the form itself.
16
+ */
17
+ export const useInputSurfaceLookup = (baseData?: Record<string, any>) => {
18
+ const pluginManager = usePluginManager();
19
+
20
+ return useCallback(
21
+ ({ prop, schema, inputProps }: { prop: string; schema: S.Schema<any>; inputProps: InputProps }) => {
22
+ const composedData = { prop, schema, ...baseData };
23
+ if (!isSurfaceAvailable(pluginManager.context, { role: 'form-input', data: composedData })) {
24
+ return undefined;
25
+ }
26
+
27
+ return <Surface role='form-input' data={composedData} {...inputProps} />;
28
+ },
29
+ [pluginManager, baseData],
30
+ );
31
+ };
@@ -34,7 +34,7 @@ export default [
34
34
  'export data label': 'Export data',
35
35
  'import data label': 'Import data',
36
36
  'migrate space label': 'Migrate space',
37
- 'share space': 'Share space',
37
+ 'share space label': 'Share current space',
38
38
  'save space to disk label': 'Save to disk',
39
39
  'load space from disk label': 'Load from disk',
40
40
  'confirm restore title': 'Overwrite files in this space?',
@@ -43,7 +43,7 @@ export default [
43
43
  'object placeholder': 'Type a title here…',
44
44
  'personal space label': 'Personal Space',
45
45
  'spaces label': 'Spaces',
46
- 'show hidden spaces label': 'Show closed spaces',
46
+ 'show hidden spaces label': 'Show archived spaces',
47
47
  'save files to directory label': 'Save files to disk',
48
48
  'select path label': 'Select path',
49
49
  'rename collection label': 'Rename collection',
@@ -67,7 +67,6 @@ export default [
67
67
  'The requested object has not been found yet. Ensure there are enough peers online in the space with an updated copy.',
68
68
  'create object in space label': 'Add to space',
69
69
  'create object in collection label': 'Add to collection',
70
- 'share space label': 'Share',
71
70
  'space members label': 'Space members',
72
71
  'active space members heading': 'Online ({{count}})',
73
72
  'inactive space members heading': 'Offline ({{count}})',
@@ -118,6 +117,7 @@ export default [
118
117
  'advanced settings label': 'Advanced',
119
118
  'foreign keys': 'Foreign Keys',
120
119
  'add key': 'Add Key',
120
+ 'open space settings label': 'Open',
121
121
 
122
122
  'members panel label': 'Members',
123
123
  'members verbose label': 'Manage space members',
@@ -126,16 +126,29 @@ export default [
126
126
  'invitations label': 'Invitations',
127
127
  'space invitation description': 'Manage invitations to the space.',
128
128
  'qr code description': 'Share this QR code, or copy the URL and share it with the person you want to invite.',
129
+ 'locked space description': 'This space is locked, unlock it to invite new members.',
130
+ 'space locked label': 'Lock space',
131
+ 'space locked description': 'Locking a space prevents new members from being invited to the space.',
129
132
 
130
133
  'settings panel label': 'Space Settings',
131
- 'open space settings label': 'Space Settings',
132
- 'space settings properties label': 'General',
134
+ 'open current space settings label': 'Open current space settings',
135
+ 'space settings properties label': 'General settings',
136
+ 'space properties settings verbose label': 'Manage space properties',
137
+ 'space properties settings description': 'You can configure how this space is displayed in the app here.',
138
+ 'space settings schema label': 'Schema',
139
+ 'schema verbose label': 'Manage schema',
140
+ 'schema description': 'You can manage all of the schema stored within this space here.',
141
+ 'no schemas found message': 'No schemas found',
133
142
  'display name input placeholder': 'Space name',
134
143
  'display name description': 'Name of the space as it appears in the app.',
135
144
  'icon description': 'Icon used to represent the space in the app.',
136
145
  'hue description': 'Color used to represent the space in the app.',
137
146
  'edge replication description':
138
147
  "Only change this if you know what you're doing. Disabling this will prevent the space from replicating through Composer's EDGE services, and relies solely on peer-to-peer sync.",
148
+ 'archive space description':
149
+ 'Archiving a space will remove it from the sidebar and stop replicating updates, but will not delete the data. You can unarchive it by enabling archived spaces in the app settings.',
150
+ 'archive space label': 'Archive',
151
+ 'unarchive space label': 'Unarchive',
139
152
  },
140
153
  },
141
154
  },
@@ -13,6 +13,7 @@ import { CollectionType } from './collection';
13
13
  import { SPACE_PLUGIN } from '../meta';
14
14
 
15
15
  export const SPACE_DIRECTORY_HANDLE = 'dxos.org/plugin/space/directory';
16
+ export const SPACE_TYPE = 'dxos.org/type/Space';
16
17
 
17
18
  export type ObjectViewerProps = {
18
19
  lastSeen: number;
@@ -42,11 +43,6 @@ export type PluginState = {
42
43
  */
43
44
  spaceNames: Record<string, string>;
44
45
 
45
- /**
46
- * Which sections of the space settings are open.
47
- */
48
- spaceSettingsOpenSections: string[];
49
-
50
46
  /**
51
47
  * Which spaces have an SDK migration running currently.
52
48
  */
@@ -92,10 +88,14 @@ export interface TypedObjectSerializer<T extends Expando = Expando> {
92
88
  deserialize(params: { content: string; space: Space; newId?: boolean }): Promise<T>;
93
89
  }
94
90
 
91
+ // TODO(burdon): Move to FormatEnum or SDK.
92
+ export const IconAnnotationId = Symbol.for('@dxos/plugin-space/annotation/Icon');
93
+ export const HueAnnotationId = Symbol.for('@dxos/plugin-space/annotation/Hue');
94
+
95
95
  export const SpaceForm = S.Struct({
96
96
  name: S.optional(S.String.annotations({ title: 'Name' })),
97
- icon: S.optional(S.String.annotations({ title: 'Icon' })),
98
- hue: S.optional(S.String.annotations({ title: 'Color' })),
97
+ icon: S.optional(S.String.annotations({ title: 'Icon', [IconAnnotationId]: true })),
98
+ hue: S.optional(S.String.annotations({ title: 'Color', [HueAnnotationId]: true })),
99
99
  // TODO(wittjosiah): Make optional with default value.
100
100
  edgeReplication: S.Boolean.annotations({ title: 'Enable EDGE Replication' }),
101
101
  });
@@ -175,6 +175,7 @@ export namespace SpaceAction {
175
175
  }) {}
176
176
 
177
177
  // TODO(wittjosiah): Handle scrolling to section.
178
+ // This maybe motivates making the space settings its own deck?
178
179
  export class OpenSettings extends S.TaggedClass<OpenSettings>()(`${SPACE_ACTION}/open-settings`, {
179
180
  input: S.Struct({ space: SpaceSchema }),
180
181
  output: S.Void,