@dxos/plugin-space 0.8.4-main.84f28bd → 0.8.4-main.c1de068

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 (145) hide show
  1. package/dist/lib/browser/CollectionMain-D2B75XBS.mjs +31 -0
  2. package/dist/lib/browser/CollectionMain-D2B75XBS.mjs.map +7 -0
  3. package/dist/lib/browser/ObjectDetailsPanel-YPTDQKMG.mjs +88 -0
  4. package/dist/lib/browser/ObjectDetailsPanel-YPTDQKMG.mjs.map +7 -0
  5. package/dist/lib/browser/{app-graph-builder-PMDF6PJV.mjs → app-graph-builder-7CZZJS3S.mjs} +138 -22
  6. package/dist/lib/browser/app-graph-builder-7CZZJS3S.mjs.map +7 -0
  7. package/dist/lib/browser/{app-graph-serializer-UKYMBX4O.mjs → app-graph-serializer-H6AW7KGS.mjs} +4 -4
  8. package/dist/lib/browser/{chunk-XXIPJLJF.mjs → chunk-CEFHNVU7.mjs} +2 -1
  9. package/dist/lib/browser/chunk-CEFHNVU7.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-C7KGJTAL.mjs → chunk-JS3MMC42.mjs} +2 -1
  11. package/dist/lib/browser/{chunk-C7KGJTAL.mjs.map → chunk-JS3MMC42.mjs.map} +3 -3
  12. package/dist/lib/browser/{chunk-6VLSHG4A.mjs → chunk-QACNNDOT.mjs} +64 -3
  13. package/dist/lib/browser/chunk-QACNNDOT.mjs.map +7 -0
  14. package/dist/lib/browser/{chunk-S6NY637J.mjs → chunk-SGTQ52SU.mjs} +57 -3
  15. package/dist/lib/browser/chunk-SGTQ52SU.mjs.map +7 -0
  16. package/dist/lib/browser/{chunk-GVTXQCIW.mjs → chunk-V7MJSSBQ.mjs} +355 -286
  17. package/dist/lib/browser/chunk-V7MJSSBQ.mjs.map +7 -0
  18. package/dist/lib/browser/{chunk-WBSEOLEM.mjs → chunk-XUYKJUU7.mjs} +124 -21
  19. package/dist/lib/browser/chunk-XUYKJUU7.mjs.map +7 -0
  20. package/dist/lib/browser/index.mjs +98 -9
  21. package/dist/lib/browser/index.mjs.map +3 -3
  22. package/dist/lib/browser/{intent-resolver-WK5WYFH3.mjs → intent-resolver-TIXVDYN7.mjs} +164 -14
  23. package/dist/lib/browser/intent-resolver-TIXVDYN7.mjs.map +7 -0
  24. package/dist/lib/browser/meta.json +1 -1
  25. package/dist/lib/browser/{react-root-7S6FIC5G.mjs → react-root-N2J7TDRX.mjs} +5 -5
  26. package/dist/lib/browser/{react-surface-6C3YJNDK.mjs → react-surface-TPNLWJJH.mjs} +35 -14
  27. package/dist/lib/browser/react-surface-TPNLWJJH.mjs.map +7 -0
  28. package/dist/lib/browser/{schema-defs-K3B3OAH4.mjs → schema-defs-Z6FC4AHC.mjs} +2 -2
  29. package/dist/lib/browser/{settings-XNWYRWNM.mjs → settings-4IMP5RYT.mjs} +2 -2
  30. package/dist/lib/browser/{spaces-ready-K7NSNBHM.mjs → spaces-ready-TOPG6IV4.mjs} +4 -4
  31. package/dist/lib/browser/{state-522XTUR4.mjs → state-QYZAB45H.mjs} +2 -2
  32. package/dist/lib/browser/types/index.mjs +1 -1
  33. package/dist/lib/node-esm/CollectionMain-ZJIFCWKZ.mjs +32 -0
  34. package/dist/lib/node-esm/CollectionMain-ZJIFCWKZ.mjs.map +7 -0
  35. package/dist/lib/node-esm/ObjectDetailsPanel-QKZEDSZK.mjs +89 -0
  36. package/dist/lib/node-esm/ObjectDetailsPanel-QKZEDSZK.mjs.map +7 -0
  37. package/dist/lib/node-esm/{app-graph-builder-TO72W6MI.mjs → app-graph-builder-KGIGWC72.mjs} +138 -22
  38. package/dist/lib/node-esm/app-graph-builder-KGIGWC72.mjs.map +7 -0
  39. package/dist/lib/node-esm/{app-graph-serializer-LA3IZDXJ.mjs → app-graph-serializer-2ICUGQQT.mjs} +4 -4
  40. package/dist/lib/node-esm/{chunk-HJJHLWKY.mjs → chunk-4AOMYKDE.mjs} +124 -21
  41. package/dist/lib/node-esm/chunk-4AOMYKDE.mjs.map +7 -0
  42. package/dist/lib/node-esm/{chunk-72QMMRKC.mjs → chunk-5HHYE264.mjs} +2 -1
  43. package/dist/lib/node-esm/{chunk-72QMMRKC.mjs.map → chunk-5HHYE264.mjs.map} +3 -3
  44. package/dist/lib/node-esm/{chunk-AT7LGFER.mjs → chunk-5T3ZH23B.mjs} +2 -1
  45. package/dist/lib/node-esm/chunk-5T3ZH23B.mjs.map +7 -0
  46. package/dist/lib/node-esm/{chunk-OUBADVJE.mjs → chunk-6X5DLJM5.mjs} +355 -286
  47. package/dist/lib/node-esm/chunk-6X5DLJM5.mjs.map +7 -0
  48. package/dist/lib/node-esm/{chunk-2THX6G4C.mjs → chunk-JH6F4C3I.mjs} +57 -3
  49. package/dist/lib/node-esm/chunk-JH6F4C3I.mjs.map +7 -0
  50. package/dist/lib/node-esm/{chunk-SXD6T2N4.mjs → chunk-P442DOQ3.mjs} +64 -3
  51. package/dist/lib/node-esm/chunk-P442DOQ3.mjs.map +7 -0
  52. package/dist/lib/node-esm/index.mjs +98 -9
  53. package/dist/lib/node-esm/index.mjs.map +3 -3
  54. package/dist/lib/node-esm/{intent-resolver-HSR27ME4.mjs → intent-resolver-MHGHRGDT.mjs} +164 -14
  55. package/dist/lib/node-esm/intent-resolver-MHGHRGDT.mjs.map +7 -0
  56. package/dist/lib/node-esm/meta.json +1 -1
  57. package/dist/lib/node-esm/{react-root-HUK3ANLV.mjs → react-root-KW3TGJGY.mjs} +5 -5
  58. package/dist/lib/node-esm/{react-surface-AGAWX7DD.mjs → react-surface-UUIUUD6P.mjs} +35 -14
  59. package/dist/lib/node-esm/react-surface-UUIUUD6P.mjs.map +7 -0
  60. package/dist/lib/node-esm/{schema-defs-4MCDG4DV.mjs → schema-defs-WHJM7UZE.mjs} +2 -2
  61. package/dist/lib/node-esm/{settings-YGKHGFPH.mjs → settings-SAOBPND3.mjs} +2 -2
  62. package/dist/lib/node-esm/{spaces-ready-UM2P3DCR.mjs → spaces-ready-HIUKNDZK.mjs} +4 -4
  63. package/dist/lib/node-esm/{state-C4IOXPZP.mjs → state-ZVEHQ4BJ.mjs} +2 -2
  64. package/dist/lib/node-esm/types/index.mjs +1 -1
  65. package/dist/types/src/SpacePlugin.d.ts.map +1 -1
  66. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  67. package/dist/types/src/capabilities/capabilities.d.ts +9 -3
  68. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  69. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  70. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  71. package/dist/types/src/components/AwaitingObject.d.ts.map +1 -1
  72. package/dist/types/src/components/CollectionMain.d.ts +1 -0
  73. package/dist/types/src/components/CollectionMain.d.ts.map +1 -1
  74. package/dist/types/src/components/CreateDialog/CreateObjectDialog.d.ts +3 -2
  75. package/dist/types/src/components/CreateDialog/CreateObjectDialog.d.ts.map +1 -1
  76. package/dist/types/src/components/MembersContainer.d.ts.map +1 -1
  77. package/dist/types/src/components/MenuFooter.d.ts.map +1 -1
  78. package/dist/types/src/components/ObjectDetailsPanel.d.ts +9 -0
  79. package/dist/types/src/components/ObjectDetailsPanel.d.ts.map +1 -0
  80. package/dist/types/src/components/PersistenceStatus.d.ts.map +1 -1
  81. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts +1 -1
  82. package/dist/types/src/components/SyncStatus/status.d.ts +5 -5
  83. package/dist/types/src/components/ViewEditor.d.ts +8 -0
  84. package/dist/types/src/components/ViewEditor.d.ts.map +1 -0
  85. package/dist/types/src/components/index.d.ts +8 -1
  86. package/dist/types/src/components/index.d.ts.map +1 -1
  87. package/dist/types/src/events.d.ts +1 -0
  88. package/dist/types/src/events.d.ts.map +1 -1
  89. package/dist/types/src/translations.d.ts +61 -0
  90. package/dist/types/src/translations.d.ts.map +1 -1
  91. package/dist/types/src/types/types.d.ts +82 -2
  92. package/dist/types/src/types/types.d.ts.map +1 -1
  93. package/dist/types/src/util.d.ts +27 -2
  94. package/dist/types/src/util.d.ts.map +1 -1
  95. package/dist/types/tsconfig.tsbuildinfo +1 -1
  96. package/package.json +47 -49
  97. package/src/SpacePlugin.ts +87 -4
  98. package/src/capabilities/app-graph-builder.ts +165 -5
  99. package/src/capabilities/capabilities.ts +8 -3
  100. package/src/capabilities/intent-resolver.ts +114 -5
  101. package/src/capabilities/react-surface.tsx +47 -10
  102. package/src/components/AwaitingObject.tsx +4 -6
  103. package/src/components/CollectionMain.tsx +2 -0
  104. package/src/components/CreateDialog/CreateObjectDialog.tsx +29 -25
  105. package/src/components/MembersContainer.tsx +5 -3
  106. package/src/components/MenuFooter.tsx +2 -3
  107. package/src/components/ObjectDetailsPanel.tsx +77 -0
  108. package/src/components/PersistenceStatus.tsx +5 -6
  109. package/src/components/PopoverRenameObject.tsx +2 -2
  110. package/src/components/SyncStatus/SyncStatus.tsx +1 -1
  111. package/src/components/SyncStatus/status.ts +4 -4
  112. package/src/components/ViewEditor.tsx +64 -0
  113. package/src/components/index.ts +6 -1
  114. package/src/events.ts +1 -0
  115. package/src/translations.ts +62 -0
  116. package/src/types/types.ts +56 -3
  117. package/src/util.tsx +115 -20
  118. package/dist/lib/browser/app-graph-builder-PMDF6PJV.mjs.map +0 -7
  119. package/dist/lib/browser/chunk-6VLSHG4A.mjs.map +0 -7
  120. package/dist/lib/browser/chunk-GVTXQCIW.mjs.map +0 -7
  121. package/dist/lib/browser/chunk-S6NY637J.mjs.map +0 -7
  122. package/dist/lib/browser/chunk-WBSEOLEM.mjs.map +0 -7
  123. package/dist/lib/browser/chunk-XXIPJLJF.mjs.map +0 -7
  124. package/dist/lib/browser/intent-resolver-WK5WYFH3.mjs.map +0 -7
  125. package/dist/lib/browser/react-surface-6C3YJNDK.mjs.map +0 -7
  126. package/dist/lib/node-esm/app-graph-builder-TO72W6MI.mjs.map +0 -7
  127. package/dist/lib/node-esm/chunk-2THX6G4C.mjs.map +0 -7
  128. package/dist/lib/node-esm/chunk-AT7LGFER.mjs.map +0 -7
  129. package/dist/lib/node-esm/chunk-HJJHLWKY.mjs.map +0 -7
  130. package/dist/lib/node-esm/chunk-OUBADVJE.mjs.map +0 -7
  131. package/dist/lib/node-esm/chunk-SXD6T2N4.mjs.map +0 -7
  132. package/dist/lib/node-esm/intent-resolver-HSR27ME4.mjs.map +0 -7
  133. package/dist/lib/node-esm/react-surface-AGAWX7DD.mjs.map +0 -7
  134. /package/dist/lib/browser/{app-graph-serializer-UKYMBX4O.mjs.map → app-graph-serializer-H6AW7KGS.mjs.map} +0 -0
  135. /package/dist/lib/browser/{react-root-7S6FIC5G.mjs.map → react-root-N2J7TDRX.mjs.map} +0 -0
  136. /package/dist/lib/browser/{schema-defs-K3B3OAH4.mjs.map → schema-defs-Z6FC4AHC.mjs.map} +0 -0
  137. /package/dist/lib/browser/{settings-XNWYRWNM.mjs.map → settings-4IMP5RYT.mjs.map} +0 -0
  138. /package/dist/lib/browser/{spaces-ready-K7NSNBHM.mjs.map → spaces-ready-TOPG6IV4.mjs.map} +0 -0
  139. /package/dist/lib/browser/{state-522XTUR4.mjs.map → state-QYZAB45H.mjs.map} +0 -0
  140. /package/dist/lib/node-esm/{app-graph-serializer-LA3IZDXJ.mjs.map → app-graph-serializer-2ICUGQQT.mjs.map} +0 -0
  141. /package/dist/lib/node-esm/{react-root-HUK3ANLV.mjs.map → react-root-KW3TGJGY.mjs.map} +0 -0
  142. /package/dist/lib/node-esm/{schema-defs-4MCDG4DV.mjs.map → schema-defs-WHJM7UZE.mjs.map} +0 -0
  143. /package/dist/lib/node-esm/{settings-YGKHGFPH.mjs.map → settings-SAOBPND3.mjs.map} +0 -0
  144. /package/dist/lib/node-esm/{spaces-ready-UM2P3DCR.mjs.map → spaces-ready-HIUKNDZK.mjs.map} +0 -0
  145. /package/dist/lib/node-esm/{state-C4IOXPZP.mjs.map → state-ZVEHQ4BJ.mjs.map} +0 -0
