@dxos/plugin-client 0.7.4-staging.f7e8224 → 0.7.5-main.499c70c
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-52IJQ35F.mjs +78 -0
- package/dist/lib/browser/chunk-52IJQ35F.mjs.map +7 -0
- package/dist/lib/browser/chunk-X4QUPYC6.mjs +12 -0
- package/dist/lib/browser/chunk-X4QUPYC6.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +184 -233
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -5
- package/dist/lib/browser/types.mjs +10 -0
- package/dist/lib/browser/types.mjs.map +7 -0
- package/dist/lib/node/chunk-NFO3ADQC.cjs +98 -0
- package/dist/lib/node/chunk-NFO3ADQC.cjs.map +7 -0
- package/dist/lib/node/chunk-RUA5KXVW.cjs +35 -0
- package/dist/lib/node/chunk-RUA5KXVW.cjs.map +7 -0
- package/dist/lib/node/index.cjs +186 -236
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.cjs +4 -8
- package/dist/lib/node/meta.cjs.map +2 -2
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types.cjs +32 -0
- package/dist/lib/node/types.cjs.map +7 -0
- package/dist/lib/node-esm/chunk-GMGRQ5Q7.mjs +14 -0
- package/dist/lib/node-esm/chunk-GMGRQ5Q7.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-TI4GNGMM.mjs +79 -0
- package/dist/lib/node-esm/chunk-TI4GNGMM.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +184 -233
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/meta.mjs +1 -5
- package/dist/lib/node-esm/types.mjs +11 -0
- package/dist/lib/node-esm/types.mjs.map +7 -0
- package/dist/types/src/ClientPlugin.d.ts +2 -35
- package/dist/types/src/ClientPlugin.d.ts.map +1 -1
- package/dist/types/src/components/IdentityDialog.d.ts +1 -0
- package/dist/types/src/components/IdentityDialog.d.ts.map +1 -1
- package/dist/types/src/components/JoinDialog.d.ts +1 -0
- package/dist/types/src/components/JoinDialog.d.ts.map +1 -1
- package/dist/types/src/components/RecoveryCodeDialog.d.ts +1 -0
- package/dist/types/src/components/RecoveryCodeDialog.d.ts.map +1 -1
- package/dist/types/src/components/RecoveryCodeDialog.stories.d.ts +8 -0
- package/dist/types/src/components/RecoveryCodeDialog.stories.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +0 -10
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +110 -0
- package/dist/types/src/types.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +22 -13
- package/src/ClientPlugin.tsx +111 -200
- package/src/components/IdentityDialog.tsx +13 -11
- package/src/components/JoinDialog.tsx +13 -19
- package/src/components/RecoveryCodeDialog.stories.tsx +50 -0
- package/src/components/RecoveryCodeDialog.tsx +19 -7
- package/src/meta.ts +0 -14
- package/src/translations.ts +5 -4
- package/src/types.ts +115 -0
- package/dist/lib/browser/chunk-FGUXUNOK.mjs +0 -26
- package/dist/lib/browser/chunk-FGUXUNOK.mjs.map +0 -7
- package/dist/lib/node/chunk-XYLDQWFV.cjs +0 -51
- package/dist/lib/node/chunk-XYLDQWFV.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-C6X363FK.mjs +0 -28
- package/dist/lib/node-esm/chunk-C6X363FK.mjs.map +0 -7
package/src/ClientPlugin.tsx
CHANGED
|
@@ -8,66 +8,31 @@ import {
|
|
|
8
8
|
LayoutAction,
|
|
9
9
|
parseIntentPlugin,
|
|
10
10
|
resolvePlugin,
|
|
11
|
-
type SurfaceProvides,
|
|
12
|
-
type GraphBuilderProvides,
|
|
13
|
-
type IntentResolverProvides,
|
|
14
|
-
type Plugin,
|
|
15
11
|
type PluginDefinition,
|
|
16
|
-
|
|
12
|
+
createSurface,
|
|
13
|
+
createIntent,
|
|
14
|
+
createResolver,
|
|
17
15
|
} from '@dxos/app-framework';
|
|
18
16
|
import { Config, Defaults, Envs, Local, Storage } from '@dxos/config';
|
|
19
17
|
import { registerSignalsRuntime } from '@dxos/echo-signals/react';
|
|
20
18
|
import { invariant } from '@dxos/invariant';
|
|
21
19
|
import { createExtension, type Node } from '@dxos/plugin-graph';
|
|
22
|
-
import {
|
|
20
|
+
import { ObservabilityAction } from '@dxos/plugin-observability/types';
|
|
21
|
+
import { Client, ClientProvider } from '@dxos/react-client';
|
|
23
22
|
import { type IdentityPanelProps, type JoinPanelProps } from '@dxos/shell/react';
|
|
24
23
|
|
|
25
|
-
import {
|
|
26
|
-
|
|
24
|
+
import {
|
|
25
|
+
IDENTITY_DIALOG,
|
|
26
|
+
IdentityDialog,
|
|
27
|
+
JOIN_DIALOG,
|
|
28
|
+
JoinDialog,
|
|
29
|
+
RECOVER_CODE_DIALOG,
|
|
30
|
+
RecoveryCodeDialog,
|
|
31
|
+
type RecoveryCodeDialogProps,
|
|
32
|
+
} from './components';
|
|
33
|
+
import meta, { CLIENT_PLUGIN } from './meta';
|
|
27
34
|
import translations from './translations';
|
|
28
|
-
|
|
29
|
-
export type ClientPluginOptions = ClientOptions & {
|
|
30
|
-
/**
|
|
31
|
-
* Used to track app-specific state in spaces.
|
|
32
|
-
*/
|
|
33
|
-
appKey: string;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Base URL for the invitation link.
|
|
37
|
-
*/
|
|
38
|
-
invitationUrl?: string;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Query parameter for the invitation code.
|
|
42
|
-
*/
|
|
43
|
-
invitationParam?: string;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Run after the client has been initialized.
|
|
47
|
-
*/
|
|
48
|
-
onClientInitialized?: (client: Client) => Promise<void>;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Run after the identity has been successfully initialized.
|
|
52
|
-
* Run with client during plugin ready phase.
|
|
53
|
-
*/
|
|
54
|
-
onReady?: (client: Client, plugins: Plugin[]) => Promise<void>;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Called when the client is reset.
|
|
58
|
-
*/
|
|
59
|
-
onReset?: (params: { target?: string }) => Promise<void>;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export type ClientPluginProvides = IntentResolverProvides &
|
|
63
|
-
GraphBuilderProvides &
|
|
64
|
-
SurfaceProvides &
|
|
65
|
-
TranslationsProvides & {
|
|
66
|
-
client: Client;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export const parseClientPlugin = (plugin?: Plugin) =>
|
|
70
|
-
(plugin?.provides as any).client instanceof Client ? (plugin as Plugin<ClientPluginProvides>) : undefined;
|
|
35
|
+
import { ClientAction, type ClientPluginOptions, type ClientPluginProvides } from './types';
|
|
71
36
|
|
|
72
37
|
export const ClientPlugin = ({
|
|
73
38
|
appKey,
|
|
@@ -119,7 +84,7 @@ export const ClientPlugin = ({
|
|
|
119
84
|
context: ({ children }) => <ClientProvider client={client}>{children}</ClientProvider>,
|
|
120
85
|
};
|
|
121
86
|
},
|
|
122
|
-
ready: async (plugins) => {
|
|
87
|
+
ready: async ({ plugins }) => {
|
|
123
88
|
if (error) {
|
|
124
89
|
throw error;
|
|
125
90
|
}
|
|
@@ -132,30 +97,32 @@ export const ClientPlugin = ({
|
|
|
132
97
|
provides: {
|
|
133
98
|
translations,
|
|
134
99
|
surface: {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
100
|
+
definitions: () => [
|
|
101
|
+
createSurface({
|
|
102
|
+
id: IDENTITY_DIALOG,
|
|
103
|
+
role: 'dialog',
|
|
104
|
+
filter: (data): data is { subject: IdentityPanelProps } => data.component === IDENTITY_DIALOG,
|
|
105
|
+
component: ({ data }) => (
|
|
106
|
+
<IdentityDialog {...data.subject} createInvitationUrl={createDeviceInvitationUrl} />
|
|
107
|
+
),
|
|
108
|
+
}),
|
|
109
|
+
createSurface({
|
|
110
|
+
id: JOIN_DIALOG,
|
|
111
|
+
role: 'dialog',
|
|
112
|
+
filter: (data): data is { subject: JoinPanelProps } => data.component === JOIN_DIALOG,
|
|
113
|
+
component: ({ data }) => <JoinDialog {...data.subject} />,
|
|
114
|
+
}),
|
|
115
|
+
createSurface({
|
|
116
|
+
id: RECOVER_CODE_DIALOG,
|
|
117
|
+
role: 'dialog',
|
|
118
|
+
filter: (data): data is { subject: RecoveryCodeDialogProps } => data.component === RECOVER_CODE_DIALOG,
|
|
119
|
+
component: ({ data }) => <RecoveryCodeDialog {...data.subject} />,
|
|
120
|
+
}),
|
|
121
|
+
],
|
|
155
122
|
},
|
|
156
123
|
graph: {
|
|
157
124
|
builder: (plugins) => {
|
|
158
|
-
const
|
|
125
|
+
const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatchPromise;
|
|
159
126
|
const id = `${CLIENT_PLUGIN}/open-shell`;
|
|
160
127
|
|
|
161
128
|
return createExtension({
|
|
@@ -165,9 +132,7 @@ export const ClientPlugin = ({
|
|
|
165
132
|
{
|
|
166
133
|
id,
|
|
167
134
|
data: async () => {
|
|
168
|
-
await
|
|
169
|
-
{ plugin: CLIENT_PLUGIN, action: ClientAction.SHARE_IDENTITY },
|
|
170
|
-
]);
|
|
135
|
+
await dispatch?.(createIntent(ClientAction.ShareIdentity));
|
|
171
136
|
},
|
|
172
137
|
properties: {
|
|
173
138
|
label: ['open shell label', { ns: CLIENT_PLUGIN }],
|
|
@@ -186,130 +151,76 @@ export const ClientPlugin = ({
|
|
|
186
151
|
},
|
|
187
152
|
},
|
|
188
153
|
intent: {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
intents: [
|
|
260
|
-
[
|
|
261
|
-
{
|
|
262
|
-
action: LayoutAction.SET_LAYOUT,
|
|
263
|
-
data: {
|
|
264
|
-
element: 'dialog',
|
|
265
|
-
component: 'dxos.org/plugin/client/JoinDialog',
|
|
266
|
-
dialogBlockAlign: 'start',
|
|
267
|
-
subject: {
|
|
268
|
-
initialDisposition: 'recover-identity',
|
|
269
|
-
} satisfies Partial<JoinPanelProps>,
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
],
|
|
273
|
-
],
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
case ClientAction.RESET_STORAGE: {
|
|
278
|
-
await onReset?.({ target: intent.data?.target });
|
|
279
|
-
return { data: true };
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
case ClientAction.CREATE_AGENT: {
|
|
283
|
-
invariant(client.services.services.EdgeAgentService, 'Missing EdgeAgentService');
|
|
284
|
-
await client.services.services.EdgeAgentService.createAgent(null as any, { timeout: 10_000 });
|
|
285
|
-
return { data: true };
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
case ClientAction.CREATE_RECOVERY_CODE: {
|
|
289
|
-
invariant(client.services.services.IdentityService, 'IdentityService not available');
|
|
290
|
-
// TODO(wittjosiah): This needs a proper api. Rename property.
|
|
291
|
-
const { seedphrase } = await client.services.services.IdentityService.createRecoveryPhrase();
|
|
292
|
-
return {
|
|
293
|
-
data: true,
|
|
294
|
-
intents: [
|
|
295
|
-
[
|
|
296
|
-
{
|
|
297
|
-
action: LayoutAction.SET_LAYOUT,
|
|
298
|
-
data: {
|
|
299
|
-
element: 'dialog',
|
|
300
|
-
dialogBlockAlign: 'start',
|
|
301
|
-
dialogType: 'alert',
|
|
302
|
-
state: true,
|
|
303
|
-
component: 'dxos.org/plugin/client/RecoveryCodeDialog',
|
|
304
|
-
subject: { code: seedphrase },
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
],
|
|
308
|
-
],
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
},
|
|
154
|
+
resolvers: () => [
|
|
155
|
+
createResolver(ClientAction.CreateIdentity, async () => {
|
|
156
|
+
const data = await client.halo.createIdentity();
|
|
157
|
+
return { data, intents: [createIntent(ObservabilityAction.SendEvent, { name: 'identity.create' })] };
|
|
158
|
+
}),
|
|
159
|
+
createResolver(ClientAction.JoinIdentity, async (data) => {
|
|
160
|
+
return {
|
|
161
|
+
intents: [
|
|
162
|
+
createIntent(LayoutAction.SetLayout, {
|
|
163
|
+
element: 'dialog',
|
|
164
|
+
component: JOIN_DIALOG,
|
|
165
|
+
dialogBlockAlign: 'start',
|
|
166
|
+
subject: {
|
|
167
|
+
initialInvitationCode: data.invitationCode,
|
|
168
|
+
initialDisposition: 'accept-halo-invitation',
|
|
169
|
+
} satisfies Partial<JoinPanelProps>,
|
|
170
|
+
}),
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
}),
|
|
174
|
+
createResolver(ClientAction.ShareIdentity, async () => {
|
|
175
|
+
return {
|
|
176
|
+
intents: [
|
|
177
|
+
createIntent(LayoutAction.SetLayout, {
|
|
178
|
+
element: 'dialog',
|
|
179
|
+
component: IDENTITY_DIALOG,
|
|
180
|
+
dialogBlockAlign: 'start',
|
|
181
|
+
}),
|
|
182
|
+
createIntent(ObservabilityAction.SendEvent, { name: 'identity.share' }),
|
|
183
|
+
],
|
|
184
|
+
};
|
|
185
|
+
}),
|
|
186
|
+
createResolver(ClientAction.RecoverIdentity, async () => {
|
|
187
|
+
return {
|
|
188
|
+
intents: [
|
|
189
|
+
createIntent(LayoutAction.SetLayout, {
|
|
190
|
+
element: 'dialog',
|
|
191
|
+
component: JOIN_DIALOG,
|
|
192
|
+
dialogBlockAlign: 'start',
|
|
193
|
+
subject: { initialDisposition: 'recover-identity' } satisfies Partial<JoinPanelProps>,
|
|
194
|
+
}),
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
}),
|
|
198
|
+
createResolver(ClientAction.ResetStorage, async (data) => {
|
|
199
|
+
await onReset?.({ target: data.target });
|
|
200
|
+
return {};
|
|
201
|
+
}),
|
|
202
|
+
createResolver(ClientAction.CreateAgent, async () => {
|
|
203
|
+
invariant(client.services.services.EdgeAgentService, 'Missing EdgeAgentService');
|
|
204
|
+
await client.services.services.EdgeAgentService.createAgent(null as any, { timeout: 10_000 });
|
|
205
|
+
}),
|
|
206
|
+
createResolver(ClientAction.CreateRecoveryCode, async () => {
|
|
207
|
+
invariant(client.services.services.IdentityService, 'IdentityService not available');
|
|
208
|
+
// TODO(wittjosiah): This needs a proper api. Rename property.
|
|
209
|
+
const { seedphrase } = await client.services.services.IdentityService.createRecoveryPhrase();
|
|
210
|
+
return {
|
|
211
|
+
intents: [
|
|
212
|
+
createIntent(LayoutAction.SetLayout, {
|
|
213
|
+
element: 'dialog',
|
|
214
|
+
dialogBlockAlign: 'start',
|
|
215
|
+
dialogType: 'alert',
|
|
216
|
+
state: true,
|
|
217
|
+
component: RECOVER_CODE_DIALOG,
|
|
218
|
+
subject: { code: seedphrase },
|
|
219
|
+
}),
|
|
220
|
+
],
|
|
221
|
+
};
|
|
222
|
+
}),
|
|
223
|
+
],
|
|
313
224
|
},
|
|
314
225
|
},
|
|
315
226
|
};
|
|
@@ -4,42 +4,44 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { useCallback } from 'react';
|
|
6
6
|
|
|
7
|
-
import { LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
|
|
7
|
+
import { createIntent, LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
|
|
8
8
|
import { useClient } from '@dxos/react-client';
|
|
9
9
|
import { Clipboard, Dialog } from '@dxos/react-ui';
|
|
10
10
|
import { IdentityPanel, type IdentityPanelProps } from '@dxos/shell/react';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { CLIENT_PLUGIN } from '../meta';
|
|
13
|
+
import { ClientAction } from '../types';
|
|
14
|
+
|
|
15
|
+
export const IDENTITY_DIALOG = `${CLIENT_PLUGIN}/IdentityDialog`;
|
|
13
16
|
|
|
14
17
|
export const IdentityDialog = (props: IdentityPanelProps) => {
|
|
15
|
-
const dispatch = useIntentDispatcher();
|
|
18
|
+
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
16
19
|
const client = useClient();
|
|
17
20
|
|
|
18
21
|
const handleDone = useCallback(
|
|
19
22
|
() =>
|
|
20
|
-
dispatch(
|
|
21
|
-
|
|
22
|
-
data: {
|
|
23
|
+
dispatch(
|
|
24
|
+
createIntent(LayoutAction.SetLayout, {
|
|
23
25
|
element: 'dialog',
|
|
24
26
|
state: false,
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
+
}),
|
|
28
|
+
),
|
|
27
29
|
[dispatch],
|
|
28
30
|
);
|
|
29
31
|
|
|
30
32
|
const handleResetStorage = useCallback(async () => {
|
|
31
33
|
await client.reset();
|
|
32
|
-
await dispatch(
|
|
34
|
+
await dispatch(createIntent(ClientAction.ResetStorage));
|
|
33
35
|
}, [dispatch]);
|
|
34
36
|
|
|
35
37
|
const handleRecover = useCallback(async () => {
|
|
36
38
|
await client.reset();
|
|
37
|
-
await dispatch(
|
|
39
|
+
await dispatch(createIntent(ClientAction.ResetStorage, { target: 'recoverIdentity' }));
|
|
38
40
|
}, [dispatch]);
|
|
39
41
|
|
|
40
42
|
const handleJoinNewIdentity = useCallback(async () => {
|
|
41
43
|
await client.reset();
|
|
42
|
-
await dispatch(
|
|
44
|
+
await dispatch(createIntent(ClientAction.ResetStorage, { target: 'deviceInvitation' }));
|
|
43
45
|
}, [dispatch]);
|
|
44
46
|
|
|
45
47
|
return (
|
|
@@ -4,38 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { useCallback } from 'react';
|
|
6
6
|
|
|
7
|
-
import { LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
|
|
7
|
+
import { createIntent, LayoutAction, useIntentDispatcher } from '@dxos/app-framework';
|
|
8
|
+
import { ObservabilityAction } from '@dxos/plugin-observability/types';
|
|
8
9
|
import { type InvitationResult } from '@dxos/react-client/invitations';
|
|
9
10
|
import { Dialog } from '@dxos/react-ui';
|
|
10
11
|
import { JoinPanel, type JoinPanelProps } from '@dxos/shell/react';
|
|
11
12
|
|
|
12
|
-
import { CLIENT_PLUGIN
|
|
13
|
+
import { CLIENT_PLUGIN } from '../meta';
|
|
14
|
+
import { ClientAction } from '../types';
|
|
15
|
+
|
|
16
|
+
export const JOIN_DIALOG = `${CLIENT_PLUGIN}/JoinDialog`;
|
|
13
17
|
|
|
14
18
|
export const JoinDialog = (props: JoinPanelProps) => {
|
|
15
|
-
const dispatch = useIntentDispatcher();
|
|
19
|
+
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
16
20
|
|
|
17
|
-
const handleCancelResetStorage = useCallback(
|
|
18
|
-
() => dispatch({ plugin: CLIENT_PLUGIN, action: ClientAction.SHARE_IDENTITY }),
|
|
19
|
-
[dispatch],
|
|
20
|
-
);
|
|
21
|
+
const handleCancelResetStorage = useCallback(() => dispatch(createIntent(ClientAction.ShareIdentity)), [dispatch]);
|
|
21
22
|
|
|
22
23
|
const handleDone = useCallback(
|
|
23
24
|
async (result: InvitationResult | null) => {
|
|
24
25
|
if (result?.identityKey) {
|
|
25
26
|
await Promise.all([
|
|
26
|
-
dispatch({
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
element: 'dialog',
|
|
30
|
-
state: false,
|
|
31
|
-
},
|
|
32
|
-
}),
|
|
33
|
-
dispatch({
|
|
34
|
-
action: OBSERVABILITY_ACTION,
|
|
35
|
-
data: {
|
|
27
|
+
dispatch(createIntent(LayoutAction.SetLayout, { element: 'dialog', state: false })),
|
|
28
|
+
dispatch(
|
|
29
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
36
30
|
name: props.initialDisposition === 'recover-identity' ? 'identity.recover' : 'identity.join',
|
|
37
|
-
},
|
|
38
|
-
|
|
31
|
+
}),
|
|
32
|
+
),
|
|
39
33
|
]);
|
|
40
34
|
}
|
|
41
35
|
},
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxos-theme';
|
|
6
|
+
|
|
7
|
+
import { type StoryObj, type Meta } from '@storybook/react';
|
|
8
|
+
import React, { useState } from 'react';
|
|
9
|
+
|
|
10
|
+
import { useClient } from '@dxos/react-client';
|
|
11
|
+
import { withClientProvider } from '@dxos/react-client/testing';
|
|
12
|
+
import { AlertDialog, useAsyncEffect } from '@dxos/react-ui';
|
|
13
|
+
import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
14
|
+
|
|
15
|
+
import { RecoveryCodeDialog, type RecoveryCodeDialogProps } from './RecoveryCodeDialog';
|
|
16
|
+
import translations from '../translations';
|
|
17
|
+
|
|
18
|
+
const Render = () => {
|
|
19
|
+
const client = useClient();
|
|
20
|
+
const [seedphrase, setSeedphrase] = useState<string>();
|
|
21
|
+
useAsyncEffect(async () => {
|
|
22
|
+
const { seedphrase } = (await client.services.services.IdentityService?.createRecoveryPhrase()) ?? {};
|
|
23
|
+
setSeedphrase(seedphrase);
|
|
24
|
+
}, [client]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<AlertDialog.Root open={!!seedphrase}>
|
|
28
|
+
<AlertDialog.Overlay>
|
|
29
|
+
<RecoveryCodeDialog code={seedphrase ?? ''} />
|
|
30
|
+
</AlertDialog.Overlay>
|
|
31
|
+
</AlertDialog.Root>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const meta: Meta<RecoveryCodeDialogProps> = {
|
|
36
|
+
title: 'plugins/plugin-client/RecoveryCodeDialog',
|
|
37
|
+
component: RecoveryCodeDialog,
|
|
38
|
+
render: Render,
|
|
39
|
+
decorators: [withClientProvider({ createIdentity: true }), withTheme, withLayout({ tooltips: true })],
|
|
40
|
+
parameters: {
|
|
41
|
+
layout: 'fullscreen',
|
|
42
|
+
translations,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default meta;
|
|
47
|
+
|
|
48
|
+
type Story = StoryObj<RecoveryCodeDialogProps>;
|
|
49
|
+
|
|
50
|
+
export const Default: Story = {};
|
|
@@ -8,6 +8,8 @@ import { AlertDialog, Button, Clipboard, Input, useTranslation } from '@dxos/rea
|
|
|
8
8
|
|
|
9
9
|
import { CLIENT_PLUGIN } from '../meta';
|
|
10
10
|
|
|
11
|
+
export const RECOVER_CODE_DIALOG = `${CLIENT_PLUGIN}/RecoveryCodeDialog`;
|
|
12
|
+
|
|
11
13
|
export type RecoveryCodeDialogProps = {
|
|
12
14
|
code: string;
|
|
13
15
|
};
|
|
@@ -20,12 +22,15 @@ export const RecoveryCodeDialog = ({ code }: RecoveryCodeDialogProps) => {
|
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
24
|
<AlertDialog.Content classNames='bs-content min-bs-[15rem] max-bs-full md:max-is-[40rem] overflow-hidden'>
|
|
23
|
-
<AlertDialog.Title
|
|
25
|
+
<AlertDialog.Title>{t('recovery code dialog title')}</AlertDialog.Title>
|
|
24
26
|
<p className='py-4'>{t('recovery code dialog description')}</p>
|
|
25
27
|
<Clipboard.Provider>
|
|
26
|
-
<Code
|
|
28
|
+
<Code code={code} />
|
|
27
29
|
</Clipboard.Provider>
|
|
28
|
-
<
|
|
30
|
+
<div className='flex flex-col py-4 gap-2'>
|
|
31
|
+
<p>{t('recovery code dialog warning 1')}</p>
|
|
32
|
+
<p>{t('recovery code dialog warning 2')}</p>
|
|
33
|
+
</div>
|
|
29
34
|
<div className='flex items-center gap-2 pbe-4'>
|
|
30
35
|
<Input.Root>
|
|
31
36
|
<Input.Checkbox
|
|
@@ -47,12 +52,19 @@ export const RecoveryCodeDialog = ({ code }: RecoveryCodeDialogProps) => {
|
|
|
47
52
|
);
|
|
48
53
|
};
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
const
|
|
55
|
+
const Code = ({ code }: { code: string }) => {
|
|
56
|
+
const words = code.split(' ');
|
|
52
57
|
return (
|
|
53
58
|
<div className='relative p-2 border border-separator rounded group'>
|
|
54
|
-
<Clipboard.IconButton value={
|
|
55
|
-
<
|
|
59
|
+
<Clipboard.IconButton value={code} classNames='absolute top-2 right-2 invisible group-hover:visible' />
|
|
60
|
+
<div className='grid grid-cols-4'>
|
|
61
|
+
{words.map((word, i) => (
|
|
62
|
+
<div key={i} className='flex items-center p-2 gap-2 items-center'>
|
|
63
|
+
<div className='w-4 text-xs text-center text-subdued'>{i + 1}</div>
|
|
64
|
+
<div className='text-sm'>{word}</div>
|
|
65
|
+
</div>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
56
68
|
</div>
|
|
57
69
|
);
|
|
58
70
|
};
|
package/src/meta.ts
CHANGED
|
@@ -10,17 +10,3 @@ export default {
|
|
|
10
10
|
id: CLIENT_PLUGIN,
|
|
11
11
|
name: 'Client',
|
|
12
12
|
} satisfies PluginMeta;
|
|
13
|
-
|
|
14
|
-
const CLIENT_ACTION = `${CLIENT_PLUGIN}/action`;
|
|
15
|
-
export enum ClientAction {
|
|
16
|
-
CREATE_IDENTITY = `${CLIENT_ACTION}/CREATE_IDENTITY`,
|
|
17
|
-
JOIN_IDENTITY = `${CLIENT_ACTION}/JOIN_IDENTITY`,
|
|
18
|
-
SHARE_IDENTITY = `${CLIENT_ACTION}/SHARE_IDENTITY`,
|
|
19
|
-
RECOVER_IDENTITY = `${CLIENT_ACTION}/RECOVER_IDENTITY`,
|
|
20
|
-
RESET_STORAGE = `${CLIENT_ACTION}/RESET_STORAGE`,
|
|
21
|
-
CREATE_AGENT = `${CLIENT_ACTION}/CREATE_AGENT`,
|
|
22
|
-
CREATE_RECOVERY_CODE = `${CLIENT_ACTION}/CREATE_RECOVERY_CODE`,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// NOTE: This action is hardcoded to avoid circular dependency with observability plugin.
|
|
26
|
-
export const OBSERVABILITY_ACTION = 'dxos.org/plugin/observability/send-event';
|
package/src/translations.ts
CHANGED
|
@@ -9,12 +9,13 @@ export default [
|
|
|
9
9
|
'en-US': {
|
|
10
10
|
[CLIENT_PLUGIN]: {
|
|
11
11
|
'open shell label': 'Open HALO',
|
|
12
|
-
'recovery code dialog title': 'Recovery
|
|
12
|
+
'recovery code dialog title': 'Account Recovery',
|
|
13
13
|
'recovery code dialog description':
|
|
14
14
|
'This is your identity recovery code, store it in a safe place. You can use it to recover your identity if you ever lose access to your devices.',
|
|
15
|
-
'recovery code dialog warning':
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
'recovery code dialog warning 1': 'NOTE: This code will not be displayed again.',
|
|
16
|
+
'recovery code dialog warning 2':
|
|
17
|
+
'It is your private key for recovering DXOS data. Anyone with this key will be able to gain access to your account.',
|
|
18
|
+
'recovery code confirmation label': 'Please confirm you have saved the code.',
|
|
18
19
|
'continue label': 'Continue',
|
|
19
20
|
},
|
|
20
21
|
},
|