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