@@ -19,7 +19,16 @@ import { findAnnotation } from '@dxos/effect';
19
19
  import { SettingsStore } from '@dxos/local-storage';
20
20
  import { ClientCapabilities } from '@dxos/plugin-client';
21
21
  import { useClient } from '@dxos/react-client';
22
- import { getSpace, isLiveObject, isSpace, parseId, SpaceState, useSpace, type Space } from '@dxos/react-client/echo';
22
+ import {
23
+ fullyQualifiedId,
24
+ getSpace,
25
+ isLiveObject,
26
+ isSpace,
27
+ parseId,
28
+ SpaceState,
29
+ useSpace,
30
+ type Space,
31
+ } from '@dxos/react-client/echo';
23
32
  import { Input, useTranslation } from '@dxos/react-ui';
24
33
  import { type InputProps, SelectInput } from '@dxos/react-ui-form';
25
34
  import { HuePicker, IconPicker } from '@dxos/react-ui-pickers';
@@ -39,6 +48,7 @@ import {
39
48
  JoinDialog,
40
49
  MembersContainer,
41
50
  MenuFooter,
51
+ ObjectDetailsPanel,
42
52
  ObjectSettingsContainer,
43
53
  POPOVER_RENAME_OBJECT,
44
54
  POPOVER_RENAME_SPACE,
@@ -50,6 +60,7 @@ import {
50
60
  SpacePresence,
51
61
  SpaceSettingsContainer,
52
62
  SyncStatus,
63
+ ViewEditor,
53
64
  type CreateObjectDialogProps,
54
65
  } from '../components';
55
66
  import { SPACE_PLUGIN } from '../meta';
@@ -146,6 +157,19 @@ export default ({ createInvitationUrl }: ReactSurfaceOptions) =>
146
157
  return <SchemaContainer space={space} />;
147
158
  },
