@dxos/plugin-space 0.6.13 → 0.6.14-main.69511f5
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-FOI7DAUV.mjs} +24 -5
- package/dist/lib/browser/chunk-FOI7DAUV.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +757 -298
- 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-OTDRTHT4.cjs} +30 -9
- package/dist/lib/node/chunk-OTDRTHT4.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 +953 -498
- 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-FYDGMPSC.mjs +116 -0
- package/dist/lib/node-esm/chunk-FYDGMPSC.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 +3100 -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/SaveStatus.d.ts +3 -0
- package/dist/types/src/components/SaveStatus.d.ts.map +1 -0
- 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/SyncStatus.d.ts +13 -0
- package/dist/types/src/components/SyncStatus/SyncStatus.d.ts.map +1 -0
- package/dist/types/src/components/SyncStatus/SyncStatus.stories.d.ts +24 -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/types.d.ts +14 -0
- package/dist/types/src/components/SyncStatus/types.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +4 -2
- 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 +8 -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 +21 -1
- 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 +45 -45
- package/src/SpacePlugin.tsx +229 -116
- package/src/components/DefaultObjectSettings.tsx +33 -0
- package/src/components/MenuFooter.tsx +2 -2
- package/src/components/SaveStatus.tsx +95 -0
- 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 +59 -0
- package/src/components/SyncStatus/SyncStatus.stories.tsx +65 -0
- package/src/components/SyncStatus/SyncStatus.tsx +188 -0
- package/src/components/SyncStatus/index.ts +5 -0
- package/src/components/SyncStatus/types.ts +77 -0
- package/src/components/index.ts +4 -2
- package/src/meta.ts +3 -1
- package/src/translations.ts +10 -2
- package/src/types/collection.ts +1 -1
- package/src/types/thread.ts +12 -2
- package/src/types/types.ts +28 -2
- 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/src/components/EmptySpace.tsx +0 -25
- package/src/components/EmptyTree.tsx +0 -25
package/src/SpacePlugin.tsx
CHANGED
|
@@ -2,74 +2,78 @@
|
|
|
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 {
|
|
10
9
|
type IntentDispatcher,
|
|
11
10
|
type IntentPluginProvides,
|
|
12
11
|
LayoutAction,
|
|
13
|
-
Surface,
|
|
14
12
|
type LocationProvides,
|
|
15
13
|
NavigationAction,
|
|
16
14
|
type Plugin,
|
|
17
15
|
type PluginDefinition,
|
|
18
|
-
|
|
16
|
+
Surface,
|
|
19
17
|
firstIdInPart,
|
|
18
|
+
openIds,
|
|
19
|
+
parseGraphPlugin,
|
|
20
20
|
parseIntentPlugin,
|
|
21
|
-
parseNavigationPlugin,
|
|
22
21
|
parseMetadataResolverPlugin,
|
|
22
|
+
parseNavigationPlugin,
|
|
23
23
|
resolvePlugin,
|
|
24
|
-
parseGraphPlugin,
|
|
25
24
|
} from '@dxos/app-framework';
|
|
26
25
|
import { EventSubscriptions, type Trigger, type UnsubscribeCallback } from '@dxos/async';
|
|
27
|
-
import { type
|
|
26
|
+
import { type HasId, isReactiveObject } from '@dxos/echo-schema';
|
|
27
|
+
import { scheduledEffect } from '@dxos/echo-signals/core';
|
|
28
28
|
import { LocalStorageStore } from '@dxos/local-storage';
|
|
29
29
|
import { log } from '@dxos/log';
|
|
30
30
|
import { Migrations } from '@dxos/migrations';
|
|
31
31
|
import { type AttentionPluginProvides, parseAttentionPlugin } from '@dxos/plugin-attention';
|
|
32
32
|
import { type ClientPluginProvides, parseClientPlugin } from '@dxos/plugin-client';
|
|
33
|
-
import {
|
|
33
|
+
import { type Node, createExtension, memoize, toSignal } from '@dxos/plugin-graph';
|
|
34
34
|
import { ObservabilityAction } from '@dxos/plugin-observability/meta';
|
|
35
35
|
import { type Client, PublicKey } from '@dxos/react-client';
|
|
36
36
|
import {
|
|
37
|
+
type EchoReactiveObject,
|
|
38
|
+
Expando,
|
|
39
|
+
Filter,
|
|
37
40
|
type PropertiesTypeProps,
|
|
38
41
|
type Space,
|
|
42
|
+
SpaceState,
|
|
39
43
|
create,
|
|
40
|
-
Expando,
|
|
41
|
-
Filter,
|
|
42
44
|
fullyQualifiedId,
|
|
43
45
|
getSpace,
|
|
44
46
|
getTypename,
|
|
45
47
|
isEchoObject,
|
|
46
48
|
isSpace,
|
|
47
49
|
loadObjectReferences,
|
|
48
|
-
|
|
50
|
+
parseId,
|
|
49
51
|
} from '@dxos/react-client/echo';
|
|
50
52
|
import { Dialog } from '@dxos/react-ui';
|
|
51
|
-
import { InvitationManager, type InvitationManagerProps, osTranslations
|
|
53
|
+
import { ClipboardProvider, InvitationManager, type InvitationManagerProps, osTranslations } from '@dxos/shell/react';
|
|
52
54
|
import { ComplexMap, nonNullable, reduceGroupBy } from '@dxos/util';
|
|
53
55
|
|
|
54
56
|
import {
|
|
55
57
|
AwaitingObject,
|
|
56
58
|
CollectionMain,
|
|
57
59
|
CollectionSection,
|
|
58
|
-
|
|
59
|
-
EmptyTree,
|
|
60
|
+
DefaultObjectSettings,
|
|
60
61
|
MenuFooter,
|
|
61
62
|
MissingObject,
|
|
62
63
|
PopoverRenameObject,
|
|
63
64
|
PopoverRenameSpace,
|
|
65
|
+
SaveStatus,
|
|
64
66
|
ShareSpaceButton,
|
|
65
67
|
SmallPresence,
|
|
66
68
|
SmallPresenceLive,
|
|
67
69
|
SpacePresence,
|
|
68
70
|
SpaceSettings,
|
|
71
|
+
SpaceSettingsPanel,
|
|
72
|
+
SyncStatus,
|
|
69
73
|
} from './components';
|
|
70
74
|
import meta, { SPACE_PLUGIN, SpaceAction } from './meta';
|
|
71
75
|
import translations from './translations';
|
|
72
|
-
import { CollectionType, type
|
|
76
|
+
import { CollectionType, type PluginState, type SpacePluginProvides, type SpaceSettingsProps } from './types';
|
|
73
77
|
import {
|
|
74
78
|
COMPOSER_SPACE_LOCK,
|
|
75
79
|
SHARED,
|
|
@@ -118,11 +122,14 @@ export const SpacePlugin = ({
|
|
|
118
122
|
firstRun,
|
|
119
123
|
onFirstRun,
|
|
120
124
|
}: SpacePluginOptions = {}): PluginDefinition<SpacePluginProvides> => {
|
|
121
|
-
const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN
|
|
125
|
+
const settings = new LocalStorageStore<SpaceSettingsProps>(SPACE_PLUGIN, {
|
|
126
|
+
onSpaceCreate: 'dxos.org/plugin/markdown/action/create',
|
|
127
|
+
});
|
|
122
128
|
const state = new LocalStorageStore<PluginState>(SPACE_PLUGIN, {
|
|
123
129
|
awaiting: undefined,
|
|
124
130
|
spaceNames: {},
|
|
125
131
|
viewersByObject: {},
|
|
132
|
+
// TODO(wittjosiah): Stop using (Complex)Map inside reactive object.
|
|
126
133
|
viewersByIdentity: new ComplexMap(PublicKey.hash),
|
|
127
134
|
sdkMigrationRunning: {},
|
|
128
135
|
});
|
|
@@ -171,9 +178,10 @@ export const SpacePlugin = ({
|
|
|
171
178
|
.filter((space) => space.state.get() === SpaceState.SPACE_READY)
|
|
172
179
|
.forEach((space) => {
|
|
173
180
|
subscriptions.add(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
scheduledEffect(
|
|
182
|
+
() => ({ name: space.properties.name }),
|
|
183
|
+
({ name }) => (state.values.spaceNames[space.id] = name),
|
|
184
|
+
),
|
|
177
185
|
);
|
|
178
186
|
});
|
|
179
187
|
}).unsubscribe,
|
|
@@ -181,54 +189,56 @@ export const SpacePlugin = ({
|
|
|
181
189
|
|
|
182
190
|
// Broadcast active node to other peers in the space.
|
|
183
191
|
subscriptions.add(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
192
|
+
scheduledEffect(
|
|
193
|
+
() => ({
|
|
194
|
+
ids: openIds(location.active),
|
|
195
|
+
removed: location.closed ? [location.closed].flat() : [],
|
|
196
|
+
}),
|
|
197
|
+
({ ids, removed }) => {
|
|
198
|
+
const send = () => {
|
|
199
|
+
const spaces = client.spaces.get();
|
|
200
|
+
const identity = client.halo.identity.get();
|
|
201
|
+
if (identity && location.active) {
|
|
202
|
+
// Group parts by space for efficient messaging.
|
|
203
|
+
const idsBySpace = reduceGroupBy(ids, (id) => {
|
|
204
|
+
const [spaceId] = id.split(':'); // TODO(burdon): Factor out.
|
|
205
|
+
return spaceId;
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// NOTE: Ensure all spaces are included so that we send the correct `removed` object arrays.
|
|
209
|
+
for (const space of spaces) {
|
|
210
|
+
if (!idsBySpace.has(space.id)) {
|
|
211
|
+
idsBySpace.set(space.id, []);
|
|
212
|
+
}
|
|
201
213
|
}
|
|
202
|
-
}
|
|
203
214
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
215
|
+
for (const [spaceId, ids] of idsBySpace) {
|
|
216
|
+
const space = spaces.find((space) => space.id === spaceId);
|
|
217
|
+
if (!space) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
209
220
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
});
|
|
221
|
+
void space
|
|
222
|
+
.postMessage('viewing', {
|
|
223
|
+
identityKey: identity.identityKey.toHex(),
|
|
224
|
+
attended: attention.attended ? [...attention.attended] : [],
|
|
225
|
+
added: ids,
|
|
226
|
+
// TODO(Zan): When we re-open a part, we should remove it from the removed list in the navigation plugin.
|
|
227
|
+
removed: removed.filter((id) => !ids.includes(id)),
|
|
228
|
+
})
|
|
229
|
+
// TODO(burdon): This seems defensive; why would this fail? Backoff interval.
|
|
230
|
+
.catch((err) => {
|
|
231
|
+
log.warn('Failed to broadcast active node for presence.', { err: err.message });
|
|
232
|
+
});
|
|
233
|
+
}
|
|
224
234
|
}
|
|
225
|
-
}
|
|
226
|
-
};
|
|
235
|
+
};
|
|
227
236
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
send();
|
|
238
|
+
const interval = setInterval(() => send(), ACTIVE_NODE_BROADCAST_INTERVAL);
|
|
239
|
+
return () => clearInterval(interval);
|
|
240
|
+
},
|
|
241
|
+
),
|
|
232
242
|
);
|
|
233
243
|
|
|
234
244
|
// Listen for active nodes from other peers in the space.
|
|
@@ -276,17 +286,8 @@ export const SpacePlugin = ({
|
|
|
276
286
|
return {
|
|
277
287
|
meta,
|
|
278
288
|
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
|
-
});
|
|
289
|
+
settings.prop({ key: 'showHidden', type: LocalStorageStore.bool({ allowUndefined: true }) });
|
|
290
|
+
state.prop({ key: 'spaceNames', type: LocalStorageStore.json<Record<string, string>>() });
|
|
290
291
|
|
|
291
292
|
navigationPlugin = resolvePlugin(plugins, parseNavigationPlugin);
|
|
292
293
|
attentionPlugin = resolvePlugin(plugins, parseAttentionPlugin);
|
|
@@ -340,8 +341,7 @@ export const SpacePlugin = ({
|
|
|
340
341
|
records: {
|
|
341
342
|
[CollectionType.typename]: {
|
|
342
343
|
placeholder: ['unnamed collection label', { ns: SPACE_PLUGIN }],
|
|
343
|
-
icon:
|
|
344
|
-
iconSymbol: 'ph--cards-three--regular',
|
|
344
|
+
icon: 'ph--cards-three--regular',
|
|
345
345
|
// TODO(wittjosiah): Move out of metadata.
|
|
346
346
|
loadReferences: (collection: CollectionType) =>
|
|
347
347
|
loadObjectReferences(collection, (collection) => [
|
|
@@ -362,22 +362,25 @@ export const SpacePlugin = ({
|
|
|
362
362
|
case 'main':
|
|
363
363
|
// TODO(wittjosiah): Need to avoid shotgun parsing space state everywhere.
|
|
364
364
|
return isSpace(primary) && primary.state.get() === SpaceState.SPACE_READY ? (
|
|
365
|
-
<Surface
|
|
365
|
+
<Surface
|
|
366
|
+
data={{ active: primary.properties[CollectionType.typename], id: primary.id }}
|
|
367
|
+
role={role}
|
|
368
|
+
{...rest}
|
|
369
|
+
/>
|
|
366
370
|
) : primary instanceof CollectionType ? (
|
|
367
|
-
{
|
|
371
|
+
{
|
|
372
|
+
node: <CollectionMain collection={primary} />,
|
|
373
|
+
disposition: 'fallback',
|
|
374
|
+
}
|
|
368
375
|
) : typeof primary === 'string' && primary.length === OBJECT_ID_LENGTH ? (
|
|
369
376
|
<MissingObject id={primary} />
|
|
370
377
|
) : null;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
return <EmptySpace />;
|
|
378
|
-
default:
|
|
379
|
-
return null;
|
|
380
|
-
}
|
|
378
|
+
case 'complementary--settings':
|
|
379
|
+
return isSpace(data.subject) ? (
|
|
380
|
+
<SpaceSettingsPanel space={data.subject} />
|
|
381
|
+
) : isEchoObject(data.subject) ? (
|
|
382
|
+
{ node: <DefaultObjectSettings object={data.subject} />, disposition: 'fallback' }
|
|
383
|
+
) : null;
|
|
381
384
|
case 'dialog':
|
|
382
385
|
if (data.component === 'dxos.org/plugin/space/InvitationManagerDialog') {
|
|
383
386
|
return (
|
|
@@ -387,10 +390,9 @@ export const SpacePlugin = ({
|
|
|
387
390
|
</ClipboardProvider>
|
|
388
391
|
</Dialog.Content>
|
|
389
392
|
);
|
|
390
|
-
} else {
|
|
391
|
-
return null;
|
|
392
393
|
}
|
|
393
|
-
|
|
394
|
+
return null;
|
|
395
|
+
case 'popover': {
|
|
394
396
|
if (data.component === 'dxos.org/plugin/space/RenameSpacePopover' && isSpace(data.subject)) {
|
|
395
397
|
return <PopoverRenameSpace space={data.subject} />;
|
|
396
398
|
}
|
|
@@ -398,11 +400,16 @@ export const SpacePlugin = ({
|
|
|
398
400
|
return <PopoverRenameObject object={data.subject} />;
|
|
399
401
|
}
|
|
400
402
|
return null;
|
|
403
|
+
}
|
|
404
|
+
// TODO(burdon): Add role name syntax to minimal plugin docs.
|
|
401
405
|
case 'presence--glyph': {
|
|
402
406
|
return isReactiveObject(data.object) ? (
|
|
403
|
-
<SmallPresenceLive
|
|
407
|
+
<SmallPresenceLive
|
|
408
|
+
id={data.id as string}
|
|
409
|
+
viewers={state.values.viewersByObject[fullyQualifiedId(data.object)]}
|
|
410
|
+
/>
|
|
404
411
|
) : (
|
|
405
|
-
<SmallPresence count={0} />
|
|
412
|
+
<SmallPresence id={data.id as string} count={0} />
|
|
406
413
|
);
|
|
407
414
|
}
|
|
408
415
|
case 'navbar-start': {
|
|
@@ -419,6 +426,7 @@ export const SpacePlugin = ({
|
|
|
419
426
|
? (space?.properties[CollectionType.typename] as CollectionType)
|
|
420
427
|
: undefined
|
|
421
428
|
: data.object;
|
|
429
|
+
|
|
422
430
|
return space && object
|
|
423
431
|
? {
|
|
424
432
|
node: (
|
|
@@ -436,11 +444,19 @@ export const SpacePlugin = ({
|
|
|
436
444
|
case 'settings':
|
|
437
445
|
return data.plugin === meta.id ? <SpaceSettings settings={settings.values} /> : null;
|
|
438
446
|
case 'menu-footer':
|
|
439
|
-
if (
|
|
440
|
-
return null;
|
|
441
|
-
} else {
|
|
447
|
+
if (isEchoObject(data.object)) {
|
|
442
448
|
return <MenuFooter object={data.object} />;
|
|
449
|
+
} else {
|
|
450
|
+
return null;
|
|
443
451
|
}
|
|
452
|
+
case 'status': {
|
|
453
|
+
return (
|
|
454
|
+
<>
|
|
455
|
+
<SyncStatus />
|
|
456
|
+
<SaveStatus />
|
|
457
|
+
</>
|
|
458
|
+
);
|
|
459
|
+
}
|
|
444
460
|
default:
|
|
445
461
|
return null;
|
|
446
462
|
}
|
|
@@ -456,8 +472,7 @@ export const SpacePlugin = ({
|
|
|
456
472
|
const dispatch = intentPlugin?.provides.intent.dispatch;
|
|
457
473
|
const resolve = metadataPlugin?.provides.metadata.resolver;
|
|
458
474
|
const graph = graphPlugin?.provides.graph;
|
|
459
|
-
|
|
460
|
-
if (!graph || !dispatch || !resolve || !client) {
|
|
475
|
+
if (!client || !dispatch || !resolve || !graph) {
|
|
461
476
|
return [];
|
|
462
477
|
}
|
|
463
478
|
|
|
@@ -491,7 +506,6 @@ export const SpacePlugin = ({
|
|
|
491
506
|
type: SPACES,
|
|
492
507
|
properties: {
|
|
493
508
|
label: ['spaces label', { ns: SPACE_PLUGIN }],
|
|
494
|
-
palette: 'teal',
|
|
495
509
|
testId: 'spacePlugin.spaces',
|
|
496
510
|
role: 'branch',
|
|
497
511
|
childrenPersistenceClass: 'echo',
|
|
@@ -540,10 +554,10 @@ export const SpacePlugin = ({
|
|
|
540
554
|
},
|
|
541
555
|
properties: {
|
|
542
556
|
label: ['create space label', { ns: SPACE_PLUGIN }],
|
|
543
|
-
icon:
|
|
544
|
-
|
|
545
|
-
disposition: 'toolbar',
|
|
557
|
+
icon: 'ph--plus--regular',
|
|
558
|
+
disposition: 'item',
|
|
546
559
|
testId: 'spacePlugin.createSpace',
|
|
560
|
+
className: 'pbs-4',
|
|
547
561
|
},
|
|
548
562
|
},
|
|
549
563
|
{
|
|
@@ -561,9 +575,10 @@ export const SpacePlugin = ({
|
|
|
561
575
|
},
|
|
562
576
|
properties: {
|
|
563
577
|
label: ['join space label', { ns: SPACE_PLUGIN }],
|
|
564
|
-
icon:
|
|
565
|
-
|
|
578
|
+
icon: 'ph--sign-in--regular',
|
|
579
|
+
disposition: 'item',
|
|
566
580
|
testId: 'spacePlugin.joinSpace',
|
|
581
|
+
className: 'pbe-4',
|
|
567
582
|
},
|
|
568
583
|
},
|
|
569
584
|
],
|
|
@@ -707,6 +722,76 @@ export const SpacePlugin = ({
|
|
|
707
722
|
.filter(nonNullable);
|
|
708
723
|
},
|
|
709
724
|
}),
|
|
725
|
+
|
|
726
|
+
// Create nodes for object settings.
|
|
727
|
+
createExtension({
|
|
728
|
+
id: `${SPACE_PLUGIN}/settings-for-subject`,
|
|
729
|
+
resolver: ({ id }) => {
|
|
730
|
+
// TODO(Zan): Find util (or make one).
|
|
731
|
+
if (!id.endsWith('~settings')) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const type = 'orphan-settings-for-subject';
|
|
736
|
+
const icon = 'ph--gear--regular';
|
|
737
|
+
|
|
738
|
+
const [subjectId] = id.split('~');
|
|
739
|
+
const { spaceId, objectId } = parseId(subjectId);
|
|
740
|
+
const space = client.spaces.get().find((space) => space.id === spaceId);
|
|
741
|
+
if (!objectId) {
|
|
742
|
+
const label = space
|
|
743
|
+
? space.properties.name || ['unnamed space label', { ns: SPACE_PLUGIN }]
|
|
744
|
+
: ['unnamed object settings label', { ns: SPACE_PLUGIN }];
|
|
745
|
+
|
|
746
|
+
// TODO(wittjosiah): Support comments for arbitrary subjects.
|
|
747
|
+
// This is to ensure that the comments panel is not stuck on an old object.
|
|
748
|
+
return {
|
|
749
|
+
id,
|
|
750
|
+
type,
|
|
751
|
+
data: null,
|
|
752
|
+
properties: {
|
|
753
|
+
icon,
|
|
754
|
+
label,
|
|
755
|
+
showResolvedThreads: false,
|
|
756
|
+
object: null,
|
|
757
|
+
space,
|
|
758
|
+
},
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const object = toSignal(
|
|
763
|
+
(onChange) => {
|
|
764
|
+
const timeout = setTimeout(async () => {
|
|
765
|
+
await space?.db.loadObjectById(objectId);
|
|
766
|
+
onChange();
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
return () => clearTimeout(timeout);
|
|
770
|
+
},
|
|
771
|
+
() => space?.db.getObjectById(objectId),
|
|
772
|
+
subjectId,
|
|
773
|
+
);
|
|
774
|
+
if (!object || !subjectId) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const meta = resolve(getTypename(object) ?? '');
|
|
779
|
+
const label = meta.label?.(object) ||
|
|
780
|
+
object.name ||
|
|
781
|
+
meta.placeholder || ['unnamed object settings label', { ns: SPACE_PLUGIN }];
|
|
782
|
+
|
|
783
|
+
return {
|
|
784
|
+
id,
|
|
785
|
+
type,
|
|
786
|
+
data: null,
|
|
787
|
+
properties: {
|
|
788
|
+
icon,
|
|
789
|
+
label,
|
|
790
|
+
object,
|
|
791
|
+
},
|
|
792
|
+
};
|
|
793
|
+
},
|
|
794
|
+
}),
|
|
710
795
|
];
|
|
711
796
|
},
|
|
712
797
|
serializer: (plugins) => {
|
|
@@ -802,9 +887,21 @@ export const SpacePlugin = ({
|
|
|
802
887
|
}
|
|
803
888
|
|
|
804
889
|
return {
|
|
805
|
-
data: {
|
|
806
|
-
|
|
890
|
+
data: {
|
|
891
|
+
space,
|
|
892
|
+
id: space.id,
|
|
893
|
+
activeParts: { main: [space.id] },
|
|
894
|
+
},
|
|
807
895
|
intents: [
|
|
896
|
+
...(settings.values.onSpaceCreate
|
|
897
|
+
? [
|
|
898
|
+
[
|
|
899
|
+
{ action: settings.values.onSpaceCreate, data: { space } },
|
|
900
|
+
{ action: SpaceAction.ADD_OBJECT, data: { target: space } },
|
|
901
|
+
{ action: NavigationAction.EXPOSE },
|
|
902
|
+
],
|
|
903
|
+
]
|
|
904
|
+
: []),
|
|
808
905
|
[
|
|
809
906
|
{
|
|
810
907
|
action: ObservabilityAction.SEND_EVENT,
|
|
@@ -825,9 +922,26 @@ export const SpacePlugin = ({
|
|
|
825
922
|
const { space } = await client.shell.joinSpace({ invitationCode: intent.data?.invitationCode });
|
|
826
923
|
if (space) {
|
|
827
924
|
return {
|
|
828
|
-
data: {
|
|
829
|
-
|
|
925
|
+
data: {
|
|
926
|
+
space,
|
|
927
|
+
id: space.id,
|
|
928
|
+
activeParts: { main: [space.id] },
|
|
929
|
+
},
|
|
830
930
|
intents: [
|
|
931
|
+
[
|
|
932
|
+
{
|
|
933
|
+
action: LayoutAction.SET_LAYOUT,
|
|
934
|
+
data: {
|
|
935
|
+
element: 'toast',
|
|
936
|
+
subject: {
|
|
937
|
+
id: `${SPACE_PLUGIN}/join-success`,
|
|
938
|
+
duration: 10_000,
|
|
939
|
+
title: translations[0]['en-US'][SPACE_PLUGIN]['join success label'],
|
|
940
|
+
closeLabel: translations[0]['en-US'][SPACE_PLUGIN]['dismiss label'],
|
|
941
|
+
},
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
],
|
|
831
945
|
[
|
|
832
946
|
{
|
|
833
947
|
action: ObservabilityAction.SEND_EVENT,
|
|
@@ -1020,8 +1134,7 @@ export const SpacePlugin = ({
|
|
|
1020
1134
|
title: translations[0]['en-US'][SPACE_PLUGIN]['space limit label'],
|
|
1021
1135
|
description: translations[0]['en-US'][SPACE_PLUGIN]['space limit description'],
|
|
1022
1136
|
duration: 5_000,
|
|
1023
|
-
icon:
|
|
1024
|
-
iconSymbol: 'ph--warning--regular',
|
|
1137
|
+
icon: 'ph--warning--regular',
|
|
1025
1138
|
actionLabel: translations[0]['en-US'][SPACE_PLUGIN]['remove deleted objects label'],
|
|
1026
1139
|
actionAlt: translations[0]['en-US'][SPACE_PLUGIN]['remove deleted objects alt'],
|
|
1027
1140
|
// TODO(wittjosiah): Use OS namespace.
|
|
@@ -1047,20 +1160,20 @@ export const SpacePlugin = ({
|
|
|
1047
1160
|
}
|
|
1048
1161
|
|
|
1049
1162
|
if (intent.data?.target instanceof CollectionType) {
|
|
1050
|
-
intent.data?.target.objects.push(object as
|
|
1163
|
+
intent.data?.target.objects.push(object as HasId);
|
|
1051
1164
|
} else if (isSpace(intent.data?.target)) {
|
|
1052
1165
|
const collection = space.properties[CollectionType.typename];
|
|
1053
1166
|
if (collection instanceof CollectionType) {
|
|
1054
|
-
collection.objects.push(object as
|
|
1167
|
+
collection.objects.push(object as HasId);
|
|
1055
1168
|
} else {
|
|
1056
1169
|
// TODO(wittjosiah): Can't add non-echo objects by including in a collection because of types.
|
|
1057
|
-
const collection = create(CollectionType, { objects: [object as
|
|
1170
|
+
const collection = create(CollectionType, { objects: [object as HasId], views: {} });
|
|
1058
1171
|
space.properties[CollectionType.typename] = collection;
|
|
1059
1172
|
}
|
|
1060
1173
|
}
|
|
1061
1174
|
|
|
1062
1175
|
return {
|
|
1063
|
-
data: { id: object
|
|
1176
|
+
data: { id: fullyQualifiedId(object), object, activeParts: { main: [fullyQualifiedId(object)] } },
|
|
1064
1177
|
intents: [
|
|
1065
1178
|
[
|
|
1066
1179
|
{
|
|
@@ -1115,7 +1228,6 @@ export const SpacePlugin = ({
|
|
|
1115
1228
|
activeParts: {
|
|
1116
1229
|
main: deletionData.wasActive,
|
|
1117
1230
|
sidebar: deletionData.wasActive,
|
|
1118
|
-
complementary: deletionData.wasActive,
|
|
1119
1231
|
},
|
|
1120
1232
|
},
|
|
1121
1233
|
});
|
|
@@ -1203,11 +1315,12 @@ export const SpacePlugin = ({
|
|
|
1203
1315
|
case SpaceAction.DUPLICATE_OBJECT: {
|
|
1204
1316
|
const originalObject = intent.data?.object ?? intent.data?.result;
|
|
1205
1317
|
const resolve = resolvePlugin(plugins, parseMetadataResolverPlugin)?.provides.metadata.resolver;
|
|
1206
|
-
|
|
1318
|
+
const space = isSpace(intent.data?.target) ? intent.data?.target : getSpace(intent.data?.target);
|
|
1319
|
+
if (!isEchoObject(originalObject) || !resolve || !space) {
|
|
1207
1320
|
return;
|
|
1208
1321
|
}
|
|
1209
1322
|
|
|
1210
|
-
const newObject = await cloneObject(originalObject, resolve);
|
|
1323
|
+
const newObject = await cloneObject(originalObject, resolve, space);
|
|
1211
1324
|
return {
|
|
1212
1325
|
intents: [
|
|
1213
1326
|
[{ action: SpaceAction.ADD_OBJECT, data: { object: newObject, target: intent.data?.target } }],
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { type EchoReactiveObject } from '@dxos/react-client/echo';
|
|
8
|
+
import { Input, useTranslation } from '@dxos/react-ui';
|
|
9
|
+
|
|
10
|
+
import { SPACE_PLUGIN } from '../meta';
|
|
11
|
+
|
|
12
|
+
export type DefaultObjectSettingsProps = {
|
|
13
|
+
object: EchoReactiveObject<any>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const DefaultObjectSettings = ({ object }: DefaultObjectSettingsProps) => {
|
|
17
|
+
const { t } = useTranslation(SPACE_PLUGIN);
|
|
18
|
+
// TODO(burdon): Standardize forms.
|
|
19
|
+
return (
|
|
20
|
+
<div role='form' className='flex flex-col w-full p-2 gap-1'>
|
|
21
|
+
<Input.Root>
|
|
22
|
+
<Input.Label>{t('name label')}</Input.Label>
|
|
23
|
+
<Input.TextInput
|
|
24
|
+
placeholder={t('name placeholder')}
|
|
25
|
+
value={object.name ?? ''}
|
|
26
|
+
onChange={(event) => {
|
|
27
|
+
object.name = event.target.value;
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
</Input.Root>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
//
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
|
+
|
|
4
5
|
import { Planet } from '@phosphor-icons/react';
|
|
5
6
|
import React from 'react';
|
|
6
7
|
|
|
7
|
-
import { getSpace } from '@dxos/client/echo';
|
|
8
|
-
import type { EchoReactiveObject } from '@dxos/echo-schema';
|
|
8
|
+
import { type EchoReactiveObject, getSpace } from '@dxos/client/echo';
|
|
9
9
|
import { useClient } from '@dxos/react-client';
|
|
10
10
|
import { DropdownMenu, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
11
11
|
|