@dxos/plugin-space 0.6.14-staging.e15392e → 0.7.0

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 (108) hide show
  1. package/dist/lib/browser/{chunk-AVLRQF6L.mjs → chunk-DJE2HYFV.mjs} +3 -2
  2. package/dist/lib/browser/{chunk-AVLRQF6L.mjs.map → chunk-DJE2HYFV.mjs.map} +2 -2
  3. package/dist/lib/browser/{chunk-FOI7DAUV.mjs → chunk-OWZKSWMX.mjs} +1 -1
  4. package/dist/lib/browser/{chunk-FOI7DAUV.mjs.map → chunk-OWZKSWMX.mjs.map} +2 -2
  5. package/dist/lib/browser/index.mjs +817 -762
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/meta.mjs +1 -1
  9. package/dist/lib/browser/types/index.mjs +1 -1
  10. package/dist/lib/node/{chunk-OTDRTHT4.cjs → chunk-FYWGZYJB.cjs} +4 -4
  11. package/dist/lib/node/{chunk-OTDRTHT4.cjs.map → chunk-FYWGZYJB.cjs.map} +2 -2
  12. package/dist/lib/node/{chunk-P4XUXM7Y.cjs → chunk-JFDDZI4Y.cjs} +6 -5
  13. package/dist/lib/node/{chunk-P4XUXM7Y.cjs.map → chunk-JFDDZI4Y.cjs.map} +2 -2
  14. package/dist/lib/node/index.cjs +1009 -957
  15. package/dist/lib/node/index.cjs.map +4 -4
  16. package/dist/lib/node/meta.cjs +5 -5
  17. package/dist/lib/node/meta.cjs.map +1 -1
  18. package/dist/lib/node/meta.json +1 -1
  19. package/dist/lib/node/types/index.cjs +11 -11
  20. package/dist/lib/node/types/index.cjs.map +1 -1
  21. package/dist/lib/node-esm/{chunk-YPQGKWHJ.mjs → chunk-DVUZ7A7G.mjs} +3 -2
  22. package/dist/lib/node-esm/{chunk-YPQGKWHJ.mjs.map → chunk-DVUZ7A7G.mjs.map} +2 -2
  23. package/dist/lib/node-esm/{chunk-FYDGMPSC.mjs → chunk-MCEAI4CV.mjs} +1 -1
  24. package/dist/lib/node-esm/{chunk-FYDGMPSC.mjs.map → chunk-MCEAI4CV.mjs.map} +2 -2
  25. package/dist/lib/node-esm/index.mjs +817 -762
  26. package/dist/lib/node-esm/index.mjs.map +4 -4
  27. package/dist/lib/node-esm/meta.json +1 -1
  28. package/dist/lib/node-esm/meta.mjs +1 -1
  29. package/dist/lib/node-esm/types/index.mjs +1 -1
  30. package/dist/types/src/SpacePlugin.d.ts +9 -1
  31. package/dist/types/src/SpacePlugin.d.ts.map +1 -1
  32. package/dist/types/src/components/JoinDialog.d.ts +7 -0
  33. package/dist/types/src/components/JoinDialog.d.ts.map +1 -0
  34. package/dist/types/src/components/ShareSpaceButton.d.ts +3 -2
  35. package/dist/types/src/components/ShareSpaceButton.d.ts.map +1 -1
  36. package/dist/types/src/components/{SpaceSettings.d.ts → SpacePluginSettings.d.ts} +2 -2
  37. package/dist/types/src/components/SpacePluginSettings.d.ts.map +1 -0
  38. package/dist/types/src/components/SpaceSettings/SpaceSettingsDialog.d.ts +10 -0
  39. package/dist/types/src/components/SpaceSettings/SpaceSettingsDialog.d.ts.map +1 -0
  40. package/dist/types/src/components/SpaceSettings/SpaceSettingsDialog.stories.d.ts +7 -0
  41. package/dist/types/src/components/SpaceSettings/SpaceSettingsDialog.stories.d.ts.map +1 -0
  42. package/dist/types/src/components/SpaceSettings/SpaceSettingsPanel.d.ts.map +1 -0
  43. package/dist/types/src/components/SpaceSettings/SpaceSettingsPanel.stories.d.ts +7 -0
  44. package/dist/types/src/components/SpaceSettings/SpaceSettingsPanel.stories.d.ts.map +1 -0
  45. package/dist/types/src/components/SpaceSettings/index.d.ts +3 -0
  46. package/dist/types/src/components/SpaceSettings/index.d.ts.map +1 -0
  47. package/dist/types/src/components/SyncStatus/Space.d.ts +8 -0
  48. package/dist/types/src/components/SyncStatus/Space.d.ts.map +1 -0
  49. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts +3 -2
  50. package/dist/types/src/components/SyncStatus/SyncStatus.d.ts.map +1 -1
  51. package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts +5 -20
  52. package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts.map +1 -1
  53. package/dist/types/src/components/SyncStatus/save-tracker.d.ts +3 -0
  54. package/dist/types/src/components/SyncStatus/save-tracker.d.ts.map +1 -0
  55. package/dist/types/src/components/SyncStatus/status.d.ts +9 -0
  56. package/dist/types/src/components/SyncStatus/status.d.ts.map +1 -0
  57. package/dist/types/src/components/SyncStatus/{types.d.ts → sync-state.d.ts} +1 -1
  58. package/dist/types/src/components/SyncStatus/sync-state.d.ts.map +1 -0
  59. package/dist/types/src/components/index.d.ts +2 -4
  60. package/dist/types/src/components/index.d.ts.map +1 -1
  61. package/dist/types/src/meta.d.ts +3 -2
  62. package/dist/types/src/meta.d.ts.map +1 -1
  63. package/dist/types/src/translations.d.ts +10 -0
  64. package/dist/types/src/translations.d.ts.map +1 -1
  65. package/dist/types/src/types/types.d.ts +7 -1
  66. package/dist/types/src/types/types.d.ts.map +1 -1
  67. package/dist/types/src/util.d.ts +8 -4
  68. package/dist/types/src/util.d.ts.map +1 -1
  69. package/package.json +35 -33
  70. package/src/SpacePlugin.tsx +279 -175
  71. package/src/components/AwaitingObject.tsx +1 -1
  72. package/src/components/JoinDialog.tsx +100 -0
  73. package/src/components/ShareSpaceButton.tsx +10 -6
  74. package/src/components/{SpaceSettings.tsx → SpacePluginSettings.tsx} +6 -6
  75. package/src/components/SpaceSettings/SpaceSettingsDialog.stories.tsx +44 -0
  76. package/src/components/SpaceSettings/SpaceSettingsDialog.tsx +103 -0
  77. package/src/components/SpaceSettings/SpaceSettingsPanel.stories.tsx +32 -0
  78. package/src/components/{SpaceSettingsPanel.tsx → SpaceSettings/SpaceSettingsPanel.tsx} +25 -20
  79. package/src/components/SpaceSettings/index.ts +6 -0
  80. package/src/components/SyncStatus/Space.tsx +109 -0
  81. package/src/components/SyncStatus/SyncStatus.stories.tsx +13 -4
  82. package/src/components/SyncStatus/SyncStatus.tsx +43 -129
  83. package/src/components/{SaveStatus.tsx → SyncStatus/save-tracker.ts} +1 -25
  84. package/src/components/SyncStatus/status.ts +44 -0
  85. package/src/components/index.ts +2 -4
  86. package/src/meta.ts +2 -1
  87. package/src/translations.ts +10 -0
  88. package/src/types/types.ts +9 -1
  89. package/src/util.tsx +51 -23
  90. package/dist/types/src/components/MissingObject.d.ts +0 -5
  91. package/dist/types/src/components/MissingObject.d.ts.map +0 -1
  92. package/dist/types/src/components/SaveStatus.d.ts +0 -3
  93. package/dist/types/src/components/SaveStatus.d.ts.map +0 -1
  94. package/dist/types/src/components/SpaceMain/SpaceMain.d.ts +0 -10
  95. package/dist/types/src/components/SpaceMain/SpaceMain.d.ts.map +0 -1
  96. package/dist/types/src/components/SpaceMain/SpaceMembersSection.d.ts +0 -6
  97. package/dist/types/src/components/SpaceMain/SpaceMembersSection.d.ts.map +0 -1
  98. package/dist/types/src/components/SpaceMain/index.d.ts +0 -2
  99. package/dist/types/src/components/SpaceMain/index.d.ts.map +0 -1
  100. package/dist/types/src/components/SpaceSettings.d.ts.map +0 -1
  101. package/dist/types/src/components/SpaceSettingsPanel.d.ts.map +0 -1
  102. package/dist/types/src/components/SyncStatus/types.d.ts.map +0 -1
  103. package/src/components/MissingObject.tsx +0 -54
  104. package/src/components/SpaceMain/SpaceMain.tsx +0 -60
  105. package/src/components/SpaceMain/SpaceMembersSection.tsx +0 -205
  106. package/src/components/SpaceMain/index.ts +0 -5
  107. /package/dist/types/src/components/{SpaceSettingsPanel.d.ts → SpaceSettings/SpaceSettingsPanel.d.ts} +0 -0
  108. /package/src/components/SyncStatus/{types.ts → sync-state.ts} +0 -0
