@dxos/plugin-space 0.6.13 → 0.6.14-main.1366248
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.
- package/dist/lib/browser/{chunk-LZEGRS7H.mjs → chunk-AVLRQF6L.mjs} +1 -1
- package/dist/lib/browser/chunk-AVLRQF6L.mjs.map +7 -0
- package/dist/lib/browser/{chunk-DTVUOG2C.mjs → chunk-WZAM3FNP.mjs} +24 -5
- package/dist/lib/browser/chunk-WZAM3FNP.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +852 -348
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/lib/browser/types/index.mjs +7 -3
- package/dist/lib/node/{chunk-CVZPI2P3.cjs → chunk-HTAM5LQD.cjs} +30 -9
- package/dist/lib/node/chunk-HTAM5LQD.cjs.map +7 -0
- package/dist/lib/node/{chunk-6CNYF6YU.cjs → chunk-P4XUXM7Y.cjs} +4 -4
- package/dist/lib/node/chunk-P4XUXM7Y.cjs.map +7 -0
- package/dist/lib/node/index.cjs +1046 -550
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.cjs +5 -5
- package/dist/lib/node/meta.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +14 -10
- package/dist/lib/node/types/index.cjs.map +2 -2
- package/dist/lib/node-esm/chunk-TRJKV4PK.mjs +116 -0
- package/dist/lib/node-esm/chunk-TRJKV4PK.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-YPQGKWHJ.mjs +37 -0
- package/dist/lib/node-esm/chunk-YPQGKWHJ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +3145 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/meta.mjs +14 -0
- package/dist/lib/node-esm/meta.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +26 -0
- package/dist/lib/node-esm/types/index.mjs.map +7 -0
- package/dist/types/src/SpacePlugin.d.ts.map +1 -1
- package/dist/types/src/components/DefaultObjectSettings.d.ts +7 -0
- package/dist/types/src/components/DefaultObjectSettings.d.ts.map +1 -0
- package/dist/types/src/components/MenuFooter.d.ts +1 -1
- package/dist/types/src/components/MenuFooter.d.ts.map +1 -1
- package/dist/types/src/components/ShareSpaceButton.stories.d.ts +3 -91
- package/dist/types/src/components/ShareSpaceButton.stories.d.ts.map +1 -1
- package/dist/types/src/components/SpaceMain/SpaceMain.d.ts.map +1 -1
- package/dist/types/src/components/SpacePresence.d.ts +4 -2
- package/dist/types/src/components/SpacePresence.d.ts.map +1 -1
- package/dist/types/src/components/SpacePresence.stories.d.ts +4 -92
- package/dist/types/src/components/SpacePresence.stories.d.ts.map +1 -1
- package/dist/types/src/components/SpaceSettings.d.ts.map +1 -1
- package/dist/types/src/components/SpaceSettingsPanel.d.ts +7 -0
- package/dist/types/src/components/SpaceSettingsPanel.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/Space.d.ts +8 -0
- package/dist/types/src/components/SyncStatus/Space.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/SyncStatus.d.ts +14 -0
- package/dist/types/src/components/SyncStatus/SyncStatus.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts +9 -0
- package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/index.d.ts +2 -0
- package/dist/types/src/components/SyncStatus/index.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/save-tracker.d.ts +3 -0
- package/dist/types/src/components/SyncStatus/save-tracker.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/status.d.ts +9 -0
- package/dist/types/src/components/SyncStatus/status.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/sync-state.d.ts +14 -0
- package/dist/types/src/components/SyncStatus/sync-state.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +3 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +14 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/thread.d.ts +15 -1
- package/dist/types/src/types/thread.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +23 -2
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +4 -7
- package/dist/types/src/util.d.ts.map +1 -1
- package/package.json +46 -45
- package/src/SpacePlugin.tsx +275 -137
- package/src/components/DefaultObjectSettings.tsx +33 -0
- package/src/components/MenuFooter.tsx +2 -2
- package/src/components/ShareSpaceButton.stories.tsx +11 -7
- package/src/components/SpaceMain/SpaceMain.tsx +1 -22
- package/src/components/SpacePresence.stories.tsx +11 -9
- package/src/components/SpacePresence.tsx +34 -23
- package/src/components/SpaceSettings.tsx +35 -6
- package/src/components/SpaceSettingsPanel.tsx +69 -0
- package/src/components/SyncStatus/Space.tsx +109 -0
- package/src/components/SyncStatus/SyncStatus.stories.tsx +74 -0
- package/src/components/SyncStatus/SyncStatus.tsx +102 -0
- package/src/components/SyncStatus/index.ts +5 -0
- package/src/components/SyncStatus/save-tracker.ts +71 -0
- package/src/components/SyncStatus/status.ts +44 -0
- package/src/components/SyncStatus/sync-state.ts +77 -0
- package/src/components/index.ts +3 -3
- package/src/meta.ts +3 -1
- package/src/translations.ts +16 -2
- package/src/types/collection.ts +1 -1
- package/src/types/thread.ts +12 -2
- package/src/types/types.ts +31 -3
- package/src/util.tsx +23 -58
- package/dist/lib/browser/chunk-DTVUOG2C.mjs.map +0 -7
- package/dist/lib/browser/chunk-LZEGRS7H.mjs.map +0 -7
- package/dist/lib/node/chunk-6CNYF6YU.cjs.map +0 -7
- package/dist/lib/node/chunk-CVZPI2P3.cjs.map +0 -7
- package/dist/types/src/components/EmptySpace.d.ts +0 -3
- package/dist/types/src/components/EmptySpace.d.ts.map +0 -1
- package/dist/types/src/components/EmptyTree.d.ts +0 -3
- package/dist/types/src/components/EmptyTree.d.ts.map +0 -1
- package/dist/types/src/components/MissingObject.d.ts +0 -5
- package/dist/types/src/components/MissingObject.d.ts.map +0 -1
- package/src/components/EmptySpace.tsx +0 -25
- package/src/components/EmptyTree.tsx +0 -25
- package/src/components/MissingObject.tsx +0 -54
package/src/SpacePlugin.tsx
CHANGED
|
@@ -2,63 +2,67 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { effect, signal } from '@preact/signals-core';
|
|
5
|
+
import { signal } from '@preact/signals-core';
|
|
7
6
|
import React from 'react';
|
|
8
7
|
|
|
9
8
|
import {
|
|
9
|
+
type GraphProvides,
|
|
10
10
|
type IntentDispatcher,
|
|
11
11
|
type IntentPluginProvides,
|
|
12
12
|
LayoutAction,
|
|
13
|
-
|
|
13
|
+
type LayoutProvides,
|
|
14
14
|
type LocationProvides,
|
|
15
15
|
NavigationAction,
|
|
16
16
|
type Plugin,
|
|
17
17
|
type PluginDefinition,
|
|
18
|
-
|
|
18
|
+
Surface,
|
|
19
19
|
firstIdInPart,
|
|
20
|
+
openIds,
|
|
21
|
+
parseGraphPlugin,
|
|
20
22
|
parseIntentPlugin,
|
|
21
|
-
|
|
23
|
+
parseLayoutPlugin,
|
|
22
24
|
parseMetadataResolverPlugin,
|
|
25
|
+
parseNavigationPlugin,
|
|
23
26
|
resolvePlugin,
|
|
24
|
-
parseGraphPlugin,
|
|
25
27
|
} from '@dxos/app-framework';
|
|
26
28
|
import { EventSubscriptions, type Trigger, type UnsubscribeCallback } from '@dxos/async';
|
|
27
|
-
import { type
|
|
29
|
+
import { type HasId, isReactiveObject } from '@dxos/echo-schema';
|
|
30
|
+
import { scheduledEffect } from '@dxos/echo-signals/core';
|
|
28
31
|
import { LocalStorageStore } from '@dxos/local-storage';
|
|
29
32
|
import { log } from '@dxos/log';
|
|
30
33
|
import { Migrations } from '@dxos/migrations';
|
|
31
34
|
import { type AttentionPluginProvides, parseAttentionPlugin } from '@dxos/plugin-attention';
|
|
32
35
|
import { type ClientPluginProvides, parseClientPlugin } from '@dxos/plugin-client';
|
|
33
|
-
import {
|
|
36
|
+
import { type Node, createExtension, memoize, toSignal } from '@dxos/plugin-graph';
|
|
34
37
|
import { ObservabilityAction } from '@dxos/plugin-observability/meta';
|
|
35
38
|
import { type Client, PublicKey } from '@dxos/react-client';
|
|
36
39
|
import {
|
|
40
|
+
type EchoReactiveObject,
|
|
41
|
+
Expando,
|
|
42
|
+
Filter,
|
|
37
43
|
type PropertiesTypeProps,
|
|
38
44
|
type Space,
|
|
45
|
+
SpaceState,
|
|
39
46
|
create,
|
|
40
|
-
Expando,
|
|
41
|
-
Filter,
|
|
42
47
|
fullyQualifiedId,
|
|
43
48
|
getSpace,
|
|
44
49
|
getTypename,
|
|
45
50
|
isEchoObject,
|
|
46
51
|
isSpace,
|
|
47
52
|
loadObjectReferences,
|
|
48
|
-
|
|
53
|
+
parseId,
|
|
54
|
+
FQ_ID_LENGTH,
|
|
49
55
|
} from '@dxos/react-client/echo';
|
|
50
56
|
import { Dialog } from '@dxos/react-ui';
|
|
51
|
-
import { InvitationManager, type InvitationManagerProps, osTranslations
|
|
57
|
+
import { ClipboardProvider, InvitationManager, type InvitationManagerProps, osTranslations } from '@dxos/shell/react';
|
|
52
58
|
import { ComplexMap, nonNullable, reduceGroupBy } from '@dxos/util';
|
|
53
59
|
|
|
54
60
|
import {
|
|
55
61
|
AwaitingObject,
|
|
56
62
|
CollectionMain,
|
|
57
63
|
CollectionSection,
|
|
58
|
-
|
|
59
|
-
EmptyTree,
|
|
64
|
+
DefaultObjectSettings,
|
|
60
65
|
MenuFooter,
|
|
61
|
-
MissingObject,
|
|
62
66
|
PopoverRenameObject,
|
|
63
67
|
PopoverRenameSpace,
|
|
64
68
|
ShareSpaceButton,
|
|
@@ -66,10 +70,12 @@ import {
|
|
|
66
70
|
SmallPresenceLive,
|
|
67
71
|
SpacePresence,
|
|
68
72
|
SpaceSettings,
|
|
73
|
+
SpaceSettingsPanel,
|
|
74
|
+
SyncStatus,
|
|
69
75
|
} from './components';
|
|
70
76
|
import meta, { SPACE_PLUGIN, SpaceAction } from './meta';
|
|
71
77
|
import translations from './translations';
|
|
72
|
-
import { CollectionType, type
|
|
78
|
+
import { CollectionType, type PluginState, type SpacePluginProvides, type SpaceSettingsProps } from './types';
|
|
73
79
|
import {
|
|
74
80
|
COMPOSER_SPACE_LOCK,
|
|
75
81
|
SHARED,
|
|
@@ -87,7 +93,6 @@ import {
|
|
|
87
93
|
} from './util';
|
|
88
94
|
|
|
89
95
|
const ACTIVE_NODE_BROADCAST_INTERVAL = 30_000;
|
|
90
|
-
const OBJECT_ID_LENGTH = 60; // 33 (space id) + 26 (object id) + 1 (separator).
|
|
91
96
|
const SPACE_MAX_OBJECTS = 500;
|
|
92
97
|
// https://stackoverflow.com/a/19016910
|
|
93
98
|
const DIRECTORY_TYPE = 'text/directory';
|
|
@@ -118,11 +123,14 @@ export const SpacePlugin = ({
|
|
|
118
123
|
firstRun,
|
|
119
124
|
onFirstRun,
|
|
120
125
|
}: SpacePluginOptions = {}): PluginDefinition<SpacePluginProvides> => {
|
|
121
|
-
const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN
|
|
126
|
+
const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN, {
|
|
127
|
+
onSpaceCreate: 'dxos.org/plugin/markdown/action/create',
|
|
128
|
+
});
|
|
122
129
|
const state = new LocalStorageStore<PluginState>(SPACE_PLUGIN, {
|
|
123
130
|
awaiting: undefined,
|
|
124
131
|
spaceNames: {},
|
|
125
132
|
viewersByObject: {},
|
|
133
|
+
// TODO(wittjosiah): Stop using (Complex)Map inside reactive object.
|
|
126
134
|
viewersByIdentity: new ComplexMap(PublicKey.hash),
|
|
127
135
|
sdkMigrationRunning: {},
|
|
128
136
|
});
|
|
@@ -131,17 +139,22 @@ export const SpacePlugin = ({
|
|
|
131
139
|
const graphSubscriptions = new Map<string, UnsubscribeCallback>();
|
|
132
140
|
|
|
133
141
|
let clientPlugin: Plugin<ClientPluginProvides> | undefined;
|
|
142
|
+
let graphPlugin: Plugin<GraphProvides> | undefined;
|
|
134
143
|
let intentPlugin: Plugin<IntentPluginProvides> | undefined;
|
|
144
|
+
let layoutPlugin: Plugin<LayoutProvides> | undefined;
|
|
135
145
|
let navigationPlugin: Plugin<LocationProvides> | undefined;
|
|
136
146
|
let attentionPlugin: Plugin<AttentionPluginProvides> | undefined;
|
|
137
147
|
|
|
138
148
|
const onSpaceReady = async () => {
|
|
139
|
-
if (!clientPlugin || !navigationPlugin || !attentionPlugin) {
|
|
149
|
+
if (!clientPlugin || !intentPlugin || !graphPlugin || !navigationPlugin || !layoutPlugin || !attentionPlugin) {
|
|
140
150
|
return;
|
|
141
151
|
}
|
|
142
152
|
|
|
143
153
|
const client = clientPlugin.provides.client;
|
|
154
|
+
const dispatch = intentPlugin.provides.intent.dispatch;
|
|
155
|
+
const graph = graphPlugin.provides.graph;
|
|
144
156
|
const location = navigationPlugin.provides.location;
|
|
157
|
+
const layout = layoutPlugin.provides.layout;
|
|
145
158
|
const attention = attentionPlugin.provides.attention;
|
|
146
159
|
const defaultSpace = client.spaces.default;
|
|
147
160
|
|
|
@@ -159,6 +172,26 @@ export const SpacePlugin = ({
|
|
|
159
172
|
defaultSpace.db.add(create({ key: SHARED, order: [] }));
|
|
160
173
|
}
|
|
161
174
|
|
|
175
|
+
// Await missing objects.
|
|
176
|
+
subscriptions.add(
|
|
177
|
+
scheduledEffect(
|
|
178
|
+
() => ({
|
|
179
|
+
layoutMode: layout.layoutMode,
|
|
180
|
+
soloPart: location.active.solo?.[0],
|
|
181
|
+
}),
|
|
182
|
+
({ layoutMode, soloPart }) => {
|
|
183
|
+
if (layoutMode !== 'solo' || !soloPart) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const node = graph.findNode(soloPart.id);
|
|
188
|
+
if (!node && soloPart.id.length === FQ_ID_LENGTH) {
|
|
189
|
+
void dispatch({ plugin: SPACE_PLUGIN, action: SpaceAction.WAIT_FOR_OBJECT, data: { id: soloPart.id } });
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
),
|
|
193
|
+
);
|
|
194
|
+
|
|
162
195
|
// Cache space names.
|
|
163
196
|
subscriptions.add(
|
|
164
197
|
client.spaces.subscribe(async (spaces) => {
|
|
@@ -171,9 +204,10 @@ export const SpacePlugin = ({
|
|
|
171
204
|
.filter((space) => space.state.get() === SpaceState.SPACE_READY)
|
|
172
205
|
.forEach((space) => {
|
|
173
206
|
subscriptions.add(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
207
|
+
scheduledEffect(
|
|
208
|
+
() => ({ name: space.properties.name }),
|
|
209
|
+
({ name }) => (state.values.spaceNames[space.id] = name),
|
|
210
|
+
),
|
|
177
211
|
);
|
|
178
212
|
});
|
|
179
213
|
}).unsubscribe,
|
|
@@ -181,54 +215,56 @@ export const SpacePlugin = ({
|
|
|
181
215
|
|
|
182
216
|
// Broadcast active node to other peers in the space.
|
|
183
217
|
subscriptions.add(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
218
|
+
scheduledEffect(
|
|
219
|
+
() => ({
|
|
220
|
+
ids: openIds(location.active),
|
|
221
|
+
removed: location.closed ? [location.closed].flat() : [],
|
|
222
|
+
}),
|
|
223
|
+
({ ids, removed }) => {
|
|
224
|
+
const send = () => {
|
|
225
|
+
const spaces = client.spaces.get();
|
|
226
|
+
const identity = client.halo.identity.get();
|
|
227
|
+
if (identity && location.active) {
|
|
228
|
+
// Group parts by space for efficient messaging.
|
|
229
|
+
const idsBySpace = reduceGroupBy(ids, (id) => {
|
|
230
|
+
const [spaceId] = id.split(':'); // TODO(burdon): Factor out.
|
|
231
|
+
return spaceId;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// NOTE: Ensure all spaces are included so that we send the correct `removed` object arrays.
|
|
235
|
+
for (const space of spaces) {
|
|
236
|
+
if (!idsBySpace.has(space.id)) {
|
|
237
|
+
idsBySpace.set(space.id, []);
|
|
238
|
+
}
|
|
201
239
|
}
|
|
202
|
-
}
|
|
203
240
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
241
|
+
for (const [spaceId, ids] of idsBySpace) {
|
|
242
|
+
const space = spaces.find((space) => space.id === spaceId);
|
|
243
|
+
if (!space) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
209
246
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
});
|
|
247
|
+
void space
|
|
248
|
+
.postMessage('viewing', {
|
|
249
|
+
identityKey: identity.identityKey.toHex(),
|
|
250
|
+
attended: attention.attended ? [...attention.attended] : [],
|
|
251
|
+
added: ids,
|
|
252
|
+
// TODO(Zan): When we re-open a part, we should remove it from the removed list in the navigation plugin.
|
|
253
|
+
removed: removed.filter((id) => !ids.includes(id)),
|
|
254
|
+
})
|
|
255
|
+
// TODO(burdon): This seems defensive; why would this fail? Backoff interval.
|
|
256
|
+
.catch((err) => {
|
|
257
|
+
log.warn('Failed to broadcast active node for presence.', { err: err.message });
|
|
258
|
+
});
|
|
259
|
+
}
|
|
224
260
|
}
|
|
225
|
-
}
|
|
226
|
-
};
|
|
261
|
+
};
|
|
227
262
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
263
|
+
send();
|
|
264
|
+
const interval = setInterval(() => send(), ACTIVE_NODE_BROADCAST_INTERVAL);
|
|
265
|
+
return () => clearInterval(interval);
|
|
266
|
+
},
|
|
267
|
+
),
|
|
232
268
|
);
|
|
233
269
|
|
|
234
270
|
// Listen for active nodes from other peers in the space.
|
|
@@ -276,18 +312,11 @@ export const SpacePlugin = ({
|
|
|
276
312
|
return {
|
|
277
313
|
meta,
|
|
278
314
|
ready: async (plugins) => {
|
|
279
|
-
settings.prop({
|
|
280
|
-
|
|
281
|
-
storageKey: 'show-hidden',
|
|
282
|
-
type: LocalStorageStore.bool({ allowUndefined: true }),
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
state.prop({
|
|
286
|
-
key: 'spaceNames',
|
|
287
|
-
storageKey: 'space-names',
|
|
288
|
-
type: LocalStorageStore.json<Record<string, string>>(),
|
|
289
|
-
});
|
|
315
|
+
settings.prop({ key: 'showHidden', type: LocalStorageStore.bool({ allowUndefined: true }) });
|
|
316
|
+
state.prop({ key: 'spaceNames', type: LocalStorageStore.json<Record<string, string>>() });
|
|
290
317
|
|
|
318
|
+
graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
|
|
319
|
+
layoutPlugin = resolvePlugin(plugins, parseLayoutPlugin);
|
|
291
320
|
navigationPlugin = resolvePlugin(plugins, parseNavigationPlugin);
|
|
292
321
|
attentionPlugin = resolvePlugin(plugins, parseAttentionPlugin);
|
|
293
322
|
clientPlugin = resolvePlugin(plugins, parseClientPlugin);
|
|
@@ -310,19 +339,20 @@ export const SpacePlugin = ({
|
|
|
310
339
|
await onFirstRun?.({ client, dispatch });
|
|
311
340
|
};
|
|
312
341
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
342
|
+
subscriptions.add(
|
|
343
|
+
client.spaces.isReady.subscribe(async (ready) => {
|
|
344
|
+
if (ready) {
|
|
345
|
+
await clientPlugin?.provides.client.spaces.default.waitUntilReady();
|
|
346
|
+
if (firstRun) {
|
|
347
|
+
void firstRun?.wait().then(handleFirstRun);
|
|
348
|
+
} else {
|
|
349
|
+
await handleFirstRun();
|
|
350
|
+
}
|
|
322
351
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
352
|
+
await onSpaceReady();
|
|
353
|
+
}
|
|
354
|
+
}).unsubscribe,
|
|
355
|
+
);
|
|
326
356
|
},
|
|
327
357
|
unload: async () => {
|
|
328
358
|
settings.close();
|
|
@@ -335,13 +365,17 @@ export const SpacePlugin = ({
|
|
|
335
365
|
space: state.values,
|
|
336
366
|
settings: settings.values,
|
|
337
367
|
translations: [...translations, osTranslations],
|
|
368
|
+
complementary: {
|
|
369
|
+
panels: [
|
|
370
|
+
{ id: 'settings', label: ['open settings panel label', { ns: SPACE_PLUGIN }], icon: 'ph--gear--regular' },
|
|
371
|
+
],
|
|
372
|
+
},
|
|
338
373
|
root: () => (state.values.awaiting ? <AwaitingObject id={state.values.awaiting} /> : null),
|
|
339
374
|
metadata: {
|
|
340
375
|
records: {
|
|
341
376
|
[CollectionType.typename]: {
|
|
342
377
|
placeholder: ['unnamed collection label', { ns: SPACE_PLUGIN }],
|
|
343
|
-
icon:
|
|
344
|
-
iconSymbol: 'ph--cards-three--regular',
|
|
378
|
+
icon: 'ph--cards-three--regular',
|
|
345
379
|
// TODO(wittjosiah): Move out of metadata.
|
|
346
380
|
loadReferences: (collection: CollectionType) =>
|
|
347
381
|
loadObjectReferences(collection, (collection) => [
|
|
@@ -356,28 +390,27 @@ export const SpacePlugin = ({
|
|
|
356
390
|
},
|
|
357
391
|
surface: {
|
|
358
392
|
component: ({ data, role, ...rest }) => {
|
|
359
|
-
const primary = data.active ?? data.object;
|
|
360
393
|
switch (role) {
|
|
361
394
|
case 'article':
|
|
362
|
-
case 'main':
|
|
363
395
|
// TODO(wittjosiah): Need to avoid shotgun parsing space state everywhere.
|
|
364
|
-
return isSpace(
|
|
365
|
-
<Surface
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
396
|
+
return isSpace(data.object) && data.object.state.get() === SpaceState.SPACE_READY ? (
|
|
397
|
+
<Surface
|
|
398
|
+
data={{ object: data.object.properties[CollectionType.typename], id: data.object.id }}
|
|
399
|
+
role={role}
|
|
400
|
+
{...rest}
|
|
401
|
+
/>
|
|
402
|
+
) : data.object instanceof CollectionType ? (
|
|
403
|
+
{
|
|
404
|
+
node: <CollectionMain collection={data.object} />,
|
|
405
|
+
disposition: 'fallback',
|
|
406
|
+
}
|
|
407
|
+
) : null;
|
|
408
|
+
case 'complementary--settings':
|
|
409
|
+
return isSpace(data.subject) ? (
|
|
410
|
+
<SpaceSettingsPanel space={data.subject} />
|
|
411
|
+
) : isEchoObject(data.subject) ? (
|
|
412
|
+
{ node: <DefaultObjectSettings object={data.subject} />, disposition: 'fallback' }
|
|
370
413
|
) : null;
|
|
371
|
-
// TODO(burdon): Add role name syntax to minimal plugin docs.
|
|
372
|
-
case 'tree--empty':
|
|
373
|
-
switch (true) {
|
|
374
|
-
case data.plugin === SPACE_PLUGIN:
|
|
375
|
-
return <EmptyTree />;
|
|
376
|
-
case isGraphNode(data.activeNode) && isSpace(data.activeNode.data):
|
|
377
|
-
return <EmptySpace />;
|
|
378
|
-
default:
|
|
379
|
-
return null;
|
|
380
|
-
}
|
|
381
414
|
case 'dialog':
|
|
382
415
|
if (data.component === 'dxos.org/plugin/space/InvitationManagerDialog') {
|
|
383
416
|
return (
|
|
@@ -387,10 +420,9 @@ export const SpacePlugin = ({
|
|
|
387
420
|
</ClipboardProvider>
|
|
388
421
|
</Dialog.Content>
|
|
389
422
|
);
|
|
390
|
-
} else {
|
|
391
|
-
return null;
|
|
392
423
|
}
|
|
393
|
-
|
|
424
|
+
return null;
|
|
425
|
+
case 'popover': {
|
|
394
426
|
if (data.component === 'dxos.org/plugin/space/RenameSpacePopover' && isSpace(data.subject)) {
|
|
395
427
|
return <PopoverRenameSpace space={data.subject} />;
|
|
396
428
|
}
|
|
@@ -398,11 +430,16 @@ export const SpacePlugin = ({
|
|
|
398
430
|
return <PopoverRenameObject object={data.subject} />;
|
|
399
431
|
}
|
|
400
432
|
return null;
|
|
433
|
+
}
|
|
434
|
+
// TODO(burdon): Add role name syntax to minimal plugin docs.
|
|
401
435
|
case 'presence--glyph': {
|
|
402
436
|
return isReactiveObject(data.object) ? (
|
|
403
|
-
<SmallPresenceLive
|
|
437
|
+
<SmallPresenceLive
|
|
438
|
+
id={data.id as string}
|
|
439
|
+
viewers={state.values.viewersByObject[fullyQualifiedId(data.object)]}
|
|
440
|
+
/>
|
|
404
441
|
) : (
|
|
405
|
-
<SmallPresence count={0} />
|
|
442
|
+
<SmallPresence id={data.id as string} count={0} />
|
|
406
443
|
);
|
|
407
444
|
}
|
|
408
445
|
case 'navbar-start': {
|
|
@@ -419,6 +456,7 @@ export const SpacePlugin = ({
|
|
|
419
456
|
? (space?.properties[CollectionType.typename] as CollectionType)
|
|
420
457
|
: undefined
|
|
421
458
|
: data.object;
|
|
459
|
+
|
|
422
460
|
return space && object
|
|
423
461
|
? {
|
|
424
462
|
node: (
|
|
@@ -436,11 +474,14 @@ export const SpacePlugin = ({
|
|
|
436
474
|
case 'settings':
|
|
437
475
|
return data.plugin === meta.id ? <SpaceSettings settings={settings.values} /> : null;
|
|
438
476
|
case 'menu-footer':
|
|
439
|
-
if (
|
|
440
|
-
return null;
|
|
441
|
-
} else {
|
|
477
|
+
if (isEchoObject(data.object)) {
|
|
442
478
|
return <MenuFooter object={data.object} />;
|
|
479
|
+
} else {
|
|
480
|
+
return null;
|
|
443
481
|
}
|
|
482
|
+
case 'status': {
|
|
483
|
+
return <SyncStatus />;
|
|
484
|
+
}
|
|
444
485
|
default:
|
|
445
486
|
return null;
|
|
446
487
|
}
|
|
@@ -456,8 +497,7 @@ export const SpacePlugin = ({
|
|
|
456
497
|
const dispatch = intentPlugin?.provides.intent.dispatch;
|
|
457
498
|
const resolve = metadataPlugin?.provides.metadata.resolver;
|
|
458
499
|
const graph = graphPlugin?.provides.graph;
|
|
459
|
-
|
|
460
|
-
if (!graph || !dispatch || !resolve || !client) {
|
|
500
|
+
if (!client || !dispatch || !resolve || !graph) {
|
|
461
501
|
return [];
|
|
462
502
|
}
|
|
463
503
|
|
|
@@ -491,7 +531,6 @@ export const SpacePlugin = ({
|
|
|
491
531
|
type: SPACES,
|
|
492
532
|
properties: {
|
|
493
533
|
label: ['spaces label', { ns: SPACE_PLUGIN }],
|
|
494
|
-
palette: 'teal',
|
|
495
534
|
testId: 'spacePlugin.spaces',
|
|
496
535
|
role: 'branch',
|
|
497
536
|
childrenPersistenceClass: 'echo',
|
|
@@ -540,10 +579,10 @@ export const SpacePlugin = ({
|
|
|
540
579
|
},
|
|
541
580
|
properties: {
|
|
542
581
|
label: ['create space label', { ns: SPACE_PLUGIN }],
|
|
543
|
-
icon:
|
|
544
|
-
|
|
545
|
-
disposition: 'toolbar',
|
|
582
|
+
icon: 'ph--plus--regular',
|
|
583
|
+
disposition: 'item',
|
|
546
584
|
testId: 'spacePlugin.createSpace',
|
|
585
|
+
className: 'pbs-4',
|
|
547
586
|
},
|
|
548
587
|
},
|
|
549
588
|
{
|
|
@@ -561,9 +600,10 @@ export const SpacePlugin = ({
|
|
|
561
600
|
},
|
|
562
601
|
properties: {
|
|
563
602
|
label: ['join space label', { ns: SPACE_PLUGIN }],
|
|
564
|
-
icon:
|
|
565
|
-
|
|
603
|
+
icon: 'ph--sign-in--regular',
|
|
604
|
+
disposition: 'item',
|
|
566
605
|
testId: 'spacePlugin.joinSpace',
|
|
606
|
+
className: 'pbe-4',
|
|
567
607
|
},
|
|
568
608
|
},
|
|
569
609
|
],
|
|
@@ -707,6 +747,76 @@ export const SpacePlugin = ({
|
|
|
707
747
|
.filter(nonNullable);
|
|
708
748
|
},
|
|
709
749
|
}),
|
|
750
|
+
|
|
751
|
+
// Create nodes for object settings.
|
|
752
|
+
createExtension({
|
|
753
|
+
id: `${SPACE_PLUGIN}/settings-for-subject`,
|
|
754
|
+
resolver: ({ id }) => {
|
|
755
|
+
// TODO(Zan): Find util (or make one).
|
|
756
|
+
if (!id.endsWith('~settings')) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const type = 'orphan-settings-for-subject';
|
|
761
|
+
const icon = 'ph--gear--regular';
|
|
762
|
+
|
|
763
|
+
const [subjectId] = id.split('~');
|
|
764
|
+
const { spaceId, objectId } = parseId(subjectId);
|
|
765
|
+
const space = client.spaces.get().find((space) => space.id === spaceId);
|
|
766
|
+
if (!objectId) {
|
|
767
|
+
const label = space
|
|
768
|
+
? space.properties.name || ['unnamed space label', { ns: SPACE_PLUGIN }]
|
|
769
|
+
: ['unnamed object settings label', { ns: SPACE_PLUGIN }];
|
|
770
|
+
|
|
771
|
+
// TODO(wittjosiah): Support comments for arbitrary subjects.
|
|
772
|
+
// This is to ensure that the comments panel is not stuck on an old object.
|
|
773
|
+
return {
|
|
774
|
+
id,
|
|
775
|
+
type,
|
|
776
|
+
data: null,
|
|
777
|
+
properties: {
|
|
778
|
+
icon,
|
|
779
|
+
label,
|
|
780
|
+
showResolvedThreads: false,
|
|
781
|
+
object: null,
|
|
782
|
+
space,
|
|
783
|
+
},
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const object = toSignal(
|
|
788
|
+
(onChange) => {
|
|
789
|
+
const timeout = setTimeout(async () => {
|
|
790
|
+
await space?.db.loadObjectById(objectId);
|
|
791
|
+
onChange();
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
return () => clearTimeout(timeout);
|
|
795
|
+
},
|
|
796
|
+
() => space?.db.getObjectById(objectId),
|
|
797
|
+
subjectId,
|
|
798
|
+
);
|
|
799
|
+
if (!object || !subjectId) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
const meta = resolve(getTypename(object) ?? '');
|
|
804
|
+
const label = meta.label?.(object) ||
|
|
805
|
+
object.name ||
|
|
806
|
+
meta.placeholder || ['unnamed object settings label', { ns: SPACE_PLUGIN }];
|
|
807
|
+
|
|
808
|
+
return {
|
|
809
|
+
id,
|
|
810
|
+
type,
|
|
811
|
+
data: null,
|
|
812
|
+
properties: {
|
|
813
|
+
icon,
|
|
814
|
+
label,
|
|
815
|
+
object,
|
|
816
|
+
},
|
|
817
|
+
};
|
|
818
|
+
},
|
|
819
|
+
}),
|
|
710
820
|
];
|
|
711
821
|
},
|
|
712
822
|
serializer: (plugins) => {
|
|
@@ -802,9 +912,21 @@ export const SpacePlugin = ({
|
|
|
802
912
|
}
|
|
803
913
|
|
|
804
914
|
return {
|
|
805
|
-
data: {
|
|
806
|
-
|
|
915
|
+
data: {
|
|
916
|
+
space,
|
|
917
|
+
id: space.id,
|
|
918
|
+
activeParts: { main: [space.id] },
|
|
919
|
+
},
|
|
807
920
|
intents: [
|
|
921
|
+
...(settings.values.onSpaceCreate
|
|
922
|
+
? [
|
|
923
|
+
[
|
|
924
|
+
{ action: settings.values.onSpaceCreate, data: { space } },
|
|
925
|
+
{ action: SpaceAction.ADD_OBJECT, data: { target: space } },
|
|
926
|
+
{ action: NavigationAction.EXPOSE },
|
|
927
|
+
],
|
|
928
|
+
]
|
|
929
|
+
: []),
|
|
808
930
|
[
|
|
809
931
|
{
|
|
810
932
|
action: ObservabilityAction.SEND_EVENT,
|
|
@@ -825,9 +947,26 @@ export const SpacePlugin = ({
|
|
|
825
947
|
const { space } = await client.shell.joinSpace({ invitationCode: intent.data?.invitationCode });
|
|
826
948
|
if (space) {
|
|
827
949
|
return {
|
|
828
|
-
data: {
|
|
829
|
-
|
|
950
|
+
data: {
|
|
951
|
+
space,
|
|
952
|
+
id: space.id,
|
|
953
|
+
activeParts: { main: [space.id] },
|
|
954
|
+
},
|
|
830
955
|
intents: [
|
|
956
|
+
[
|
|
957
|
+
{
|
|
958
|
+
action: LayoutAction.SET_LAYOUT,
|
|
959
|
+
data: {
|
|
960
|
+
element: 'toast',
|
|
961
|
+
subject: {
|
|
962
|
+
id: `${SPACE_PLUGIN}/join-success`,
|
|
963
|
+
duration: 10_000,
|
|
964
|
+
title: translations[0]['en-US'][SPACE_PLUGIN]['join success label'],
|
|
965
|
+
closeLabel: translations[0]['en-US'][SPACE_PLUGIN]['dismiss label'],
|
|
966
|
+
},
|
|
967
|
+
},
|
|
968
|
+
},
|
|
969
|
+
],
|
|
831
970
|
[
|
|
832
971
|
{
|
|
833
972
|
action: ObservabilityAction.SEND_EVENT,
|
|
@@ -1020,8 +1159,7 @@ export const SpacePlugin = ({
|
|
|
1020
1159
|
title: translations[0]['en-US'][SPACE_PLUGIN]['space limit label'],
|
|
1021
1160
|
description: translations[0]['en-US'][SPACE_PLUGIN]['space limit description'],
|
|
1022
1161
|
duration: 5_000,
|
|
1023
|
-
icon:
|
|
1024
|
-
iconSymbol: 'ph--warning--regular',
|
|
1162
|
+
icon: 'ph--warning--regular',
|
|
1025
1163
|
actionLabel: translations[0]['en-US'][SPACE_PLUGIN]['remove deleted objects label'],
|
|
1026
1164
|
actionAlt: translations[0]['en-US'][SPACE_PLUGIN]['remove deleted objects alt'],
|
|
1027
1165
|
// TODO(wittjosiah): Use OS namespace.
|
|
@@ -1047,20 +1185,20 @@ export const SpacePlugin = ({
|
|
|
1047
1185
|
}
|
|
1048
1186
|
|
|
1049
1187
|
if (intent.data?.target instanceof CollectionType) {
|
|
1050
|
-
intent.data?.target.objects.push(object as
|
|
1188
|
+
intent.data?.target.objects.push(object as HasId);
|
|
1051
1189
|
} else if (isSpace(intent.data?.target)) {
|
|
1052
1190
|
const collection = space.properties[CollectionType.typename];
|
|
1053
1191
|
if (collection instanceof CollectionType) {
|
|
1054
|
-
collection.objects.push(object as
|
|
1192
|
+
collection.objects.push(object as HasId);
|
|
1055
1193
|
} else {
|
|
1056
1194
|
// TODO(wittjosiah): Can't add non-echo objects by including in a collection because of types.
|
|
1057
|
-
const collection = create(CollectionType, { objects: [object as
|
|
1195
|
+
const collection = create(CollectionType, { objects: [object as HasId], views: {} });
|
|
1058
1196
|
space.properties[CollectionType.typename] = collection;
|
|
1059
1197
|
}
|
|
1060
1198
|
}
|
|
1061
1199
|
|
|
1062
1200
|
return {
|
|
1063
|
-
data: { id: object
|
|
1201
|
+
data: { id: fullyQualifiedId(object), object, activeParts: { main: [fullyQualifiedId(object)] } },
|
|
1064
1202
|
intents: [
|
|
1065
1203
|
[
|
|
1066
1204
|
{
|
|
@@ -1115,7 +1253,6 @@ export const SpacePlugin = ({
|
|
|
1115
1253
|
activeParts: {
|
|
1116
1254
|
main: deletionData.wasActive,
|
|
1117
1255
|
sidebar: deletionData.wasActive,
|
|
1118
|
-
complementary: deletionData.wasActive,
|
|
1119
1256
|
},
|
|
1120
1257
|
},
|
|
1121
1258
|
});
|
|
@@ -1203,11 +1340,12 @@ export const SpacePlugin = ({
|
|
|
1203
1340
|
case SpaceAction.DUPLICATE_OBJECT: {
|
|
1204
1341
|
const originalObject = intent.data?.object ?? intent.data?.result;
|
|
1205
1342
|
const resolve = resolvePlugin(plugins, parseMetadataResolverPlugin)?.provides.metadata.resolver;
|
|
1206
|
-
|
|
1343
|
+
const space = isSpace(intent.data?.target) ? intent.data?.target : getSpace(intent.data?.target);
|
|
1344
|
+
if (!isEchoObject(originalObject) || !resolve || !space) {
|
|
1207
1345
|
return;
|
|
1208
1346
|
}
|
|
1209
1347
|
|
|
1210
|
-
const newObject = await cloneObject(originalObject, resolve);
|
|
1348
|
+
const newObject = await cloneObject(originalObject, resolve, space);
|
|
1211
1349
|
return {
|
|
1212
1350
|
intents: [
|
|
1213
1351
|
[{ action: SpaceAction.ADD_OBJECT, data: { object: newObject, target: intent.data?.target } }],
|