@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.
Files changed (63) hide show
  1. package/dist/lib/browser/chunk-52IJQ35F.mjs +78 -0
  2. package/dist/lib/browser/chunk-52IJQ35F.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-X4QUPYC6.mjs +12 -0
  4. package/dist/lib/browser/chunk-X4QUPYC6.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +184 -233
  6. package/dist/lib/browser/index.mjs.map +3 -3
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/meta.mjs +1 -5
  9. package/dist/lib/browser/types.mjs +10 -0
  10. package/dist/lib/browser/types.mjs.map +7 -0
  11. package/dist/lib/node/chunk-NFO3ADQC.cjs +98 -0
  12. package/dist/lib/node/chunk-NFO3ADQC.cjs.map +7 -0
  13. package/dist/lib/node/chunk-RUA5KXVW.cjs +35 -0
  14. package/dist/lib/node/chunk-RUA5KXVW.cjs.map +7 -0
  15. package/dist/lib/node/index.cjs +186 -236
  16. package/dist/lib/node/index.cjs.map +3 -3
  17. package/dist/lib/node/meta.cjs +4 -8
  18. package/dist/lib/node/meta.cjs.map +2 -2
  19. package/dist/lib/node/meta.json +1 -1
  20. package/dist/lib/node/types.cjs +32 -0
  21. package/dist/lib/node/types.cjs.map +7 -0
  22. package/dist/lib/node-esm/chunk-GMGRQ5Q7.mjs +14 -0
  23. package/dist/lib/node-esm/chunk-GMGRQ5Q7.mjs.map +7 -0
  24. package/dist/lib/node-esm/chunk-TI4GNGMM.mjs +79 -0
  25. package/dist/lib/node-esm/chunk-TI4GNGMM.mjs.map +7 -0
  26. package/dist/lib/node-esm/index.mjs +184 -233
  27. package/dist/lib/node-esm/index.mjs.map +3 -3
  28. package/dist/lib/node-esm/meta.json +1 -1
  29. package/dist/lib/node-esm/meta.mjs +1 -5
  30. package/dist/lib/node-esm/types.mjs +11 -0
  31. package/dist/lib/node-esm/types.mjs.map +7 -0
  32. package/dist/types/src/ClientPlugin.d.ts +2 -35
  33. package/dist/types/src/ClientPlugin.d.ts.map +1 -1
  34. package/dist/types/src/components/IdentityDialog.d.ts +1 -0
  35. package/dist/types/src/components/IdentityDialog.d.ts.map +1 -1
  36. package/dist/types/src/components/JoinDialog.d.ts +1 -0
  37. package/dist/types/src/components/JoinDialog.d.ts.map +1 -1
  38. package/dist/types/src/components/RecoveryCodeDialog.d.ts +1 -0
  39. package/dist/types/src/components/RecoveryCodeDialog.d.ts.map +1 -1
  40. package/dist/types/src/components/RecoveryCodeDialog.stories.d.ts +8 -0
  41. package/dist/types/src/components/RecoveryCodeDialog.stories.d.ts.map +1 -0
  42. package/dist/types/src/meta.d.ts +0 -10
  43. package/dist/types/src/meta.d.ts.map +1 -1
  44. package/dist/types/src/translations.d.ts +2 -1
  45. package/dist/types/src/translations.d.ts.map +1 -1
  46. package/dist/types/src/types.d.ts +110 -0
  47. package/dist/types/src/types.d.ts.map +1 -0
  48. package/dist/types/tsconfig.tsbuildinfo +1 -0
  49. package/package.json +22 -13
  50. package/src/ClientPlugin.tsx +111 -200
  51. package/src/components/IdentityDialog.tsx +13 -11
  52. package/src/components/JoinDialog.tsx +13 -19
  53. package/src/components/RecoveryCodeDialog.stories.tsx +50 -0
  54. package/src/components/RecoveryCodeDialog.tsx +19 -7
  55. package/src/meta.ts +0 -14
  56. package/src/translations.ts +5 -4
  57. package/src/types.ts +115 -0
  58. package/dist/lib/browser/chunk-FGUXUNOK.mjs +0 -26
  59. package/dist/lib/browser/chunk-FGUXUNOK.mjs.map +0 -7
  60. package/dist/lib/node/chunk-XYLDQWFV.cjs +0 -51
  61. package/dist/lib/node/chunk-XYLDQWFV.cjs.map +0 -7
  62. package/dist/lib/node-esm/chunk-C6X363FK.mjs +0 -28
  63. package/dist/lib/node-esm/chunk-C6X363FK.mjs.map +0 -7