@@ -2,73 +2,76 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { type HTMLAttributes, useEffect, useState } from 'react';
5
+ import React, { useEffect, useState } from 'react';
6
6
 
7
7
  import { StatusBar } from '@dxos/plugin-status-bar';
8
+ import { useClient } from '@dxos/react-client';
8
9
  import { Icon, Popover, useTranslation } from '@dxos/react-ui';
9
10
  import { type ThemedClassName } from '@dxos/react-ui';
10
11
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
11
12
  import { mx } from '@dxos/react-ui-theme';
12
13
 
13
- import { type Progress, type PeerSyncState, type SpaceSyncStateMap, getSyncSummary, useSyncState } from './types';
14
+ import { SpaceRow, SYNC_STALLED_TIMEOUT } from './Space';
15
+ import { createClientSaveTracker } from './save-tracker';
16
+ import { getIcon, getStatus } from './status';
17
+ import { type PeerSyncState, type SpaceSyncStateMap, getSyncSummary, useSyncState } from './sync-state';
14
18
  import { SPACE_PLUGIN } from '../../meta';
15
19
 
16
- const SYNC_STALLED_TIMEOUT = 5_000;
17
-
18
- const styles = {
19
- barBg: 'bg-neutral-50 dark:bg-green-900 text-black',
20
- barFg: 'bg-neutral-100 bg-green-500',
21
- barHover: 'dark:hover:bg-green-500',
22
- };
23
-
24
20
  export const SyncStatus = () => {
21
+ const client = useClient();
25
22
  const state = useSyncState();
26
- return <SyncStatusIndicator state={state} />;
23
+ const [saved, setSaved] = useState(true);
24
+
25
+ useEffect(() => {
26
+ return createClientSaveTracker(client, (state) => {
27
+ setSaved(state === 'saved');
28
+ });
29
+ }, []);
30
+
31
+ return <SyncStatusIndicator state={state} saved={saved} />;
27
32
  };