148
159
  }),
160
+ createSurface({
161
+ id: `${SPACE_PLUGIN}/selected-objects`,
162
+ role: 'article',
163
+ filter: (data): data is { companionTo: DataType.View; subject: 'selected-objects' } =>
164
+ Obj.instanceOf(DataType.View, data.companionTo) && data.subject === 'selected-objects',
165
+ component: ({ data }) => (
166
+ <ObjectDetailsPanel
167
+ key={fullyQualifiedId(data.companionTo)}
168
+ objectId={fullyQualifiedId(data.companionTo)}
169
+ view={data.companionTo}
170
+ />
171
+ ),
172
+ }),
149
173
  createSurface({
150
174
  id: JOIN_DIALOG,
151
175
  role: 'dialog',
@@ -228,7 +252,7 @@ export default ({ createInvitationUrl }: ReactSurfaceOptions) =>
228
252
 
229
253
  const schemaWhitelists = useCapabilities(ClientCapabilities.SchemaWhiteList);
230
254
  const whitelistedTypenames = useMemo(
231
- () => new Set(schemaWhitelists.flatMap((typeArray) => typeArray.map((type) => type.typename))),
255
+ () => new Set(schemaWhitelists.flatMap((typeArray) => typeArray.map((type) => Type.getTypename(type)))),
232
256
  [schemaWhitelists],
233
257
  );
234
258
 
@@ -239,7 +263,7 @@ export default ({ createInvitationUrl }: ReactSurfaceOptions) =>
239
263
  objectForms
240
264
  .map((form) => Type.getTypename(form.objectSchema))
241
265
  // TODO(wittjosiah): Remove.
242
- .filter((typename) => !OMIT.includes(typename)),
266
+ .filter((typename) => !OMIT.includes(typename) && !typename.endsWith('View')),
243
267
  ),
244
268
  [objectForms],
245
269
  );