@@ -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
- type TranslationsProvides,
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 { Client, type ClientOptions, ClientProvider } from '@dxos/react-client';
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 { IdentityDialog, JoinDialog, RecoveryCodeDialog, type RecoveryCodeDialogProps } from './components';
26
- import meta, { CLIENT_PLUGIN, ClientAction, OBSERVABILITY_ACTION } from './meta';
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
- component: ({ data, role, ...rest }) => {
136
- switch (role) {
137
- case 'dialog':
138
- if (data.component === 'dxos.org/plugin/client/IdentityDialog') {
139
- return (
140
- <IdentityDialog
141
- {...(data.subject as IdentityPanelProps)}
142
- createInvitationUrl={createDeviceInvitationUrl}
143
- />
144
- );
145
- } else if (data.component === 'dxos.org/plugin/client/JoinDialog') {
146
- return <JoinDialog {...(data.subject as JoinPanelProps)} />;
147
- } else if (data.component === 'dxos.org/plugin/client/RecoveryCodeDialog') {
148
- return <RecoveryCodeDialog {...(data.subject as RecoveryCodeDialogProps)} />;
149
- }
150
- break;
151
- }
152
-
153
- return null;
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 intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
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 intentPlugin?.provides.intent.dispatch([
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
- resolver: async (intent) => {
190
- switch (intent.action) {
191
- case ClientAction.CREATE_IDENTITY: {
192
- const data = await client.halo.createIdentity();
193
- return {
194
- data,
195
- intents: [
196
- [
197
- {
198
- action: OBSERVABILITY_ACTION,
199
- data: {
200
- name: 'identity.create',
201
- },
202
- },
203
- ],
204
- ],
205
- };
206
- }
207
-
208
- case ClientAction.JOIN_IDENTITY: {
209
- return {
210
- data: true,
211
- intents: [
212
- [
213
- {
214
- action: LayoutAction.SET_LAYOUT,
215
- data: {
216
- element: 'dialog',
217
- component: 'dxos.org/plugin/client/JoinDialog',
218
- dialogBlockAlign: 'start',
219
- subject: {
220
- initialInvitationCode: intent.data?.invitationCode,
221
- initialDisposition: 'accept-halo-invitation',
222
- } satisfies Partial<JoinPanelProps>,
223
- },
224
- },
225
- ],
226
- ],
227
- };
228
- }
229
-
230
- case ClientAction.SHARE_IDENTITY: {
231
- return {
232
- data: true,
233
- intents: [
234
- [
235
- {
236
- action: LayoutAction.SET_LAYOUT,
237
- data: {
238
- element: 'dialog',
239
- component: 'dxos.org/plugin/client/IdentityDialog',
240
- dialogBlockAlign: 'start',
241
- },
242
- },
243
- ],
244
- [
245
- {
246
- action: OBSERVABILITY_ACTION,
247
- data: {
248
- name: 'identity.share',
249
- },
250
- },
251
- ],
252
- ],
253
- };
254
- }
255
-
256
- case ClientAction.RECOVER_IDENTITY: {
257
- return {
258
- data: true,
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 { ClientAction } from '../meta';
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
- action: LayoutAction.SET_LAYOUT,
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({ action: ClientAction.RESET_STORAGE });
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({ action: ClientAction.RESET_STORAGE, data: { target: 'recoverIdentity' } });
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({ action: ClientAction.RESET_STORAGE, data: { target: 'deviceInvitation' } });
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, ClientAction, OBSERVABILITY_ACTION } from '../meta';
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
- action: LayoutAction.SET_LAYOUT,
28
- data: {
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 classNames=''>{t('recovery code dialog title')}</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 value={code} />
28
+ <Code code={code} />
27
29
  </Clipboard.Provider>
28
- <p className='py-4'>{t('recovery code dialog warning')}</p>
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
- // TODO(wittjosiah): Factor out.
51
- const Code = ({ value }: { value: string }) => {
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={value} classNames='absolute top-2 right-2 invisible group-hover:visible' />
55
- <code className='whitespace-pre-wrap'>{value}</code>
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';
@@ -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 Code',
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
- 'Please note: This code will not be displayed again and cannot be replaced. It is your private key for recovering DXOS data. Anyone with this key will also be able to gain access to your account.',
17
- 'recovery code confirmation label': 'Confirm the code has been saved',
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
  },