28
33
 
29
- export const SyncStatusIndicator = ({ state }: { state: SpaceSyncStateMap }) => {
34
+ export const SyncStatusIndicator = ({ state, saved }: { state: SpaceSyncStateMap; saved: Boolean }) => {
35
+ const { t } = useTranslation(SPACE_PLUGIN);
30
36
  const summary = getSyncSummary(state);
31
- const offline = false;
32
-
37
+ const offline = Object.values(state).length === 0;
33
38
  const needsToUpload = summary.differentDocuments > 0 || summary.missingOnRemote > 0;
34
39
  const needsToDownload = summary.differentDocuments > 0 || summary.missingOnLocal > 0;
40
+ const status = getStatus({ offline, saved, needsToUpload, needsToDownload });
41
+
35
42
  const [classNames, setClassNames] = useState<string>();
36
43
  useEffect(() => {
37
44
  setClassNames(undefined);
38
- if (!needsToUpload && !needsToDownload) {
45
+ if (offline || (!needsToUpload && !needsToDownload)) {
39
46
  return;
40
47
  }
41
48
 
42
49
  const t = setTimeout(() => {
50
+ // TODO(wittjosiah): Use semantic color tokens.
43
51
  setClassNames('text-orange-500');
44
52
  }, SYNC_STALLED_TIMEOUT);
45
53
  return () => clearTimeout(t);
46
- }, [needsToUpload, needsToDownload]);
54
+ }, [offline, needsToUpload, needsToDownload]);
47
55
 
48
- return (
49
- <StatusBar.Item>
56
+ const title = t(`${status} label`);
57
+ const icon = <Icon icon={getIcon(status)} size={4} classNames={classNames} />;
58
+
59
+ if (offline) {
60
+ return <StatusBar.Item title={title}>{icon}</StatusBar.Item>;
61
+ } else {
62
+ return (
50
63
  <Popover.Root>
51
- <Popover.Trigger>
52
- <Icon
53
- icon={
54
- offline
55
- ? 'ph--cloud-x--regular'
56
- : needsToUpload
57
- ? 'ph--cloud-arrow-up--regular'
58
- : needsToDownload
59
- ? 'ph--cloud-arrow-down--regular'
60
- : 'ph--cloud-check--regular'
61
- }
62
- size={4}
63
- classNames={classNames}
64
- />
64
+ <Popover.Trigger asChild>
65
+ <StatusBar.Button title={title}>{icon}</StatusBar.Button>
65
66
  </Popover.Trigger>
66
- <Popover.Content sideOffset={16}>
67
- <SyncStatusDetail state={state} summary={summary} debug={false} />
68
- </Popover.Content>
67
+ <Popover.Portal>
68
+ <Popover.Content sideOffset={16}>
69
+ <SyncStatusDetail state={state} summary={summary} debug={false} />
70
+ </Popover.Content>
71
+ </Popover.Portal>
69
72
  </Popover.Root>
70
- </StatusBar.Item>
71
- );
73
+ );
74
+ }
72
75
  };
73
76
 