@@ -247,13 +271,18 @@ export default ({ createInvitationUrl }: ReactSurfaceOptions) =>
247
271
  const fixed = client.graph.schemaRegistry.schemas.filter((schema) => {
248
272
  const limitedStatic =
249
273
  annotation.includes('limited-static') && whitelistedTypenames.has(Type.getTypename(schema));
274
+ const unusedStatic =
275
+ annotation.includes('unused-static') &&
276
+ whitelistedTypenames.has(Type.getTypename(schema)) &&
277
+ !space.properties.staticRecords?.includes(Type.getTypename(schema));
250
278
  const objectForm = annotation.includes('object-form') && objectFormTypenames.has(Type.getTypename(schema));
251
- return annotation.includes('static') || limitedStatic || objectForm;
279
+ return annotation.includes('static') || limitedStatic || unusedStatic || objectForm;
252
280
  });
253
281
  const dynamic = space?.db.schemaRegistry.query().runSync();
254
282
  const typenames = Array.from(
255
283
  new Set<string>([
256
284
  ...(annotation.includes('limited-static') ||
285
+ annotation.includes('unused-static') ||
257
286
  annotation.includes('static') ||
258
287
  annotation.includes('object-form')
259
288
  ? fixed.map((schema) => Type.getTypename(schema))
@@ -264,25 +293,33 @@ export default ({ createInvitationUrl }: ReactSurfaceOptions) =>
264
293
 
265
294
  const options = useMemo(
266
295
  () =>
267
- typenames.map((typename) => ({
268
- value: typename,
269
- label: t('typename label', { ns: typename, defaultValue: typename }),
270
- })),
296
+ typenames
297
+ .map((typename) => ({
298
+ value: typename,
299
+ label: t('typename label', { ns: typename, defaultValue: typename }),
300
+ }))
301
+ .toSorted((a, b) => a.label.localeCompare(b.label)),
271
302
  [t, typenames],
272
303
  );
273
304
 
274
305
  return <SelectInput {...props} options={options} />;
275
306
  },
276
307
  }),
308
+ createSurface({
309
+ id: `${SPACE_PLUGIN}/object-settings`,
310
+ role: 'object-settings',
311
+ filter: (data): data is { subject: DataType.View } => Obj.instanceOf(DataType.View, data.subject),
312
+ component: ({ data }) => <ViewEditor view={data.subject} />,
313
+ }),
277
314
  createSurface({
278
315
  id: POPOVER_RENAME_SPACE,
279
- role: 'popover',
316
+ role: 'card--popover',
280
317
  filter: (data): data is { props: Space } => data.component === POPOVER_RENAME_SPACE && isSpace(data.props),
281
318
  component: ({ data }) => <PopoverRenameSpace space={data.props} />,
282
319
  }),
283
320
  createSurface({
284
321
  id: POPOVER_RENAME_OBJECT,
285
- role: 'popover',
322
+ role: 'card--popover',
286
323
  filter: (data): data is { props: Obj.Any } =>
287
324
  data.component === POPOVER_RENAME_OBJECT && isLiveObject(data.props),
288
325
  component: ({ data }) => <PopoverRenameObject object={data.props} />,
@@ -2,14 +2,12 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { CheckCircle, CircleDashed, CircleNotch } from '@phosphor-icons/react';
6
5
  import React, { useCallback, useEffect, useState } from 'react';
7
6
 
8
7
  import { createIntent, LayoutAction, useIntentDispatcher, useLayout } from '@dxos/app-framework';
9
8
  import { useClient } from '@dxos/react-client';
10
9
  import { Filter, fullyQualifiedId, useQuery } from '@dxos/react-client/echo';
11
- import { Button, Toast, useTranslation } from '@dxos/react-ui';
12
- import { getSize, mx } from '@dxos/react-ui-theme';
10
+ import { Button, Icon, Toast, useTranslation } from '@dxos/react-ui';
13
11
 
14
12
  import { SPACE_PLUGIN } from '../meta';
15
13
  import { SpaceAction } from '../types';
@@ -66,17 +64,17 @@ export const AwaitingObject = ({ id }: { id: string }) => {
66
64
  <Toast.Title classNames='flex items-center gap-2'>
67
65
  {found ? (
68
66
  <>
69
- <CheckCircle className={getSize(5)} />
67
+ <Icon icon='ph--check-circle--regular' size={5} />
70
68
  <span>{t('found object label')}</span>
71
69
  </>
72
70
  ) : waiting ? (
73
71
  <>
74
- <CircleNotch className={mx(getSize(5), 'animate-spin')} />
72
+ <Icon icon='ph--circle-notch--regular' size={5} classNames='animate-spin' />
75
73
  <span>{t('waiting for object label')}</span>
76
74
  </>
77
75
  ) : (
78
76
  <>
79
- <CircleDashed className={getSize(5)} />
77
+ <Icon icon='ph--circle-dashed--regular' size={5} />
80
78
  <span>{t('object not found label')}</span>
81
79
  </>
82
80
  )}
@@ -28,3 +28,5 @@ export const CollectionMain = ({ collection }: { collection: DataType.Collection
28
28
  </div>
29
29
  );
30
30
  };
31
+
32
+ export default CollectionMain;
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { pipe } from 'effect';
5
+ import { Effect, pipe } from 'effect';
6
6
  import React, { useCallback, useRef, useState } from 'react';
7
7
 
8
8
  import {
@@ -14,7 +14,7 @@ import {
14
14
  useIntentDispatcher,
15
15
  usePluginManager,
16
16
  } from '@dxos/app-framework';
17
- import { Query, Type, type Obj } from '@dxos/echo';
17
+ import { Obj, Query, Type } from '@dxos/echo';
18
18
  import { invariant } from '@dxos/invariant';
19
19
  import { useClient } from '@dxos/react-client';
20
20
  import { getSpace, isLiveObject, isSpace, type Space, useQuery, useSpaces } from '@dxos/react-client/echo';
@@ -31,6 +31,7 @@ import { SpaceAction } from '../../types';
31
31
  export const CREATE_OBJECT_DIALOG = `${SPACE_PLUGIN}/CreateObjectDialog`;
32
32
 
33
33
  export type CreateObjectDialogProps = Pick<CreateObjectPanelProps, 'target' | 'typename' | 'name'> & {
34
+ onCreateObject?: (object: Obj.Any) => void;
34
35
  shouldNavigate?: (object: Obj.Any) => boolean;
35
36
  };
36
37
 
@@ -38,6 +39,7 @@ export const CreateObjectDialog = ({
38
39
  target: initialTarget,
39
40
  typename: initialTypename,
40
41
  name,
42
+ onCreateObject,
41
43
  shouldNavigate: _shouldNavigate,
42
44
  }: CreateObjectDialogProps) => {
43
45
  const closeRef = useRef<HTMLButtonElement | null>(null);
@@ -45,7 +47,7 @@ export const CreateObjectDialog = ({
45
47
  const { t } = useTranslation(SPACE_PLUGIN);
46
48
  const client = useClient();
47
49
  const spaces = useSpaces();
48
- const { dispatchPromise: dispatch } = useIntentDispatcher();
50
+ const { dispatch } = useIntentDispatcher();
49
51
  const forms = useCapabilities(SpaceCapabilities.ObjectForm);
50
52
  const [target, setTarget] = useState<Space | DataType.Collection | undefined>(initialTarget);
51
53
  const [typename, setTypename] = useState<string | undefined>(initialTypename);
@@ -60,31 +62,33 @@ export const CreateObjectDialog = ({
60
62
  );
61
63
 
62
64
  const handleCreateObject = useCallback<NonNullable<CreateObjectPanelProps['onCreateObject']>>(
63
- async ({ form, data = {} }) => {
64
- if (!target) {
65
- // TODO(wittjosiah): UI feedback.
66
- return;
67
- }
65
+ ({ form, data = {} }) =>
66
+ Effect.gen(function* () {
67
+ if (!target) {
68
+ // TODO(wittjosiah): UI feedback.
69
+ return;
70
+ }
71
+
72
+ // NOTE: Must close before navigating or attention won't follow object.
73
+ closeRef.current?.click();
68
74
 
69
- // NOTE: Must close before navigating or attention won't follow object.
70
- closeRef.current?.click();
75
+ const space = isSpace(target) ? target : getSpace(target);
76
+ invariant(space, 'Missing space');
77
+ const { object } = yield* dispatch(form.getIntent(data, { space }));
78
+ if (isLiveObject(object) && !Obj.instanceOf(DataType.StoredSchema, object)) {
79
+ // TODO(wittjosiah): Selection in navtree isn't working as expected when hidden typenames evals to true.
80
+ const hidden = form.hidden || hiddenTypenames.includes(Type.getTypename(form.objectSchema));
81
+ const addObjectIntent = createIntent(SpaceAction.AddObject, { target, object, hidden });
82
+ const shouldNavigate = _shouldNavigate ?? (() => true);
83
+ if (shouldNavigate(object)) {
84
+ yield* dispatch(pipe(addObjectIntent, chain(LayoutAction.Open, { part: 'main' })));
85
+ } else {
86
+ yield* dispatch(addObjectIntent);
87
+ }
71
88
 
72
- const space = isSpace(target) ? target : getSpace(target);
73
- invariant(space, 'Missing space');
74
- const result = await dispatch(form.getIntent(data, { space }));
75
- const object = result.data?.object;
76
- if (isLiveObject(object)) {
77
- // TODO(wittjosiah): Selection in navtree isn't working as expected when hidden typenames evals to true.
78
- const hidden = form.hidden || hiddenTypenames.includes(Type.getTypename(form.objectSchema));
79
- const addObjectIntent = createIntent(SpaceAction.AddObject, { target, object, hidden });
80
- const shouldNavigate = _shouldNavigate ?? (() => true);
81
- if (shouldNavigate(object)) {
82
- await dispatch(pipe(addObjectIntent, chain(LayoutAction.Open, { part: 'main' })));
83
- } else {
84
- await dispatch(addObjectIntent);
89
+ onCreateObject?.(object);
85
90
  }
86
- }
87
- },
91
+ }).pipe(Effect.runPromise),
88
92
  [dispatch, target, resolve, hiddenTypenames, _shouldNavigate],
89
93
  );
90
94
 
@@ -2,7 +2,6 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Check, X } from '@phosphor-icons/react';
6
5
  import React, { type Dispatch, type SetStateAction, useCallback, useMemo, useState } from 'react';
7
6
  import { QR } from 'react-qr-rounded';
8
7
 
@@ -14,7 +13,6 @@ import { type CancellableInvitationObservable, Invitation, InvitationEncoder } f
14
13
  import { Button, Clipboard, Icon, Input, useId, useTranslation } from '@dxos/react-ui';
15
14
  import { ControlPage, ControlSection, ControlFrame, ControlFrameItem, ControlItemInput } from '@dxos/react-ui-form';
16
15
  import { StackItem } from '@dxos/react-ui-stack';
17
- import { getSize, mx } from '@dxos/react-ui-theme';
18
16
  import { DataType } from '@dxos/schema';
19
17
  import {
20
18
  type ActionMenuItem,
@@ -280,5 +278,9 @@ const InvitationAuthCode = ({ id, code, onCancel }: { id: string; code: string;
280
278
  };
281
279
 
282
280
  const InvitationComplete = ({ statusValue }: { statusValue: number }) => {
283
- return statusValue > 0 ? <Check className={mx('m-1.5', getSize(6))} /> : <X className={mx('m-1.5', getSize(6))} />;
281
+ return statusValue > 0 ? (
282
+ <Icon icon='ph--check--regular' size={6} classNames='m-1.5' />
283
+ ) : (
284
+ <Icon icon='ph--x--regular' size={6} classNames='m-1.5' />
285
+ );
284
286
  };
@@ -2,13 +2,12 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Planet } from '@phosphor-icons/react';
6
5
  import React from 'react';
7
6
 
8
7
  import { getSpace } from '@dxos/client/echo';
9
8
  import { type Obj } from '@dxos/echo';
10
9
  import { useClient } from '@dxos/react-client';
11
- import { DropdownMenu, toLocalizedString, useTranslation } from '@dxos/react-ui';
10
+ import { DropdownMenu, Icon, toLocalizedString, useTranslation } from '@dxos/react-ui';
12
11
 
13
12
  import { SPACE_PLUGIN } from '../meta';
14
13
  import { getSpaceDisplayName } from '../util';
@@ -25,7 +24,7 @@ export const MenuFooter = ({ object }: { object: Obj.Any }) => {
25
24
  <dl className='pis-2 mbe-2 text-xs grid grid-cols-[max-content_1fr] gap-2'>
26
25
  <dt className='uppercase text-[.75em] tracking-wide font-medium mbs-px self-start'>{t('location label')}</dt>
27
26
  <dd className='line-clamp-3'>
28
- <Planet className='inline-block mie-1' />
27
+ <Icon icon='ph--planet--regular' classNames='inline-block mie-1' />
29
28
  {toLocalizedString(spaceName, t)}
30
29
  </dd>
31
30
  </dl>
@@ -0,0 +1,77 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback } from 'react';
6
+
7
+ import { type JsonPath, setValue } from '@dxos/echo-schema';
8
+ import { invariant } from '@dxos/invariant';
9
+ import { useClient } from '@dxos/react-client';
10
+ import { getSpace, Filter, useQuery, useSchema } from '@dxos/react-client/echo';
11
+ import { Callout, useTranslation } from '@dxos/react-ui';
12
+ import { useSelected } from '@dxos/react-ui-attention';
13
+ import { Form, useRefQueryLookupHandler } from '@dxos/react-ui-form';
14
+ import { type DataType } from '@dxos/schema';
15
+ import { isNonNullable } from '@dxos/util';
16
+
17
+ import { SPACE_PLUGIN } from '../meta';
18
+
19
+ type RowDetailsPanelProps = { objectId: string; view: DataType.View };
20
+
21
+ const ObjectDetailsPanel = ({ objectId, view }: RowDetailsPanelProps) => {
22
+ const { t } = useTranslation(SPACE_PLUGIN);
23
+ const client = useClient();
24
+ const space = getSpace(view);
25
+ const schema = useSchema(client, space, view.query?.typename);
26
+
27
+ const queriedObjects = useQuery(space, schema ? Filter.type(schema) : Filter.nothing());
28
+ const selectedRows = useSelected(objectId, 'multi');
29
+ const selectedObjects = selectedRows.map((id) => queriedObjects.find((obj) => obj.id === id)).filter(isNonNullable);
30
+
31
+ const handleRefQueryLookup = useRefQueryLookupHandler({ space });
32
+
33
+ const handleSave = useCallback(
34
+ (values: any, { changed }: { changed: Record<JsonPath, boolean> }) => {
35
+ const id = values.id;
36
+ invariant(typeof id === 'string');
37
+ const object = queriedObjects.find((obj) => obj.id === id);
38
+ invariant(object);
39
+
40
+ const changedPaths = Object.keys(changed).filter((path) => changed[path as JsonPath]) as JsonPath[];
41
+ for (const path of changedPaths) {
42
+ const value = values[path];
43
+ setValue(object, path, value);
44
+ }
45
+ },
46
+ [queriedObjects],
47
+ );
48
+
49
+ if (selectedObjects.length === 0) {
50
+ return (
51
+ <div role='none' className='plb-cardSpacingBlock pli-cardSpacingInline'>
52
+ <Callout.Root classNames='is-full'>
53
+ <Callout.Title>{t('row details no selection label')}</Callout.Title>
54
+ </Callout.Root>
55
+ </div>
56
+ );
57
+ }
58
+
59
+ return (
60
+ <div role='none' className='bs-full is-full flex flex-col p-2 gap-1 overflow-y-auto'>
61
+ {schema &&
62
+ selectedObjects.map((object) => (
63
+ <div key={object.id} className='border border-separator rounded'>
64
+ <Form
65
+ autoSave
66
+ schema={schema}
67
+ values={object}
68
+ onSave={handleSave}
69
+ onQueryRefOptions={handleRefQueryLookup}
70
+ />
71
+ </div>
72
+ ))}
73
+ </div>
74
+ );
75
+ };
76
+
77
+ export default ObjectDetailsPanel;
@@ -2,13 +2,12 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { ArrowsCounterClockwise, CheckCircle, Warning } from '@phosphor-icons/react';
6
5
  import React, { useEffect, useState } from 'react';
7
6
 
8
7
  import { debounce } from '@dxos/async';
9
8
  import { type EchoDatabase } from '@dxos/react-client/echo';
10
- import { Tooltip, useTranslation } from '@dxos/react-ui';
11
- import { getSize, mx, staticPlaceholderText, warningText } from '@dxos/react-ui-theme';
9
+ import { Icon, Tooltip, useTranslation } from '@dxos/react-ui';
10
+ import { mx, staticPlaceholderText, warningText } from '@dxos/react-ui-theme';
12
11
 
13
12
  import { SPACE_PLUGIN } from '../meta';
14
13
 
@@ -54,14 +53,14 @@ export const PersistenceStatus = ({ db }: { db: EchoDatabase }) => {
54
53
  case Status.ERROR:
55
54
  return (
56
55
  <div className='flex items-center'>
57
- <Warning className={mx(getSize(4), 'me-1')} />
56
+ <Icon icon='ph--warning--regular' size={4} classNames='me-1' />
58
57
  <span className={mx('text-sm', warningText)}>{t('persistence error label')}</span>
59
58
  </div>
60
59
  );
61
60
  case Status.PENDING:
62
61
  return (
63
62
  <div className='flex items-center'>
64
- <ArrowsCounterClockwise className={mx(getSize(4), 'me-1')} />
63
+ <Icon icon='ph--arrows-counter-clockwise--regular' size={4} classNames='me-1' />
65
64
  <span className={mx('text-sm', staticPlaceholderText)}>{t('persistence pending label')}</span>
66
65
  </div>
67
66
  );
@@ -74,7 +73,7 @@ export const PersistenceStatus = ({ db }: { db: EchoDatabase }) => {
74
73
  content={t('persisted locally message')}
75
74
  className='flex items-center'
76
75
  >
77
- <CheckCircle className={mx(getSize(4), 'me-1')} />
76
+ <Icon icon='ph--check-circle--regular' size={4} classNames='me-1' />
78
77
  {displayMessage && (
79
78
  <span className={mx('text-sm', staticPlaceholderText)}>{t('persisted locally label')}</span>
80
79
  )}
@@ -25,10 +25,10 @@ export const PopoverRenameObject = ({ object: obj }: { object: Live<any> }) => {
25
25
  const handleDone = useCallback(() => {
26
26
  try {
27
27
  object.name = name;
28
- } catch {
28
+ } catch (err) {
29
29
  try {
30
30
  object.title = name;
31
- } catch (err) {
31
+ } catch {
32
32
  log.error('Failed to rename object', { err });
33
33
  }
34
34
  }
@@ -29,7 +29,7 @@ export const SyncStatus = () => {
29
29
  return <SyncStatusIndicator state={state} saved={saved} />;
30
30
  };
31
31
 
32
- export const SyncStatusIndicator = ({ state, saved }: { state: SpaceSyncStateMap; saved: Boolean }) => {
32
+ export const SyncStatusIndicator = ({ state, saved }: { state: SpaceSyncStateMap; saved: boolean }) => {
33
33
  const { t } = useTranslation(SPACE_PLUGIN);
34
34
  const summary = getSyncSummary(state);
35
35
  const offline = Object.values(state).length === 0;
@@ -10,10 +10,10 @@ export const getStatus = ({
10
10
  needsToUpload,
11
11
  needsToDownload,
12
12
  }: {
13
- offline: Boolean;
14
- saved: Boolean;
15
- needsToUpload: Boolean;
16
- needsToDownload: Boolean;
13
+ offline: boolean;
14
+ saved: boolean;
15
+ needsToUpload: boolean;
16
+ needsToDownload: boolean;
17
17
  }): Status => {
18
18
  if (!saved) {
19
19
  return 'saving locally';
@@ -0,0 +1,64 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useMemo } from 'react';
6
+
7
+ import { createIntent, useIntentDispatcher } from '@dxos/app-framework';
8
+ import { Type } from '@dxos/echo';
9
+ import { invariant } from '@dxos/invariant';
10
+ import { useClient } from '@dxos/react-client';
11
+ import { Filter, getSpace, useQuery, useSchema } from '@dxos/react-client/echo';
12
+ import { ViewEditor as NativeViewEditor } from '@dxos/react-ui-form';
13
+ import { DataType } from '@dxos/schema';
14
+
15
+ import { SpaceAction } from '../types';
16
+
17
+ type ViewEditorProps = { view: DataType.View };
18
+
19
+ export const ViewEditor = ({ view }: ViewEditorProps) => {
20
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
21
+ const client = useClient();
22
+ const space = getSpace(view);
23
+ const schema = useSchema(client, space, view.query.typename);
24
+
25
+ const views = useQuery(space, Filter.type(DataType.View));
26
+ const currentTypename = useMemo(() => view.query?.typename, [view.query?.typename]);
27
+
28
+ const handleUpdateTypename = useCallback(
29
+ (typename: string) => {
30
+ invariant(schema);
31
+ invariant(Type.isMutable(schema));
32
+
33
+ const matchingViews = views.filter((view) => view.query.typename === currentTypename);
34
+ for (const view of matchingViews) {
35
+ view.query.typename = typename;
36
+ }
37
+
38
+ schema.updateTypename(typename);
39
+ },
40
+ [views, schema],
41
+ );
42
+
43
+ const handleDelete = useCallback(
44
+ (fieldId: string) => {
45
+ void dispatch(createIntent(SpaceAction.DeleteField, { view, fieldId }));
46
+ },
47
+ [dispatch, view],
48
+ );
49
+
50
+ if (!space || !schema) {
51
+ return null;
52
+ }
53
+
54
+ return (
55
+ <NativeViewEditor
56
+ registry={space.db.schemaRegistry}
57
+ schema={schema}
58
+ view={view}
59
+ onTypenameChanged={Type.isMutable(schema) ? handleUpdateTypename : undefined}
60
+ onDelete={Type.isMutable(schema) ? handleDelete : undefined}
61
+ outerSpacing={false}
62
+ />
63
+ );
64
+ };
@@ -2,9 +2,10 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { lazy } from 'react';
6
+
5
7
  export * from './AwaitingObject';
6
8
  export * from './CreateDialog';
7
- export * from './CollectionMain';
8
9
  export * from './CollectionSection';
9
10
  export * from './JoinDialog';
10
11
  export * from './MembersContainer';
@@ -18,3 +19,7 @@ export * from './SpacePresence';
18
19
  export * from './SpacePluginSettings';
19
20
  export * from './SpaceSettings';
20
21
  export * from './SyncStatus';
22
+ export * from './ViewEditor';
23
+
24
+ export const CollectionMain = lazy(() => import('./CollectionMain'));
25
+ export const ObjectDetailsPanel = lazy(() => import('./ObjectDetailsPanel'));
package/src/events.ts CHANGED
@@ -11,4 +11,5 @@ export namespace SpaceEvents {
11
11
  export const SetupSettingsPanel = defineEvent(`${SPACE_PLUGIN}/event/setup-settings-panel`);
12
12
  export const DefaultSpaceReady = defineEvent(`${SPACE_PLUGIN}/event/default-space-ready`);
13
13
  export const SpaceCreated = defineEvent(`${SPACE_PLUGIN}/event/space-created`);
14
+ export const SchemaAdded = defineEvent(`${SPACE_PLUGIN}/event/schema-added`);
14
15
  }
@@ -2,6 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { StoredSchema } from '@dxos/echo-schema';
5
6
  import { type Resource } from '@dxos/react-ui';
6
7
  import { DataType } from '@dxos/schema';
7
8
 
@@ -17,6 +18,8 @@ export const translations = [
17
18
  'typename label_one': 'Collection',
18
19
  'typename label_other': 'Collections',
19
20
  'object name placeholder': 'New collection',
21
+ 'rename object label': 'Rename collection',
22
+ 'delete object label': 'Delete collection',
20
23
  },
21
24
  [DataType.QueryCollection.typename]: {
22
25
  'typename label': 'Smart Collection',
@@ -24,6 +27,61 @@ export const translations = [
24
27
  'typename label_one': 'Smart Collection',
25
28
  'typename label_other': 'Smart Collections',
26
29
  'object name placeholder': 'New smart collection',
30
+ 'rename object label': 'Rename smart collection',
31
+ 'delete object label': 'Delete smart collection',
32
+ },
33
+ [StoredSchema.typename]: {
34
+ 'typename label': 'Record',
35
+ 'typename label_zero': 'Records',
36
+ 'typename label_one': 'Record',
37
+ 'typename label_other': 'Records',
38
+ 'object name placeholder': 'New record type',
39
+ 'rename object label': 'Rename record type',
40
+ 'delete object label': 'Delete record type',
41
+ },
42
+ [DataType.View.typename]: {
43
+ 'typename label': 'View',
44
+ 'typename label_zero': 'Views',
45
+ 'typename label_one': 'View',
46
+ 'typename label_other': 'Views',
47
+ 'object name placeholder': 'New view',
48
+ 'rename object label': 'Rename view',
49
+ 'delete object label': 'Delete view',
50
+ },
51
+ [DataType.Event.typename]: {
52
+ 'typename label': 'Event',
53
+ 'typename label_zero': 'Events',
54
+ 'typename label_one': 'Event',
55
+ 'typename label_other': 'Events',
56
+ 'object name placeholder': 'New event',
57
+ },
58
+ [DataType.Organization.typename]: {
59
+ 'typename label': 'Organization',
60
+ 'typename label_zero': 'Organizations',
61
+ 'typename label_one': 'Organization',
62
+ 'typename label_other': 'Organizations',
63
+ 'object name placeholder': 'New organization',
64
+ },
65
+ [DataType.Person.typename]: {
66
+ 'typename label': 'Person',
67
+ 'typename label_zero': 'People',
68
+ 'typename label_one': 'Person',
69
+ 'typename label_other': 'People',
70
+ 'object name placeholder': 'New person',
71
+ },
72
+ [DataType.Project.typename]: {
73
+ 'typename label': 'Project',
74
+ 'typename label_zero': 'Projects',
75
+ 'typename label_one': 'Project',
76
+ 'typename label_other': 'Projects',
77
+ 'object name placeholder': 'New project',
78
+ },
79
+ [DataType.Task.typename]: {
80
+ 'typename label': 'Task',
81
+ 'typename label_zero': 'Tasks',
82
+ 'typename label_one': 'Task',
83
+ 'typename label_other': 'Tasks',
84
+ 'object name placeholder': 'New task',
27
85
  },
28
86
  [meta.id]: {
29
87
  'plugin name': 'Spaces',
@@ -136,6 +194,10 @@ export const translations = [
136
194
  'add key': 'Add Key',
137
195
  'open space settings label': 'Open settings',
138
196
 
197
+ 'row details no selection label': 'No objects selected',
198
+ 'companion selected objects label': 'Selected',
199
+ 'field deleted label': 'Field deleted',
200
+
139
201
  'members panel label': 'Members',
140
202
  'members verbose label': 'Manage space members',
141
203
  'members description': 'You can view the current status of space members here as well as invite new members.',