@dxos/plugin-space 0.7.2 → 0.7.3-staging.0905f03
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-DJE2HYFV.mjs → chunk-FTKV32QZ.mjs} +9 -2
- package/dist/lib/browser/chunk-FTKV32QZ.mjs.map +7 -0
- package/dist/lib/browser/{chunk-OWZKSWMX.mjs → chunk-MWKXNS5S.mjs} +13 -3
- package/dist/lib/browser/{chunk-OWZKSWMX.mjs.map → chunk-MWKXNS5S.mjs.map} +3 -3
- package/dist/lib/browser/index.mjs +1167 -786
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +3 -1
- package/dist/lib/browser/types/index.mjs +5 -3
- package/dist/lib/node/{chunk-FYWGZYJB.cjs → chunk-6SNOZF7Y.cjs} +18 -7
- package/dist/lib/node/chunk-6SNOZF7Y.cjs.map +7 -0
- package/dist/lib/node/{chunk-JFDDZI4Y.cjs → chunk-QNVEU2UD.cjs} +12 -4
- package/dist/lib/node/chunk-QNVEU2UD.cjs.map +7 -0
- package/dist/lib/node/index.cjs +1210 -839
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.cjs +7 -5
- package/dist/lib/node/meta.cjs.map +2 -2
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +14 -12
- package/dist/lib/node/types/index.cjs.map +2 -2
- package/dist/lib/node-esm/{chunk-MCEAI4CV.mjs → chunk-OHEAWSCA.mjs} +13 -3
- package/dist/lib/node-esm/{chunk-MCEAI4CV.mjs.map → chunk-OHEAWSCA.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-DVUZ7A7G.mjs → chunk-UMV7XREB.mjs} +9 -2
- package/dist/lib/node-esm/chunk-UMV7XREB.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1167 -786
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/meta.mjs +3 -1
- package/dist/lib/node-esm/types/index.mjs +5 -3
- package/dist/types/src/SpacePlugin.d.ts.map +1 -1
- package/dist/types/src/components/CreateDialog/CreateObjectDialog.d.ts +9 -0
- package/dist/types/src/components/CreateDialog/CreateObjectDialog.d.ts.map +1 -0
- package/dist/types/src/components/CreateDialog/CreateObjectDialog.stories.d.ts +10 -0
- package/dist/types/src/components/CreateDialog/CreateObjectDialog.stories.d.ts.map +1 -0
- package/dist/types/src/components/CreateDialog/CreateObjectPanel.d.ts +22 -0
- package/dist/types/src/components/CreateDialog/CreateObjectPanel.d.ts.map +1 -0
- package/dist/types/src/components/CreateDialog/CreateSpaceDialog.d.ts +3 -0
- package/dist/types/src/components/CreateDialog/CreateSpaceDialog.d.ts.map +1 -0
- package/dist/types/src/components/CreateDialog/index.d.ts +3 -0
- package/dist/types/src/components/CreateDialog/index.d.ts.map +1 -0
- package/dist/types/src/components/PopoverRenameObject.d.ts +1 -1
- package/dist/types/src/components/SpacePluginSettings.d.ts.map +1 -1
- package/dist/types/src/components/SpaceSettings/SpaceSettingsDialog.d.ts.map +1 -1
- package/dist/types/src/components/SpaceSettings/SpaceSettingsPanel.d.ts.map +1 -1
- package/dist/types/src/components/SyncStatus/InlineSyncStatus.d.ts +7 -0
- package/dist/types/src/components/SyncStatus/InlineSyncStatus.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/InlineSyncStatus.stories.d.ts +6 -0
- package/dist/types/src/components/SyncStatus/InlineSyncStatus.stories.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/Space.d.ts +8 -3
- package/dist/types/src/components/SyncStatus/Space.d.ts.map +1 -1
- package/dist/types/src/components/SyncStatus/SyncStatus.d.ts +3 -2
- package/dist/types/src/components/SyncStatus/SyncStatus.d.ts.map +1 -1
- package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts +4 -4
- package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts.map +1 -1
- package/dist/types/src/components/SyncStatus/SyncStatusDetail.stories.d.ts +9 -0
- package/dist/types/src/components/SyncStatus/SyncStatusDetail.stories.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/index.d.ts +1 -0
- package/dist/types/src/components/SyncStatus/index.d.ts.map +1 -1
- package/dist/types/src/components/SyncStatus/sync-state.d.ts +5 -1
- package/dist/types/src/components/SyncStatus/sync-state.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +5 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +224 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +14 -14
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +3 -13
- package/dist/types/src/util.d.ts.map +1 -1
- package/package.json +38 -35
- package/src/SpacePlugin.tsx +203 -128
- package/src/components/AwaitingObject.tsx +2 -2
- package/src/components/CreateDialog/CreateObjectDialog.stories.tsx +83 -0
- package/src/components/CreateDialog/CreateObjectDialog.tsx +98 -0
- package/src/components/CreateDialog/CreateObjectPanel.tsx +169 -0
- package/src/components/CreateDialog/CreateSpaceDialog.tsx +57 -0
- package/src/components/CreateDialog/index.ts +6 -0
- package/src/components/PopoverRenameObject.tsx +1 -1
- package/src/components/SpacePluginSettings.tsx +3 -32
- package/src/components/SpaceSettings/SpaceSettingsDialog.tsx +5 -5
- package/src/components/SpaceSettings/SpaceSettingsPanel.tsx +2 -6
- package/src/components/SyncStatus/InlineSyncStatus.stories.tsx +57 -0
- package/src/components/SyncStatus/InlineSyncStatus.tsx +61 -0
- package/src/components/SyncStatus/Space.tsx +30 -6
- package/src/components/SyncStatus/SyncStatus.stories.tsx +15 -42
- package/src/components/SyncStatus/SyncStatus.tsx +32 -14
- package/src/components/SyncStatus/SyncStatusDetail.stories.tsx +85 -0
- package/src/components/SyncStatus/index.ts +1 -0
- package/src/components/SyncStatus/sync-state.ts +24 -0
- package/src/components/index.ts +1 -0
- package/src/meta.ts +6 -0
- package/src/translations.ts +15 -0
- package/src/types/types.ts +20 -16
- package/src/util.tsx +51 -141
- package/dist/lib/browser/chunk-DJE2HYFV.mjs.map +0 -7
- package/dist/lib/node/chunk-FYWGZYJB.cjs.map +0 -7
- package/dist/lib/node/chunk-JFDDZI4Y.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-DVUZ7A7G.mjs.map +0 -7
package/src/SpacePlugin.tsx
CHANGED
|
@@ -12,10 +12,12 @@ import {
|
|
|
12
12
|
LayoutAction,
|
|
13
13
|
type LayoutProvides,
|
|
14
14
|
type LocationProvides,
|
|
15
|
+
type MetadataResolverProvides,
|
|
15
16
|
NavigationAction,
|
|
16
17
|
type Plugin,
|
|
17
18
|
type PluginDefinition,
|
|
18
19
|
Surface,
|
|
20
|
+
filterPlugins,
|
|
19
21
|
findPlugin,
|
|
20
22
|
firstIdInPart,
|
|
21
23
|
openIds,
|
|
@@ -27,9 +29,10 @@ import {
|
|
|
27
29
|
resolvePlugin,
|
|
28
30
|
} from '@dxos/app-framework';
|
|
29
31
|
import { EventSubscriptions, type Trigger, type UnsubscribeCallback } from '@dxos/async';
|
|
30
|
-
import { type
|
|
32
|
+
import { S, type AbstractTypedObject, type HasId } from '@dxos/echo-schema';
|
|
31
33
|
import { scheduledEffect } from '@dxos/echo-signals/core';
|
|
32
34
|
import { invariant } from '@dxos/invariant';
|
|
35
|
+
import { create, isDeleted, isReactiveObject } from '@dxos/live-object';
|
|
33
36
|
import { LocalStorageStore } from '@dxos/local-storage';
|
|
34
37
|
import { log } from '@dxos/log';
|
|
35
38
|
import { Migrations } from '@dxos/migrations';
|
|
@@ -37,25 +40,25 @@ import { type AttentionPluginProvides, parseAttentionPlugin } from '@dxos/plugin
|
|
|
37
40
|
import { type ClientPluginProvides, parseClientPlugin } from '@dxos/plugin-client';
|
|
38
41
|
import { type Node, createExtension, memoize, toSignal } from '@dxos/plugin-graph';
|
|
39
42
|
import { ObservabilityAction } from '@dxos/plugin-observability/meta';
|
|
43
|
+
import { EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
40
44
|
import { type Client, PublicKey } from '@dxos/react-client';
|
|
41
45
|
import {
|
|
42
|
-
type ReactiveEchoObject,
|
|
43
46
|
Expando,
|
|
47
|
+
FQ_ID_LENGTH,
|
|
44
48
|
Filter,
|
|
45
|
-
|
|
49
|
+
OBJECT_ID_LENGTH,
|
|
50
|
+
type ReactiveEchoObject,
|
|
51
|
+
SPACE_ID_LENGTH,
|
|
46
52
|
type Space,
|
|
47
53
|
SpaceState,
|
|
48
|
-
create,
|
|
49
54
|
fullyQualifiedId,
|
|
50
55
|
getSpace,
|
|
51
56
|
getTypename,
|
|
52
57
|
isEchoObject,
|
|
53
58
|
isSpace,
|
|
54
59
|
loadObjectReferences,
|
|
60
|
+
parseFullyQualifiedId,
|
|
55
61
|
parseId,
|
|
56
|
-
FQ_ID_LENGTH,
|
|
57
|
-
SPACE_ID_LENGTH,
|
|
58
|
-
OBJECT_ID_LENGTH,
|
|
59
62
|
} from '@dxos/react-client/echo';
|
|
60
63
|
import { type JoinPanelProps, osTranslations } from '@dxos/shell/react';
|
|
61
64
|
import { ComplexMap, nonNullable, reduceGroupBy } from '@dxos/util';
|
|
@@ -64,33 +67,42 @@ import {
|
|
|
64
67
|
AwaitingObject,
|
|
65
68
|
CollectionMain,
|
|
66
69
|
CollectionSection,
|
|
70
|
+
CreateObjectDialog,
|
|
71
|
+
type CreateObjectDialogProps,
|
|
72
|
+
CreateSpaceDialog,
|
|
67
73
|
DefaultObjectSettings,
|
|
68
74
|
JoinDialog,
|
|
75
|
+
InlineSyncStatus,
|
|
69
76
|
MenuFooter,
|
|
70
77
|
PopoverRenameObject,
|
|
71
78
|
PopoverRenameSpace,
|
|
72
79
|
ShareSpaceButton,
|
|
73
80
|
SmallPresence,
|
|
74
81
|
SmallPresenceLive,
|
|
75
|
-
SpacePresence,
|
|
76
82
|
SpacePluginSettings,
|
|
83
|
+
SpacePresence,
|
|
84
|
+
SpaceSettingsDialog,
|
|
77
85
|
SpaceSettingsPanel,
|
|
78
86
|
SyncStatus,
|
|
79
|
-
SpaceSettingsDialog,
|
|
80
87
|
type SpaceSettingsDialogProps,
|
|
81
88
|
} from './components';
|
|
82
|
-
import meta, { SPACE_PLUGIN, SpaceAction } from './meta';
|
|
89
|
+
import meta, { CollectionAction, SPACE_PLUGIN, SpaceAction } from './meta';
|
|
83
90
|
import translations from './translations';
|
|
84
|
-
import {
|
|
91
|
+
import {
|
|
92
|
+
CollectionType,
|
|
93
|
+
parseSchemaPlugin,
|
|
94
|
+
SpaceForm,
|
|
95
|
+
type PluginState,
|
|
96
|
+
type SpacePluginProvides,
|
|
97
|
+
type SpaceSettingsProps,
|
|
98
|
+
} from './types';
|
|
85
99
|
import {
|
|
86
100
|
COMPOSER_SPACE_LOCK,
|
|
87
101
|
SHARED,
|
|
88
102
|
SPACES,
|
|
89
103
|
SPACE_TYPE,
|
|
90
104
|
cloneObject,
|
|
91
|
-
constructObjectActionGroups,
|
|
92
105
|
constructObjectActions,
|
|
93
|
-
constructSpaceActionGroups,
|
|
94
106
|
constructSpaceActions,
|
|
95
107
|
constructSpaceNode,
|
|
96
108
|
createObjectNode,
|
|
@@ -142,9 +154,7 @@ export const SpacePlugin = ({
|
|
|
142
154
|
firstRun,
|
|
143
155
|
onFirstRun,
|
|
144
156
|
}: SpacePluginOptions = {}): PluginDefinition<SpacePluginProvides> => {
|
|
145
|
-
const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN, {
|
|
146
|
-
onSpaceCreate: 'dxos.org/plugin/markdown/action/create',
|
|
147
|
-
});
|
|
157
|
+
const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN, {});
|
|
148
158
|
const state = new LocalStorageStore<PluginState>(SPACE_PLUGIN, {
|
|
149
159
|
awaiting: undefined,
|
|
150
160
|
spaceNames: {},
|
|
@@ -153,10 +163,12 @@ export const SpacePlugin = ({
|
|
|
153
163
|
viewersByIdentity: new ComplexMap(PublicKey.hash),
|
|
154
164
|
sdkMigrationRunning: {},
|
|
155
165
|
navigableCollections: false,
|
|
166
|
+
enabledEdgeReplication: false,
|
|
156
167
|
});
|
|
157
168
|
const subscriptions = new EventSubscriptions();
|
|
158
169
|
const spaceSubscriptions = new EventSubscriptions();
|
|
159
170
|
const graphSubscriptions = new Map<string, UnsubscribeCallback>();
|
|
171
|
+
const schemas: AbstractTypedObject[] = [];
|
|
160
172
|
|
|
161
173
|
let clientPlugin: Plugin<ClientPluginProvides> | undefined;
|
|
162
174
|
let graphPlugin: Plugin<GraphProvides> | undefined;
|
|
@@ -164,6 +176,7 @@ export const SpacePlugin = ({
|
|
|
164
176
|
let layoutPlugin: Plugin<LayoutProvides> | undefined;
|
|
165
177
|
let navigationPlugin: Plugin<LocationProvides> | undefined;
|
|
166
178
|
let attentionPlugin: Plugin<AttentionPluginProvides> | undefined;
|
|
179
|
+
let metadataPlugin: Plugin<MetadataResolverProvides> | undefined;
|
|
167
180
|
|
|
168
181
|
const createSpaceInvitationUrl = (invitationCode: string) => {
|
|
169
182
|
const baseUrl = new URL(invitationUrl);
|
|
@@ -254,18 +267,31 @@ export const SpacePlugin = ({
|
|
|
254
267
|
subscriptions.add(
|
|
255
268
|
scheduledEffect(
|
|
256
269
|
() => ({
|
|
257
|
-
|
|
258
|
-
|
|
270
|
+
open: openIds(location.active, layout.layoutMode === 'solo' ? ['solo'] : ['main']),
|
|
271
|
+
closed: [...location.closed],
|
|
259
272
|
}),
|
|
260
|
-
({
|
|
273
|
+
({ open, closed }) => {
|
|
261
274
|
const send = () => {
|
|
262
275
|
const spaces = client.spaces.get();
|
|
263
276
|
const identity = client.halo.identity.get();
|
|
264
277
|
if (identity && location.active) {
|
|
265
278
|
// Group parts by space for efficient messaging.
|
|
266
|
-
const idsBySpace = reduceGroupBy(
|
|
267
|
-
|
|
268
|
-
|
|
279
|
+
const idsBySpace = reduceGroupBy(open, (id) => {
|
|
280
|
+
try {
|
|
281
|
+
const [spaceId] = parseFullyQualifiedId(id);
|
|
282
|
+
return spaceId;
|
|
283
|
+
} catch {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const removedBySpace = reduceGroupBy(closed, (id) => {
|
|
289
|
+
try {
|
|
290
|
+
const [spaceId] = parseFullyQualifiedId(id);
|
|
291
|
+
return spaceId;
|
|
292
|
+
} catch {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
269
295
|
});
|
|
270
296
|
|
|
271
297
|
// NOTE: Ensure all spaces are included so that we send the correct `removed` object arrays.
|
|
@@ -275,7 +301,8 @@ export const SpacePlugin = ({
|
|
|
275
301
|
}
|
|
276
302
|
}
|
|
277
303
|
|
|
278
|
-
for (const [spaceId,
|
|
304
|
+
for (const [spaceId, added] of idsBySpace) {
|
|
305
|
+
const removed = removedBySpace.get(spaceId) ?? [];
|
|
279
306
|
const space = spaces.find((space) => space.id === spaceId);
|
|
280
307
|
if (!space) {
|
|
281
308
|
continue;
|
|
@@ -285,9 +312,8 @@ export const SpacePlugin = ({
|
|
|
285
312
|
.postMessage('viewing', {
|
|
286
313
|
identityKey: identity.identityKey.toHex(),
|
|
287
314
|
attended: attention.attended ? [...attention.attended] : [],
|
|
288
|
-
added
|
|
289
|
-
|
|
290
|
-
removed: removed.filter((id) => !ids.includes(id)),
|
|
315
|
+
added,
|
|
316
|
+
removed,
|
|
291
317
|
})
|
|
292
318
|
// TODO(burdon): This seems defensive; why would this fail? Backoff interval.
|
|
293
319
|
.catch((err) => {
|
|
@@ -298,6 +324,7 @@ export const SpacePlugin = ({
|
|
|
298
324
|
};
|
|
299
325
|
|
|
300
326
|
send();
|
|
327
|
+
// Send at interval to allow peers to expire entries if they become disconnected.
|
|
301
328
|
const interval = setInterval(() => send(), ACTIVE_NODE_BROADCAST_INTERVAL);
|
|
302
329
|
return () => clearInterval(interval);
|
|
303
330
|
},
|
|
@@ -314,7 +341,13 @@ export const SpacePlugin = ({
|
|
|
314
341
|
const { added, removed, attended } = message.payload;
|
|
315
342
|
|
|
316
343
|
const identityKey = PublicKey.safeFrom(message.payload.identityKey);
|
|
317
|
-
|
|
344
|
+
const currentIdentity = client.halo.identity.get();
|
|
345
|
+
if (
|
|
346
|
+
identityKey &&
|
|
347
|
+
!currentIdentity?.identityKey.equals(identityKey) &&
|
|
348
|
+
Array.isArray(added) &&
|
|
349
|
+
Array.isArray(removed)
|
|
350
|
+
) {
|
|
318
351
|
added.forEach((id) => {
|
|
319
352
|
if (typeof id === 'string') {
|
|
320
353
|
if (!(id in state.values.viewersByObject)) {
|
|
@@ -346,11 +379,24 @@ export const SpacePlugin = ({
|
|
|
346
379
|
);
|
|
347
380
|
};
|
|
348
381
|
|
|
382
|
+
const setEdgeReplicationDefault = async (client: Client) => {
|
|
383
|
+
try {
|
|
384
|
+
await Promise.all(
|
|
385
|
+
client.spaces.get().map((space) => space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED)),
|
|
386
|
+
);
|
|
387
|
+
state.values.enabledEdgeReplication = true;
|
|
388
|
+
} catch (err) {
|
|
389
|
+
log.catch(err);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
349
393
|
return {
|
|
350
394
|
meta,
|
|
351
395
|
ready: async (plugins) => {
|
|
352
396
|
settings.prop({ key: 'showHidden', type: LocalStorageStore.bool({ allowUndefined: true }) });
|
|
353
|
-
state
|
|
397
|
+
state
|
|
398
|
+
.prop({ key: 'spaceNames', type: LocalStorageStore.json<Record<string, string>>() })
|
|
399
|
+
.prop({ key: 'enabledEdgeReplication', type: LocalStorageStore.bool() });
|
|
354
400
|
|
|
355
401
|
// TODO(wittjosiah): Hardcoded due to circular dependency.
|
|
356
402
|
// Should be based on a provides interface.
|
|
@@ -360,6 +406,7 @@ export const SpacePlugin = ({
|
|
|
360
406
|
|
|
361
407
|
graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
|
|
362
408
|
layoutPlugin = resolvePlugin(plugins, parseLayoutPlugin);
|
|
409
|
+
metadataPlugin = resolvePlugin(plugins, parseMetadataResolverPlugin);
|
|
363
410
|
navigationPlugin = resolvePlugin(plugins, parseNavigationPlugin);
|
|
364
411
|
attentionPlugin = resolvePlugin(plugins, parseAttentionPlugin);
|
|
365
412
|
clientPlugin = resolvePlugin(plugins, parseClientPlugin);
|
|
@@ -371,6 +418,21 @@ export const SpacePlugin = ({
|
|
|
371
418
|
const client = clientPlugin.provides.client;
|
|
372
419
|
const dispatch = intentPlugin.provides.intent.dispatch;
|
|
373
420
|
|
|
421
|
+
schemas.push(
|
|
422
|
+
...filterPlugins(plugins, parseSchemaPlugin)
|
|
423
|
+
.map((plugin) => plugin.provides.echo.schema)
|
|
424
|
+
.filter(nonNullable)
|
|
425
|
+
.reduce((acc, schema) => {
|
|
426
|
+
return [...acc, ...schema];
|
|
427
|
+
}),
|
|
428
|
+
);
|
|
429
|
+
client.addTypes(schemas);
|
|
430
|
+
filterPlugins(plugins, parseSchemaPlugin).forEach((plugin) => {
|
|
431
|
+
if (plugin.provides.echo.system) {
|
|
432
|
+
client.addTypes(plugin.provides.echo.system);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
374
436
|
const handleFirstRun = async () => {
|
|
375
437
|
const defaultSpace = client.spaces.default;
|
|
376
438
|
|
|
@@ -393,6 +455,7 @@ export const SpacePlugin = ({
|
|
|
393
455
|
}
|
|
394
456
|
|
|
395
457
|
await onSpaceReady();
|
|
458
|
+
await setEdgeReplicationDefault(client);
|
|
396
459
|
}
|
|
397
460
|
}).unsubscribe,
|
|
398
461
|
);
|
|
@@ -417,6 +480,7 @@ export const SpacePlugin = ({
|
|
|
417
480
|
metadata: {
|
|
418
481
|
records: {
|
|
419
482
|
[CollectionType.typename]: {
|
|
483
|
+
createObject: CollectionAction.CREATE,
|
|
420
484
|
placeholder: ['unnamed collection label', { ns: SPACE_PLUGIN }],
|
|
421
485
|
icon: 'ph--cards-three--regular',
|
|
422
486
|
// TODO(wittjosiah): Move out of metadata.
|
|
@@ -448,6 +512,7 @@ export const SpacePlugin = ({
|
|
|
448
512
|
disposition: 'fallback',
|
|
449
513
|
}
|
|
450
514
|
) : null;
|
|
515
|
+
// TODO(burdon): Add role name syntax to minimal plugin docs.
|
|
451
516
|
case 'complementary--settings':
|
|
452
517
|
return isSpace(data.subject) ? (
|
|
453
518
|
<SpaceSettingsPanel space={data.subject} />
|
|
@@ -464,6 +529,17 @@ export const SpacePlugin = ({
|
|
|
464
529
|
);
|
|
465
530
|
} else if (data.component === 'dxos.org/plugin/space/JoinDialog') {
|
|
466
531
|
return <JoinDialog {...(data.subject as JoinPanelProps)} />;
|
|
532
|
+
} else if (data.component === 'dxos.org/plugin/space/CreateSpaceDialog') {
|
|
533
|
+
return <CreateSpaceDialog />;
|
|
534
|
+
} else if (data.component === 'dxos.org/plugin/space/CreateObjectDialog') {
|
|
535
|
+
return (
|
|
536
|
+
<CreateObjectDialog
|
|
537
|
+
{...(data.subject as CreateObjectDialogProps)}
|
|
538
|
+
schemas={schemas}
|
|
539
|
+
navigableCollections={state.values.navigableCollections}
|
|
540
|
+
resolve={metadataPlugin?.provides.metadata.resolver}
|
|
541
|
+
/>
|
|
542
|
+
);
|
|
467
543
|
}
|
|
468
544
|
return null;
|
|
469
545
|
case 'popover': {
|
|
@@ -475,20 +551,19 @@ export const SpacePlugin = ({
|
|
|
475
551
|
}
|
|
476
552
|
return null;
|
|
477
553
|
}
|
|
478
|
-
|
|
479
|
-
case 'presence--glyph': {
|
|
554
|
+
case 'navtree-item-end': {
|
|
480
555
|
return isReactiveObject(data.object) ? (
|
|
481
556
|
<SmallPresenceLive
|
|
482
557
|
id={data.id as string}
|
|
483
558
|
viewers={state.values.viewersByObject[fullyQualifiedId(data.object)]}
|
|
484
559
|
/>
|
|
560
|
+
) : isSpace(data.object) ? (
|
|
561
|
+
<InlineSyncStatus space={data.object} />
|
|
485
562
|
) : (
|
|
563
|
+
// TODO(wittjosiah): Attention glyph for non-echo items should be handled elsewhere.
|
|
486
564
|
<SmallPresence id={data.id as string} count={0} />
|
|
487
565
|
);
|
|
488
566
|
}
|
|
489
|
-
case 'navbar-start': {
|
|
490
|
-
return null;
|
|
491
|
-
}
|
|
492
567
|
case 'navbar-end': {
|
|
493
568
|
if (!isEchoObject(data.object) && !isSpace(data.object)) {
|
|
494
569
|
return null;
|
|
@@ -545,64 +620,45 @@ export const SpacePlugin = ({
|
|
|
545
620
|
return [];
|
|
546
621
|
}
|
|
547
622
|
|
|
623
|
+
const spacesNode = {
|
|
624
|
+
id: SPACES,
|
|
625
|
+
type: SPACES,
|
|
626
|
+
cacheable: ['label', 'role'],
|
|
627
|
+
properties: {
|
|
628
|
+
label: ['spaces label', { ns: SPACE_PLUGIN }],
|
|
629
|
+
testId: 'spacePlugin.spaces',
|
|
630
|
+
role: 'branch',
|
|
631
|
+
disabled: true,
|
|
632
|
+
childrenPersistenceClass: 'echo',
|
|
633
|
+
onRearrangeChildren: async (nextOrder: Space[]) => {
|
|
634
|
+
// NOTE: This is needed to ensure order is updated by next animation frame.
|
|
635
|
+
// TODO(wittjosiah): Is there a better way to do this?
|
|
636
|
+
// If not, graph should be passed as an argument to the extension.
|
|
637
|
+
graph._sortEdges(
|
|
638
|
+
SPACES,
|
|
639
|
+
'outbound',
|
|
640
|
+
nextOrder.map(({ id }) => id),
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
const {
|
|
644
|
+
objects: [spacesOrder],
|
|
645
|
+
} = await client.spaces.default.db.query(Filter.schema(Expando, { key: SHARED })).run();
|
|
646
|
+
if (spacesOrder) {
|
|
647
|
+
spacesOrder.order = nextOrder.map(({ id }) => id);
|
|
648
|
+
} else {
|
|
649
|
+
log.warn('spaces order object not found');
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
},
|
|
653
|
+
};
|
|
654
|
+
|
|
548
655
|
return [
|
|
549
656
|
// Create spaces group node.
|
|
550
657
|
createExtension({
|
|
551
658
|
id: `${SPACE_PLUGIN}/root`,
|
|
552
659
|
filter: (node): node is Node<null> => node.id === 'root',
|
|
553
|
-
connector: () =>
|
|
554
|
-
|
|
555
|
-
(onChange) => {
|
|
556
|
-
let defaultSpaceUnsubscribe: UnsubscribeCallback | undefined;
|
|
557
|
-
// No need to unsubscribe because this observable completes when spaces are ready.
|
|
558
|
-
client.spaces.isReady.subscribe((ready) => {
|
|
559
|
-
if (ready) {
|
|
560
|
-
defaultSpaceUnsubscribe = client.spaces.default.state.subscribe(() => onChange()).unsubscribe;
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
return () => defaultSpaceUnsubscribe?.();
|
|
565
|
-
},
|
|
566
|
-
() => client.spaces.isReady.get() && client.spaces.default.state.get() === SpaceState.SPACE_READY,
|
|
567
|
-
);
|
|
568
|
-
if (!isReady) {
|
|
569
|
-
return [];
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
return [
|
|
573
|
-
{
|
|
574
|
-
id: SPACES,
|
|
575
|
-
type: SPACES,
|
|
576
|
-
cacheable: ['label', 'role'],
|
|
577
|
-
properties: {
|
|
578
|
-
label: ['spaces label', { ns: SPACE_PLUGIN }],
|
|
579
|
-
testId: 'spacePlugin.spaces',
|
|
580
|
-
role: 'branch',
|
|
581
|
-
disabled: true,
|
|
582
|
-
childrenPersistenceClass: 'echo',
|
|
583
|
-
onRearrangeChildren: async (nextOrder: Space[]) => {
|
|
584
|
-
// NOTE: This is needed to ensure order is updated by next animation frame.
|
|
585
|
-
// TODO(wittjosiah): Is there a better way to do this?
|
|
586
|
-
// If not, graph should be passed as an argument to the extension.
|
|
587
|
-
graph._sortEdges(
|
|
588
|
-
SPACES,
|
|
589
|
-
'outbound',
|
|
590
|
-
nextOrder.map(({ id }) => id),
|
|
591
|
-
);
|
|
592
|
-
|
|
593
|
-
const {
|
|
594
|
-
objects: [spacesOrder],
|
|
595
|
-
} = await client.spaces.default.db.query(Filter.schema(Expando, { key: SHARED })).run();
|
|
596
|
-
if (spacesOrder) {
|
|
597
|
-
spacesOrder.order = nextOrder.map(({ id }) => id);
|
|
598
|
-
} else {
|
|
599
|
-
log.warn('spaces order object not found');
|
|
600
|
-
}
|
|
601
|
-
},
|
|
602
|
-
},
|
|
603
|
-
},
|
|
604
|
-
];
|
|
605
|
-
},
|
|
660
|
+
connector: () => [spacesNode],
|
|
661
|
+
resolver: ({ id }) => (id === SPACES ? spacesNode : undefined),
|
|
606
662
|
}),
|
|
607
663
|
|
|
608
664
|
// Create space nodes.
|
|
@@ -611,18 +667,18 @@ export const SpacePlugin = ({
|
|
|
611
667
|
filter: (node): node is Node<null> => node.id === SPACES,
|
|
612
668
|
actions: () => [
|
|
613
669
|
{
|
|
614
|
-
id: SpaceAction.
|
|
670
|
+
id: SpaceAction.OPEN_CREATE_SPACE,
|
|
615
671
|
data: async () => {
|
|
616
672
|
await dispatch({
|
|
617
673
|
plugin: SPACE_PLUGIN,
|
|
618
|
-
action: SpaceAction.
|
|
674
|
+
action: SpaceAction.OPEN_CREATE_SPACE,
|
|
619
675
|
});
|
|
620
676
|
},
|
|
621
677
|
properties: {
|
|
622
678
|
label: ['create space label', { ns: SPACE_PLUGIN }],
|
|
623
679
|
icon: 'ph--plus--regular',
|
|
624
|
-
disposition: 'item',
|
|
625
680
|
testId: 'spacePlugin.createSpace',
|
|
681
|
+
disposition: 'item',
|
|
626
682
|
className: 'border-t border-separator',
|
|
627
683
|
},
|
|
628
684
|
},
|
|
@@ -637,8 +693,8 @@ export const SpacePlugin = ({
|
|
|
637
693
|
properties: {
|
|
638
694
|
label: ['join space label', { ns: SPACE_PLUGIN }],
|
|
639
695
|
icon: 'ph--sign-in--regular',
|
|
640
|
-
disposition: 'item',
|
|
641
696
|
testId: 'spacePlugin.joinSpace',
|
|
697
|
+
disposition: 'item',
|
|
642
698
|
},
|
|
643
699
|
},
|
|
644
700
|
],
|
|
@@ -720,16 +776,10 @@ export const SpacePlugin = ({
|
|
|
720
776
|
},
|
|
721
777
|
}),
|
|
722
778
|
|
|
723
|
-
// Create space actions
|
|
779
|
+
// Create space actions.
|
|
724
780
|
createExtension({
|
|
725
781
|
id: `${SPACE_PLUGIN}/actions`,
|
|
726
782
|
filter: (node): node is Node<Space> => isSpace(node.data),
|
|
727
|
-
actionGroups: ({ node }) =>
|
|
728
|
-
constructSpaceActionGroups({
|
|
729
|
-
space: node.data,
|
|
730
|
-
dispatch,
|
|
731
|
-
navigable: state.values.navigableCollections,
|
|
732
|
-
}),
|
|
733
783
|
actions: ({ node }) => {
|
|
734
784
|
const space = node.data;
|
|
735
785
|
return constructSpaceActions({
|
|
@@ -818,7 +868,8 @@ export const SpacePlugin = ({
|
|
|
818
868
|
void space.db
|
|
819
869
|
.query({ id: objectId })
|
|
820
870
|
.first()
|
|
821
|
-
.then((o) => (store.value = o))
|
|
871
|
+
.then((o) => (store.value = o))
|
|
872
|
+
.catch((err) => log.catch(err, { objectId }));
|
|
822
873
|
}
|
|
823
874
|
}, id);
|
|
824
875
|
const object = store.value;
|
|
@@ -838,12 +889,6 @@ export const SpacePlugin = ({
|
|
|
838
889
|
createExtension({
|
|
839
890
|
id: `${SPACE_PLUGIN}/object-actions`,
|
|
840
891
|
filter: (node): node is Node<ReactiveEchoObject<any>> => isEchoObject(node.data),
|
|
841
|
-
actionGroups: ({ node }) =>
|
|
842
|
-
constructObjectActionGroups({
|
|
843
|
-
object: node.data,
|
|
844
|
-
dispatch,
|
|
845
|
-
navigable: state.values.navigableCollections,
|
|
846
|
-
}),
|
|
847
892
|
actions: ({ node }) => constructObjectActions({ node, dispatch }),
|
|
848
893
|
}),
|
|
849
894
|
|
|
@@ -889,18 +934,7 @@ export const SpacePlugin = ({
|
|
|
889
934
|
};
|
|
890
935
|
}
|
|
891
936
|
|
|
892
|
-
const object =
|
|
893
|
-
(onChange) => {
|
|
894
|
-
const timeout = setTimeout(async () => {
|
|
895
|
-
await space?.db.query({ id: objectId }).first();
|
|
896
|
-
onChange();
|
|
897
|
-
});
|
|
898
|
-
|
|
899
|
-
return () => clearTimeout(timeout);
|
|
900
|
-
},
|
|
901
|
-
() => space?.db.getObjectById(objectId),
|
|
902
|
-
subjectId,
|
|
903
|
-
);
|
|
937
|
+
const [object] = memoizeQuery(space, { id: objectId });
|
|
904
938
|
if (!object || !subjectId) {
|
|
905
939
|
return;
|
|
906
940
|
}
|
|
@@ -1002,12 +1036,34 @@ export const SpacePlugin = ({
|
|
|
1002
1036
|
return { data: true };
|
|
1003
1037
|
}
|
|
1004
1038
|
|
|
1039
|
+
case SpaceAction.OPEN_CREATE_SPACE: {
|
|
1040
|
+
return {
|
|
1041
|
+
data: true,
|
|
1042
|
+
intents: [
|
|
1043
|
+
[
|
|
1044
|
+
{
|
|
1045
|
+
action: LayoutAction.SET_LAYOUT,
|
|
1046
|
+
data: {
|
|
1047
|
+
element: 'dialog',
|
|
1048
|
+
component: 'dxos.org/plugin/space/CreateSpaceDialog',
|
|
1049
|
+
dialogBlockAlign: 'start',
|
|
1050
|
+
subject: intent.data,
|
|
1051
|
+
},
|
|
1052
|
+
},
|
|
1053
|
+
],
|
|
1054
|
+
],
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1005
1058
|
case SpaceAction.CREATE: {
|
|
1006
|
-
if (!client) {
|
|
1059
|
+
if (!client || !S.is(SpaceForm)(intent.data)) {
|
|
1007
1060
|
return;
|
|
1008
1061
|
}
|
|
1009
1062
|
|
|
1010
|
-
const space = await client.spaces.create(intent.data
|
|
1063
|
+
const space = await client.spaces.create({ name: intent.data.name });
|
|
1064
|
+
if (intent.data.edgeReplication) {
|
|
1065
|
+
await space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED);
|
|
1066
|
+
}
|
|
1011
1067
|
await space.waitUntilReady();
|
|
1012
1068
|
const collection = create(CollectionType, { objects: [], views: {} });
|
|
1013
1069
|
space.properties[CollectionType.typename] = collection;
|
|
@@ -1023,16 +1079,6 @@ export const SpacePlugin = ({
|
|
|
1023
1079
|
activeParts: { main: [space.id] },
|
|
1024
1080
|
},
|
|
1025
1081
|
intents: [
|
|
1026
|
-
...(settings.values.onSpaceCreate
|
|
1027
|
-
? [
|
|
1028
|
-
[
|
|
1029
|
-
{ action: settings.values.onSpaceCreate, data: { space } },
|
|
1030
|
-
{ action: SpaceAction.ADD_OBJECT, data: { target: space } },
|
|
1031
|
-
{ action: NavigationAction.OPEN },
|
|
1032
|
-
{ action: NavigationAction.EXPOSE },
|
|
1033
|
-
],
|
|
1034
|
-
]
|
|
1035
|
-
: []),
|
|
1036
1082
|
[
|
|
1037
1083
|
{
|
|
1038
1084
|
action: ObservabilityAction.SEND_EVENT,
|
|
@@ -1258,6 +1304,25 @@ export const SpacePlugin = ({
|
|
|
1258
1304
|
break;
|
|
1259
1305
|
}
|
|
1260
1306
|
|
|
1307
|
+
case SpaceAction.OPEN_CREATE_OBJECT: {
|
|
1308
|
+
return {
|
|
1309
|
+
data: true,
|
|
1310
|
+
intents: [
|
|
1311
|
+
[
|
|
1312
|
+
{
|
|
1313
|
+
action: LayoutAction.SET_LAYOUT,
|
|
1314
|
+
data: {
|
|
1315
|
+
element: 'dialog',
|
|
1316
|
+
component: 'dxos.org/plugin/space/CreateObjectDialog',
|
|
1317
|
+
dialogBlockAlign: 'start',
|
|
1318
|
+
subject: intent.data,
|
|
1319
|
+
},
|
|
1320
|
+
},
|
|
1321
|
+
],
|
|
1322
|
+
],
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1261
1326
|
case SpaceAction.ADD_OBJECT: {
|
|
1262
1327
|
const object = intent.data?.object ?? intent.data?.result;
|
|
1263
1328
|
if (!isReactiveObject(object)) {
|
|
@@ -1491,6 +1556,16 @@ export const SpacePlugin = ({
|
|
|
1491
1556
|
settings.values.showHidden = intent.data?.state ?? !settings.values.showHidden;
|
|
1492
1557
|
return { data: true };
|
|
1493
1558
|
}
|
|
1559
|
+
|
|
1560
|
+
case CollectionAction.CREATE: {
|
|
1561
|
+
const collection = create(CollectionType, {
|
|
1562
|
+
name: intent.data?.name,
|
|
1563
|
+
objects: [],
|
|
1564
|
+
views: {},
|
|
1565
|
+
});
|
|
1566
|
+
|
|
1567
|
+
return { data: collection };
|
|
1568
|
+
}
|
|
1494
1569
|
}
|
|
1495
1570
|
},
|
|
1496
1571
|
},
|
|
@@ -7,7 +7,7 @@ import React, { useEffect, useState } from 'react';
|
|
|
7
7
|
|
|
8
8
|
import { parseIntentPlugin, useResolvePlugin, parseNavigationPlugin, NavigationAction } from '@dxos/app-framework';
|
|
9
9
|
import { useClient } from '@dxos/react-client';
|
|
10
|
-
import { fullyQualifiedId, useQuery } from '@dxos/react-client/echo';
|
|
10
|
+
import { Filter, fullyQualifiedId, useQuery } from '@dxos/react-client/echo';
|
|
11
11
|
import { Button, Toast, useTranslation } from '@dxos/react-ui';
|
|
12
12
|
import { getSize, mx } from '@dxos/react-ui-theme';
|
|
13
13
|
|
|
@@ -25,7 +25,7 @@ export const AwaitingObject = ({ id }: { id: string }) => {
|
|
|
25
25
|
const navigationPlugin = useResolvePlugin(parseNavigationPlugin);
|
|
26
26
|
|
|
27
27
|
const client = useClient();
|
|
28
|
-
const objects = useQuery(client.spaces);
|
|
28
|
+
const objects = useQuery(client.spaces, Filter.all());
|
|
29
29
|
|
|
30
30
|
useEffect(() => {
|
|
31
31
|
if (!id) {
|