74
77
  export const SyncStatusDetail = ({
@@ -86,9 +89,9 @@ export const SyncStatusDetail = ({
86
89
 
87
90
  // TODO(burdon): Normalize to max document count?
88
91
  return (
89
- <div className={mx('flex flex-col text-xs min-w-[16rem]', classNames)}>
90
- <h1 className='p-2'>{t('sync status title')}</h1>
91
- <div className='flex flex-col gap-[2px] my-[2px]'>
92
+ <div className={mx('flex flex-col gap-3 p-2 text-xs min-w-[16rem]', classNames)}>
93
+ <h1>{t('sync status title')}</h1>
94
+ <div className='flex flex-col gap-2'>
92
95
  {entries.map(([spaceId, state]) => (
93
96
  <SpaceRow key={spaceId} spaceId={spaceId} state={state} />
94
97
  ))}
@@ -97,92 +100,3 @@ export const SyncStatusDetail = ({
97
100
  </div>
98
101
  );
99
102
  };
100
-
101
- const useActive = (count: number) => {
102
- const [current, setCurrent] = useState(count);
103
- const [active, setActive] = useState(false);
104
- useEffect(() => {
105
- let t: NodeJS.Timeout | undefined;
106
- if (count !== current) {
107
- setActive(true);
108
- setCurrent(count);
109
- t && clearTimeout(t);
110
- t = setTimeout(() => {
111
- setActive(false);
112
- }, SYNC_STALLED_TIMEOUT);
113
- }
114
-
115
- return () => {
116
- setActive(false);
117
- clearTimeout(t);
118
- };
119
- }, [count, current]);
120
- return active;
121
- };
122
-
123
- const SpaceRow = ({
124
- spaceId,
125
- state: { localDocumentCount, remoteDocumentCount, missingOnLocal, missingOnRemote },
126
- }: {
127
- spaceId: string;
128
- state: PeerSyncState;
129
- }) => {
130
- const downActive = useActive(localDocumentCount);
131
- const upActive = useActive(remoteDocumentCount);
132
-
133
- return (
134
- <div
135
- className={mx('flex items-center mx-[2px] gap-[2px] cursor-pointer', styles.barHover)}
136
- title={spaceId}
137
- onClick={() => {
138
- void navigator.clipboard.writeText(spaceId);
139
- }}
140
- >
141
- <Icon
142
- icon='ph--arrow-fat-line-left--regular'
143
- size={3}
144
- classNames={mx(downActive && 'animate-[pulse_1s_infinite]')}
145
- />
146
- <Candle
147
- up={{ count: remoteDocumentCount, total: remoteDocumentCount + missingOnRemote }}
148
- down={{ count: localDocumentCount, total: localDocumentCount + missingOnLocal }}
149
- title={spaceId}
150
- />
151
- <Icon
152
- icon='ph--arrow-fat-line-right--regular'
153
- size={3}
154
- classNames={mx(upActive && 'animate-[pulse_1s_step-start_infinite]')}
155
- />
156
- </div>
157
- );
158
- };
159
-
160
- type CandleProps = ThemedClassName<Pick<HTMLAttributes<HTMLDivElement>, 'title'>> & { up: Progress; down: Progress };
161
-
162
- const Candle = ({ classNames, up, down }: CandleProps) => {
163
- return (
164
- <div className={mx('grid grid-cols-[1fr_2rem_1fr] w-full h-3', classNames)}>
165
- <Bar classNames='justify-end' {...up} />
166
- <div className='relative'>
167
- <div className={mx('absolute inset-0 flex items-center justify-center text-xs', styles.barBg)}>{up.total}</div>
168
- </div>
169
- <Bar {...down} />
170
- </div>
171
- );
172
- };
173
-
174
- const Bar = ({ classNames, count, total }: ThemedClassName<Progress>) => {
175
- let p = (count / total) * 100;
176
- if (count < total) {
177
- p = Math.min(p, 95);
178
- }
179
-
180
- return (
181
- <div className={mx('relative flex w-full', styles.barBg, classNames)}>
182
- <div className={mx('shrink-0', styles.barFg)} style={{ width: `${p}%` }}></div>
183
- {count !== total && (
184
- <div className='absolute top-0 bottom-0 flex items-center mx-0.5 text-black text-xs'>{count}</div>
185
- )}
186
- </div>
187
- );
188
- };
@@ -2,36 +2,12 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useEffect, useState } from 'react';
6
-
7
5
  import { type UnsubscribeCallback } from '@dxos/async';
8
6
  import { type Client } from '@dxos/client';
9
7
  import { type Space, type SpaceId } from '@dxos/client/echo';
10
8
  import { Context } from '@dxos/context';
11
- import { StatusBar } from '@dxos/plugin-status-bar';
12
- import { useClient } from '@dxos/react-client';
13
- import { Icon, useTranslation } from '@dxos/react-ui';
14
-
15
- import { SPACE_PLUGIN } from '../meta';
16
-
17
- export const SaveStatus = () => {
18
- const { t } = useTranslation(SPACE_PLUGIN);
19
- const client = useClient();
20
- const [state, setState] = useState<'saved' | 'saving'>('saved');
21
- useEffect(() => {
22
- return createClientSaveTracker(client, (state) => {
23
- setState(state);
24
- });
25
- }, []);
26
-
27
- return (
28
- <StatusBar.Item title={state === 'saving' ? t('saving label') : t('saved label')}>
29
- <Icon icon={state === 'saving' ? 'ph--arrows-clockwise--regular' : 'ph--check-circle--regular'} size={4} />
30
- </StatusBar.Item>
31
- );
32
- };
33
9
 
34
- const createClientSaveTracker = (client: Client, cb: (state: 'saved' | 'saving') => void) => {
10
+ export const createClientSaveTracker = (client: Client, cb: (state: 'saved' | 'saving') => void) => {
35
11
  const unsubscribeCallbacks: Record<SpaceId, UnsubscribeCallback> = {};
36
12
  const state: Record<SpaceId, 'saved' | 'saving'> = {};
37
13
 
@@ -0,0 +1,44 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export type Status = 'saving locally' | 'downloading' | 'uploading' | 'offline persisted' | 'remote synced';
6
+
7
+ export const getStatus = ({
8
+ offline,
9
+ saved,
10
+ needsToUpload,
11
+ needsToDownload,
12
+ }: {
13
+ offline: Boolean;
14
+ saved: Boolean;
15
+ needsToUpload: Boolean;
16
+ needsToDownload: Boolean;
17
+ }): Status => {
18
+ if (!saved) {
19
+ return 'saving locally';
20
+ } else if (!offline && needsToDownload) {
21
+ return 'downloading';
22
+ } else if (!offline && needsToUpload) {
23
+ return 'uploading';
24
+ } else if (offline && !needsToUpload && !needsToDownload) {
25
+ return 'offline persisted';
26
+ } else {
27
+ return 'remote synced';
28
+ }
29
+ };
30
+
31
+ export const getIcon = (status: Status) => {
32
+ switch (status) {
33
+ case 'saving locally':
34
+ return 'ph--download--regular';
35
+ case 'downloading':
36
+ return 'ph--cloud-arrow-down--regular';
37
+ case 'uploading':
38
+ return 'ph--cloud-arrow-up--regular';
39
+ case 'offline persisted':
40
+ return 'ph--check-circle--regular';
41
+ case 'remote synced':
42
+ return 'ph--cloud-check--regular';
43
+ }
44
+ };
@@ -6,15 +6,13 @@ export * from './AwaitingObject';
6
6
  export * from './CollectionMain';
7
7
  export * from './CollectionSection';
8
8
  export * from './DefaultObjectSettings';
9
+ export * from './JoinDialog';
9
10
  export * from './MenuFooter';
10
- export * from './MissingObject';
11
11
  export * from './PersistenceStatus';
12
12
  export * from './PopoverRenameObject';
13
13
  export * from './PopoverRenameSpace';
14
14
  export * from './ShareSpaceButton';
15
- export * from './SpaceMain';
16
15
  export * from './SpacePresence';
16
+ export * from './SpacePluginSettings';
17
17
  export * from './SpaceSettings';
18
- export * from './SpaceSettingsPanel';
19
- export * from './SaveStatus';
20
18
  export * from './SyncStatus';
package/src/meta.ts CHANGED
@@ -25,9 +25,10 @@ export enum SpaceAction {
25
25
  CLOSE = `${SPACE_ACTION}/close`,
26
26
  MIGRATE = `${SPACE_ACTION}/migrate`,
27
27
  ADD_OBJECT = `${SPACE_ACTION}/add-object`,
28
- REMOVE_OBJECT = `${SPACE_ACTION}/remove-object`,
28
+ REMOVE_OBJECTS = `${SPACE_ACTION}/remove-objects`,
29
29
  RENAME_OBJECT = `${SPACE_ACTION}/rename-object`,
30
30
  DUPLICATE_OBJECT = `${SPACE_ACTION}/duplicate-object`,
31
31
  WAIT_FOR_OBJECT = `${SPACE_ACTION}/wait-for-object`,
32
32
  TOGGLE_HIDDEN = `${SPACE_ACTION}/toggle-hidden`,
33
+ OPEN_SETTINGS = `${SPACE_ACTION}/open-settings`,
33
34
  }
@@ -47,6 +47,7 @@ export default [
47
47
  'delete object label': 'Delete item',
48
48
  'collection deleted label': 'Collection deleted',
49
49
  'object deleted label': 'Item deleted',
50
+ 'objects deleted label': 'Items deleted',
50
51
  'go to object label': 'Open item',
51
52
  'found object label': 'Ready.',
52
53
  'found object description': 'The requested object is now available.',
@@ -94,6 +95,15 @@ export default [
94
95
  'name placeholder': 'Name',
95
96
  'unnamed object settings label': 'Settings',
96
97
  'edge replication label': 'Enable EDGE Replication',
98
+ 'saving locally label': 'Writing to disk',
99
+ 'downloading label': 'Replicating from peers',
100
+ 'uploading label': 'Replicating to peers',
101
+ 'offline persisted label': 'Saved to disk (offline)',
102
+ 'remote synced label': 'Synced with peers',
103
+ 'open settings panel label': 'Show Settings',
104
+ 'open space settings label': 'Space Settings',
105
+ 'members tab label': 'Members',
106
+ 'settings tab label': 'Settings',
97
107
  },
98
108
  },
99
109
  },
@@ -14,6 +14,7 @@ import type {
14
14
  } from '@dxos/app-framework';
15
15
  import { type Expando } from '@dxos/echo-schema';
16
16
  import { type SchemaProvides } from '@dxos/plugin-client';
17
+ import { type PanelProvides } from '@dxos/plugin-deck/types';
17
18
  import { type PublicKey } from '@dxos/react-client';
18
19
  import { type Space } from '@dxos/react-client/echo';
19
20
  import { type Label } from '@dxos/react-ui';
@@ -54,6 +55,12 @@ export type PluginState = {
54
55
  */
55
56
  // TODO(wittjosiah): Factor out to sdk. Migration running should probably be a space state.
56
57
  sdkMigrationRunning: Record<string, boolean>;
58
+
59
+ /**
60
+ * Whether or not the user can navigate to collections in the graph.
61
+ * Determined by whether or not there is an available plugin that can render a collection.
62
+ */
63
+ navigableCollections: boolean;
57
64
  };
58
65
 
59
66
  export type SpaceSettingsProps = {
@@ -87,7 +94,8 @@ export type SpacePluginProvides = SurfaceProvides &
87
94
  MetadataRecordsProvides &
88
95
  SettingsProvides<SpaceSettingsProps> &
89
96
  TranslationsProvides &
90
- SchemaProvides & {
97
+ SchemaProvides &
98
+ PanelProvides & {
91
99
  space: Readonly<PluginState>;
92
100
  };
93
101
 
package/src/util.tsx CHANGED
@@ -92,15 +92,18 @@ export const getSpaceDisplayName = (
92
92
  };
93
93
 
94
94
  const getCollectionGraphNodePartials = ({
95
+ navigable,
95
96
  collection,
96
97
  space,
97
98
  resolve,
98
99
  }: {
100
+ navigable: boolean;
99
101
  collection: CollectionType;
100
102
  space: Space;
101
103
  resolve: MetadataResolver;
102
104
  }) => {
103
105
  return {
106
+ disabled: !navigable,
104
107
  acceptPersistenceClass: new Set(['echo']),
105
108
  acceptPersistenceKey: new Set([space.id]),
106
109
  role: 'branch',
@@ -176,11 +179,13 @@ const checkPendingMigration = (space: Space) => {
176
179
 
177
180
  export const constructSpaceNode = ({
178
181
  space,
182
+ navigable = false,
179
183
  personal,
180
184
  namesCache,
181
185
  resolve,
182
186
  }: {
183
187
  space: Space;
188
+ navigable?: boolean;
184
189
  personal?: boolean;
185
190
  namesCache?: Record<string, string>;
186
191
  resolve: MetadataResolver;
@@ -189,7 +194,7 @@ export const constructSpaceNode = ({
189
194
  const collection = space.state.get() === SpaceState.SPACE_READY && space.properties[CollectionType.typename];
190
195
  const partials =
191
196
  space.state.get() === SpaceState.SPACE_READY && collection instanceof CollectionType
192
- ? getCollectionGraphNodePartials({ collection, space, resolve })
197
+ ? getCollectionGraphNodePartials({ collection, space, resolve, navigable })
193
198
  : {};
194
199
 
195
200
  return {
@@ -201,13 +206,21 @@ export const constructSpaceNode = ({
201
206
  label: getSpaceDisplayName(space, { personal, namesCache }),
202
207
  description: space.state.get() === SpaceState.SPACE_READY && space.properties.description,
203
208
  icon: 'ph--planet--regular',
204
- disabled: space.state.get() !== SpaceState.SPACE_READY || hasPendingMigration,
209
+ disabled: !navigable || space.state.get() !== SpaceState.SPACE_READY || hasPendingMigration,
205
210
  testId: 'spacePlugin.space',
206
211
  },
207
212
  };
208
213
  };
209
214
 
210
- export const constructSpaceActionGroups = ({ space, dispatch }: { space: Space; dispatch: IntentDispatcher }) => {
215
+ export const constructSpaceActionGroups = ({
216
+ space,
217
+ navigable,
218
+ dispatch,
219
+ }: {
220
+ space: Space;
221
+ navigable: boolean;
222
+ dispatch: IntentDispatcher;
223
+ }) => {
211
224
  const state = space.state.get();
212
225
  const hasPendingMigration = checkPendingMigration(space);
213
226
  const getId = (id: string) => `${id}/${space.id}`;
@@ -226,8 +239,6 @@ export const constructSpaceActionGroups = ({ space, dispatch }: { space: Space;
226
239
  label: ['create object in space label', { ns: SPACE_PLUGIN }],
227
240
  icon: 'ph--plus--regular',
228
241
  disposition: 'toolbar',
229
- // TODO(wittjosiah): This is currently a navtree feature. Address this with cmd+k integration.
230
- // mainAreaDisposition: 'in-flow',
231
242
  menuType: 'searchList',
232
243
  testId: 'spacePlugin.createObject',
233
244
  },
@@ -242,9 +253,13 @@ export const constructSpaceActionGroups = ({ space, dispatch }: { space: Space;
242
253
  action: SpaceAction.ADD_OBJECT,
243
254
  data: { target: collection, object: create(CollectionType, { objects: [], views: {} }) },
244
255
  },
245
- {
246
- action: NavigationAction.OPEN,
247
- },
256
+ ...(navigable
257
+ ? [
258
+ {
259
+ action: NavigationAction.OPEN,
260
+ },
261
+ ]
262
+ : []),
248
263
  ]),
249
264
  properties: {
250
265
  label: ['create collection label', { ns: SPACE_PLUGIN }],
@@ -286,7 +301,6 @@ export const constructSpaceActions = ({
286
301
  label: ['migrate space label', { ns: SPACE_PLUGIN }],
287
302
  icon: 'ph--database--regular',
288
303
  disposition: 'toolbar',
289
- mainAreaDisposition: 'in-flow',
290
304
  disabled: migrating || Migrations.running(space),
291
305
  },
292
306
  });
@@ -302,7 +316,7 @@ export const constructSpaceActions = ({
302
316
  if (locked) {
303
317
  return;
304
318
  }
305
- await dispatch({ plugin: SPACE_PLUGIN, action: SpaceAction.SHARE, data: { spaceId: space.id } });
319
+ await dispatch({ plugin: SPACE_PLUGIN, action: SpaceAction.SHARE, data: { space } });
306
320
  },
307
321
  properties: {
308
322
  label: ['share space label', { ns: SPACE_PLUGIN }],
@@ -312,7 +326,6 @@ export const constructSpaceActions = ({
312
326
  macos: 'meta+.',
313
327
  windows: 'alt+.',
314
328
  },
315
- mainAreaDisposition: 'absent',
316
329
  },
317
330
  },
318
331
  {
@@ -343,12 +356,23 @@ export const constructSpaceActions = ({
343
356
  macos: 'shift+F6',
344
357
  windows: 'shift+F6',
345
358
  },
346
- mainAreaDisposition: 'absent',
359
+ },
360
+ },
361
+ {
362
+ id: getId(SpaceAction.OPEN_SETTINGS),
363
+ type: ACTION_TYPE,
364
+ data: async () => {
365
+ await dispatch({ plugin: SPACE_PLUGIN, action: SpaceAction.OPEN_SETTINGS, data: { space } });
366
+ },
367
+ properties: {
368
+ label: ['open space settings label', { ns: SPACE_PLUGIN }],
369
+ icon: 'ph--gear--regular',
347
370
  },
348
371
  },
349
372
  );
350
373
  }
351
374
 
375
+ // TODO(wittjosiah): Consider moving close space into the space settings dialog.
352
376
  if (state !== SpaceState.SPACE_INACTIVE && !hasPendingMigration) {
353
377
  actions.push({
354
378
  id: getId(SpaceAction.CLOSE),
@@ -359,7 +383,6 @@ export const constructSpaceActions = ({
359
383
  properties: {
360
384
  label: ['close space label', { ns: SPACE_PLUGIN }],
361
385
  icon: 'ph--x--regular',
362
- mainAreaDisposition: 'menu',
363
386
  disabled: personal,
364
387
  },
365
388
  });
@@ -376,7 +399,6 @@ export const constructSpaceActions = ({
376
399
  label: ['open space label', { ns: SPACE_PLUGIN }],
377
400
  icon: 'ph--clock-counter-clockwise--regular',
378
401
  disposition: 'toolbar',
379
- mainAreaDisposition: 'in-flow',
380
402
  },
381
403
  });
382
404
  }
@@ -387,10 +409,12 @@ export const constructSpaceActions = ({
387
409
  export const createObjectNode = ({
388
410
  object,
389
411
  space,
412
+ navigable = false,
390
413
  resolve,
391
414
  }: {
392
415
  object: EchoReactiveObject<any>;
393
416
  space: Space;
417
+ navigable?: boolean;
394
418
  resolve: MetadataResolver;
395
419
  }) => {
396
420
  const type = getTypename(object);
@@ -405,7 +429,7 @@ export const createObjectNode = ({
405
429
 
406
430
  const partials =
407
431
  object instanceof CollectionType
408
- ? getCollectionGraphNodePartials({ collection: object, space, resolve })
432
+ ? getCollectionGraphNodePartials({ collection: object, space, resolve, navigable })
409
433
  : metadata.graphProps;
410
434
 
411
435
  return {
@@ -427,9 +451,11 @@ export const createObjectNode = ({
427
451
 
428
452
  export const constructObjectActionGroups = ({
429
453
  object,
454
+ navigable,
430
455
  dispatch,
431
456
  }: {
432
457
  object: EchoReactiveObject<any>;
458
+ navigable: boolean;
433
459
  dispatch: IntentDispatcher;
434
460
  }) => {
435
461
  if (!(object instanceof CollectionType)) {
@@ -447,8 +473,6 @@ export const constructObjectActionGroups = ({
447
473
  label: ['create object in collection label', { ns: SPACE_PLUGIN }],
448
474
  icon: 'ph--plus--regular',
449
475
  disposition: 'toolbar',
450
- // TODO(wittjosiah): This is currently a navtree feature. Address this with cmd+k integration.
451
- // mainAreaDisposition: 'in-flow',
452
476
  menuType: 'searchList',
453
477
  testId: 'spacePlugin.createObject',
454
478
  },
@@ -463,9 +487,13 @@ export const constructObjectActionGroups = ({
463
487
  action: SpaceAction.ADD_OBJECT,
464
488
  data: { target: collection, object: create(CollectionType, { objects: [], views: {} }) },
465
489
  },
466
- {
467
- action: NavigationAction.OPEN,
468
- },
490
+ ...(navigable
491
+ ? [
492
+ {
493
+ action: NavigationAction.OPEN,
494
+ },
495
+ ]
496
+ : []),
469
497
  ]),
470
498
  properties: {
471
499
  label: ['create collection label', { ns: SPACE_PLUGIN }],
@@ -511,7 +539,7 @@ export const constructObjectActions = ({
511
539
  },
512
540
  },
513
541
  {
514
- id: getId(SpaceAction.REMOVE_OBJECT),
542
+ id: getId(SpaceAction.REMOVE_OBJECTS),
515
543
  type: ACTION_TYPE,
516
544
  data: async () => {
517
545
  const graph = getGraph(node);
@@ -520,8 +548,8 @@ export const constructObjectActions = ({
520
548
  .find(({ data }) => data instanceof CollectionType)?.data;
521
549
  await dispatch([
522
550
  {
523
- action: SpaceAction.REMOVE_OBJECT,
524
- data: { object, collection },
551
+ action: SpaceAction.REMOVE_OBJECTS,
552
+ data: { objects: [object], collection },
525
553
  },
526
554
  ]);
527
555
  },
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- export declare const MissingObject: ({ id }: {
3
- id: string;
4
- }) => React.JSX.Element;
5
- //# sourceMappingURL=MissingObject.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MissingObject.d.ts","sourceRoot":"","sources":["../../../../src/components/MissingObject.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAUnD,eAAO,MAAM,aAAa,WAAY;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,sBAuCnD,CAAC"}
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- export declare const SaveStatus: () => React.JSX.Element;
3
- //# sourceMappingURL=SaveStatus.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SaveStatus.d.ts","sourceRoot":"","sources":["../../../../src/components/SaveStatus.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAYnD,eAAO,MAAM,UAAU,yBAetB,CAAC"}
@@ -1,10 +0,0 @@
1
- import React from 'react';
2
- import { type Space } from '@dxos/react-client/echo';
3
- /**
4
- * @deprecated
5
- */
6
- export declare const SpaceMain: ({ space, role }: {
7
- space: Space;
8
- role: "main" | "article";
9
- }) => React.JSX.Element;
10
- //# sourceMappingURL=SpaceMain.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SpaceMain.d.ts","sourceRoot":"","sources":["../../../../../src/components/SpaceMain/SpaceMain.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAC;AA0BjE;;GAEG;AAEH,eAAO,MAAM,SAAS,oBAAqB;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,sBAqBpF,CAAC"}
@@ -1,6 +0,0 @@
1
- import React from 'react';
2
- import { type Space } from '@dxos/react-client/echo';
3
- export declare const SpaceMembersSection: ({ space }: {
4
- space: Space;
5
- }) => React.JSX.Element;
6
- //# sourceMappingURL=SpaceMembersSection.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SpaceMembersSection.d.ts","sourceRoot":"","sources":["../../../../../src/components/SpaceMain/SpaceMembersSection.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAGrD,OAAO,EAAE,KAAK,KAAK,EAAgD,MAAM,yBAAyB,CAAC;AA+BnG,eAAO,MAAM,mBAAmB,cAAe;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,sBAqK9D,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './SpaceMain';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/SpaceMain/index.ts"],"names":[],"mappings":"AAIA,cAAc,aAAa,CAAC"}