@dxos/shell 0.6.14-main.2b6a0f3 → 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.
Files changed (136) hide show
  1. package/dist/bundle/shell.mjs +15116 -11401
  2. package/dist/bundle/shell.mjs.map +1 -1
  3. package/dist/bundle/shell.umd.js +134 -89
  4. package/dist/bundle/shell.umd.js.map +1 -1
  5. package/dist/bundle/style.css +1 -1
  6. package/dist/lib/browser/meta.json +1 -1
  7. package/dist/lib/browser/react.mjs +465 -364
  8. package/dist/lib/browser/react.mjs.map +4 -4
  9. package/dist/lib/browser/testing/index.mjs +1 -39
  10. package/dist/lib/browser/testing/index.mjs.map +4 -4
  11. package/dist/lib/node/chunk-Q7SFCCGT.cjs +33 -0
  12. package/dist/lib/node/chunk-Q7SFCCGT.cjs.map +7 -0
  13. package/dist/lib/node/meta.json +1 -0
  14. package/dist/lib/node/react.cjs +4763 -0
  15. package/dist/lib/node/react.cjs.map +7 -0
  16. package/dist/lib/node/react.css +7 -0
  17. package/dist/lib/node/react.css.map +7 -0
  18. package/dist/lib/node/testing/index.cjs +181 -0
  19. package/dist/lib/node/testing/index.cjs.map +7 -0
  20. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  21. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  22. package/dist/lib/node-esm/meta.json +1 -0
  23. package/dist/lib/node-esm/react.css +7 -0
  24. package/dist/lib/node-esm/react.css.map +7 -0
  25. package/dist/lib/node-esm/react.mjs +4809 -0
  26. package/dist/lib/node-esm/react.mjs.map +7 -0
  27. package/dist/lib/node-esm/testing/index.mjs +161 -0
  28. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  29. package/dist/types/src/components/CompoundButton/CompoundButton.stories.js +1 -1
  30. package/dist/types/src/components/CompoundButton/CompoundButton.stories.js.map +1 -1
  31. package/dist/types/src/components/DeviceList/DeviceList.d.ts +1 -1
  32. package/dist/types/src/components/DeviceList/DeviceList.d.ts.map +1 -1
  33. package/dist/types/src/components/DeviceList/DeviceList.js +2 -2
  34. package/dist/types/src/components/DeviceList/DeviceList.js.map +1 -1
  35. package/dist/types/src/components/DeviceList/DeviceListItem.d.ts.map +1 -1
  36. package/dist/types/src/components/DeviceList/DeviceListItem.js +4 -1
  37. package/dist/types/src/components/DeviceList/DeviceListItem.js.map +1 -1
  38. package/dist/types/src/components/DeviceList/DeviceListProps.d.ts +2 -0
  39. package/dist/types/src/components/DeviceList/DeviceListProps.d.ts.map +1 -1
  40. package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js +3 -3
  41. package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js.map +1 -1
  42. package/dist/types/src/components/InvitationList/InvitationList.stories.js +11 -11
  43. package/dist/types/src/components/InvitationList/InvitationList.stories.js.map +1 -1
  44. package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -1
  45. package/dist/types/src/components/InvitationList/InvitationListContainer.js +2 -2
  46. package/dist/types/src/components/InvitationList/InvitationListContainer.js.map +1 -1
  47. package/dist/types/src/components/Panel/Panel.stories.js +1 -1
  48. package/dist/types/src/components/Panel/Panel.stories.js.map +1 -1
  49. package/dist/types/src/components/Viewport/Viewport.stories.js +1 -1
  50. package/dist/types/src/components/Viewport/Viewport.stories.js.map +1 -1
  51. package/dist/types/src/composites/Shell/Shell.d.ts.map +1 -1
  52. package/dist/types/src/composites/Shell/Shell.js +11 -1
  53. package/dist/types/src/composites/Shell/Shell.js.map +1 -1
  54. package/dist/types/src/panels/IdentityPanel/IdentityPanel.d.ts.map +1 -1
  55. package/dist/types/src/panels/IdentityPanel/IdentityPanel.js +43 -24
  56. package/dist/types/src/panels/IdentityPanel/IdentityPanel.js.map +1 -1
  57. package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.js +1 -1
  58. package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.js.map +1 -1
  59. package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts +2 -1
  60. package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts.map +1 -1
  61. package/dist/types/src/panels/IdentityPanel/identityMachine.d.ts +1 -1
  62. package/dist/types/src/panels/IdentityPanel/identityMachine.d.ts.map +1 -1
  63. package/dist/types/src/panels/IdentityPanel/identityMachine.js +2 -0
  64. package/dist/types/src/panels/IdentityPanel/identityMachine.js.map +1 -1
  65. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.d.ts +3 -5
  66. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.d.ts.map +1 -1
  67. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js +5 -3
  68. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js.map +1 -1
  69. package/dist/types/src/panels/JoinPanel/JoinPanel.stories.js +1 -1
  70. package/dist/types/src/panels/JoinPanel/JoinPanel.stories.js.map +1 -1
  71. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts +1 -1
  72. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts.map +1 -1
  73. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -1
  74. package/dist/types/src/panels/JoinPanel/joinMachine.js +6 -0
  75. package/dist/types/src/panels/JoinPanel/joinMachine.js.map +1 -1
  76. package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.d.ts.map +1 -1
  77. package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.js +1 -3
  78. package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.js.map +1 -1
  79. package/dist/types/src/panels/JoinPanel/steps/IdentityInput.d.ts.map +1 -1
  80. package/dist/types/src/panels/JoinPanel/steps/IdentityInput.js +17 -7
  81. package/dist/types/src/panels/JoinPanel/steps/IdentityInput.js.map +1 -1
  82. package/dist/types/src/panels/Panels.stories.js +1 -1
  83. package/dist/types/src/panels/Panels.stories.js.map +1 -1
  84. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js +16 -16
  85. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js.map +1 -1
  86. package/dist/types/src/playwright/invitations-manager.d.ts +1 -2
  87. package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
  88. package/dist/types/src/playwright/invitations-manager.js +4 -5
  89. package/dist/types/src/playwright/invitations-manager.js.map +1 -1
  90. package/dist/types/src/playwright/invitations.spec.js +13 -25
  91. package/dist/types/src/playwright/invitations.spec.js.map +1 -1
  92. package/dist/types/src/steps/ConfirmReset.d.ts +1 -1
  93. package/dist/types/src/steps/ConfirmReset.d.ts.map +1 -1
  94. package/dist/types/src/steps/ConfirmReset.js +6 -2
  95. package/dist/types/src/steps/ConfirmReset.js.map +1 -1
  96. package/dist/types/src/stories/Invitations.e2e-stories.d.ts +1 -3
  97. package/dist/types/src/stories/Invitations.e2e-stories.d.ts.map +1 -1
  98. package/dist/types/src/stories/Invitations.e2e-stories.js +14 -6
  99. package/dist/types/src/stories/Invitations.e2e-stories.js.map +1 -1
  100. package/dist/types/src/testing/index.d.ts +0 -1
  101. package/dist/types/src/testing/index.d.ts.map +1 -1
  102. package/dist/types/src/testing/index.js +1 -1
  103. package/dist/types/src/testing/index.js.map +1 -1
  104. package/dist/types/src/translations/locales/en-US.d.ts +2 -0
  105. package/dist/types/src/translations/locales/en-US.d.ts.map +1 -1
  106. package/dist/types/src/translations/locales/en-US.js +2 -0
  107. package/dist/types/src/translations/locales/en-US.js.map +1 -1
  108. package/package.json +39 -28
  109. package/src/components/CompoundButton/CompoundButton.stories.tsx +1 -1
  110. package/src/components/DeviceList/DeviceList.tsx +2 -1
  111. package/src/components/DeviceList/DeviceListItem.tsx +8 -0
  112. package/src/components/DeviceList/DeviceListProps.ts +2 -0
  113. package/src/components/IdentityList/SpaceMemberList.stories.tsx +2 -2
  114. package/src/components/InvitationList/InvitationList.stories.tsx +2 -2
  115. package/src/components/InvitationList/InvitationListContainer.tsx +6 -3
  116. package/src/components/Panel/Panel.stories.tsx +1 -1
  117. package/src/components/Viewport/Viewport.stories.tsx +1 -1
  118. package/src/composites/Shell/Shell.tsx +12 -1
  119. package/src/panels/IdentityPanel/IdentityPanel.stories.tsx +1 -1
  120. package/src/panels/IdentityPanel/IdentityPanel.tsx +78 -44
  121. package/src/panels/IdentityPanel/IdentityPanelProps.ts +2 -0
  122. package/src/panels/IdentityPanel/identityMachine.ts +3 -1
  123. package/src/panels/IdentityPanel/steps/IdentityActionChooser.tsx +21 -10
  124. package/src/panels/JoinPanel/JoinPanel.stories.tsx +1 -1
  125. package/src/panels/JoinPanel/JoinPanelProps.ts +1 -1
  126. package/src/panels/JoinPanel/joinMachine.ts +7 -0
  127. package/src/panels/JoinPanel/steps/AdditionMethodChooser.tsx +0 -2
  128. package/src/panels/JoinPanel/steps/IdentityInput.tsx +22 -10
  129. package/src/panels/Panels.stories.tsx +1 -1
  130. package/src/panels/SpacePanel/SpacePanel.stories.tsx +2 -2
  131. package/src/playwright/invitations-manager.ts +5 -5
  132. package/src/playwright/invitations.spec.ts +14 -25
  133. package/src/steps/ConfirmReset.tsx +13 -5
  134. package/src/stories/Invitations.e2e-stories.tsx +17 -10
  135. package/src/testing/index.ts +2 -1
  136. package/src/translations/locales/en-US.ts +2 -0
@@ -21,6 +21,7 @@ export type IdentityPanelImplProps = {
21
21
  | 'device invitation manager'
22
22
  | 'identity action chooser'
23
23
  | 'confirm join new identity'
24
+ | 'confirm recover'
24
25
  | 'confirm reset storage';
25
26
  initialDisposition?: IdentityPanelInitialDisposition;
26
27
  identity: Identity;
@@ -29,6 +30,7 @@ export type IdentityPanelImplProps = {
29
30
  onChangeConnectionState?: (nextState: ConnectionState) => Promise<void>;
30
31
  onUpdateProfile?: (profile: NonNullable<Identity['profile']>) => Promise<void>;
31
32
  onResetStorage?: () => Promise<void>;
33
+ onRecover?: () => Promise<void>;
32
34
  onJoinNewIdentity?: () => Promise<void>;
33
35
  createInvitationUrl: (invitationCode: string) => string;
34
36
  send?: (event: SingleOrArray<Event<IdentityEvent>>) => void;
@@ -21,7 +21,7 @@ type IdentityMachineContext = {
21
21
  };
22
22
 
23
23
  type IdentityChooseActionEvent = {
24
- type: 'chooseResetStorage' | 'chooseJoinNewIdentity' | 'unchooseAction';
24
+ type: 'chooseResetStorage' | 'chooseRecoverIdentity' | 'chooseJoinNewIdentity' | 'unchooseAction';
25
25
  };
26
26
 
27
27
  type IdentitySelectDeviceInvitationEvent = {
@@ -67,6 +67,7 @@ const identityMachine = createMachine<IdentityMachineContext, IdentityEvent>(
67
67
  choosingAction: {},
68
68
  managingDeviceInvitation: {},
69
69
  confirmingResetStorage: {},
70
+ confirmingRecover: {},
70
71
  confirmingJoinNewIdentity: {},
71
72
  },
72
73
  on: {
@@ -74,6 +75,7 @@ const identityMachine = createMachine<IdentityMachineContext, IdentityEvent>(
74
75
  deselectInvitation: { target: '.choosingAction', actions: ['unsetInvitation', 'log'] },
75
76
  selectInvitation: { target: '.managingDeviceInvitation', actions: ['setInvitation', 'log'] },
76
77
  chooseJoinNewIdentity: { target: '.confirmingJoinNewIdentity', actions: 'log' },
78
+ chooseRecoverIdentity: { target: '.confirmingRecover', actions: 'log' },
77
79
  chooseResetStorage: { target: '.confirmingResetStorage', actions: 'log' },
78
80
  },
79
81
  },
@@ -9,7 +9,7 @@ import { useClient } from '@dxos/react-client';
9
9
  import { useHaloInvitations, DeviceType } from '@dxos/react-client/halo';
10
10
  import { Invitation, InvitationEncoder } from '@dxos/react-client/invitations';
11
11
 
12
- import { AgentConfig, type AgentFormProps, DeviceList } from '../../../components';
12
+ import { AgentConfig, type AgentFormProps, DeviceList, type DeviceListProps } from '../../../components';
13
13
  import { type IdentityPanelStepProps } from '../IdentityPanelProps';
14
14
 
15
15
  export type IdentityActionChooserProps = IdentityPanelStepProps;
@@ -33,20 +33,30 @@ export const IdentityActionChooser = (props: IdentityPanelStepProps) => {
33
33
  }
34
34
  send?.({ type: 'selectInvitation', invitation });
35
35
  };
36
- return <IdentityActionChooserImpl {...props} onCreateInvitationClick={createInvitation} />;
36
+ const isProduction = client.config.values.runtime?.app?.env?.DX_ENVIRONMENT === 'production';
37
+ return (
38
+ <IdentityActionChooserImpl
39
+ {...props}
40
+ onClickAdd={createInvitation}
41
+ onClickJoinExisting={() => send?.({ type: 'chooseJoinNewIdentity' })}
42
+ onClickRecover={isProduction ? undefined : () => send?.({ type: 'chooseRecoverIdentity' })}
43
+ onClickReset={() => send?.({ type: 'chooseResetStorage' })}
44
+ />
45
+ );
37
46
  };
38
47
 
39
48
  export type IdentityActionChooserImplProps = IdentityActionChooserProps &
40
- Partial<AgentFormProps> & {
41
- onCreateInvitationClick?: () => void;
42
- };
49
+ Partial<AgentFormProps> &
50
+ Pick<DeviceListProps, 'onClickAdd' | 'onClickJoinExisting' | 'onClickRecover' | 'onClickReset'>;
43
51
 
44
52
  export const IdentityActionChooserImpl = ({
45
- send,
46
- onCreateInvitationClick,
47
53
  devices,
48
54
  connectionState,
49
55
  agentHostingEnabled,
56
+ onClickAdd,
57
+ onClickJoinExisting,
58
+ onClickRecover,
59
+ onClickReset,
50
60
  ...agentProps
51
61
  }: IdentityActionChooserImplProps) => {
52
62
  const managedDeviceAvailable = devices.find((device) => device.profile?.type === DeviceType.AGENT_MANAGED);
@@ -55,9 +65,10 @@ export const IdentityActionChooserImpl = ({
55
65
  <DeviceList
56
66
  devices={devices}
57
67
  connectionState={connectionState}
58
- onClickAdd={onCreateInvitationClick}
59
- onClickJoinExisting={() => send?.({ type: 'chooseJoinNewIdentity' })}
60
- onClickReset={() => send?.({ type: 'chooseResetStorage' })}
68
+ onClickAdd={onClickAdd}
69
+ onClickJoinExisting={onClickJoinExisting}
70
+ onClickRecover={onClickRecover}
71
+ onClickReset={onClickReset}
61
72
  onAgentDestroy={agentProps.onAgentDestroy!}
62
73
  />
63
74
  {!managedDeviceAvailable && agentHostingEnabled && <AgentConfig {...(agentProps as AgentFormProps)} />}
@@ -30,7 +30,7 @@ const JoinDialog = (args: Partial<JoinPanelImplProps>) => (
30
30
  );
31
31
 
32
32
  export default {
33
- title: 'sdk/react-shell/JoinPanel',
33
+ title: 'sdk/shell/JoinPanel',
34
34
  component: JoinDialog,
35
35
  decorators: [withTheme],
36
36
  parameters: { translations, chromatic: { disableSnapshot: false } },
@@ -14,7 +14,7 @@ import { type FailReason } from '../../types';
14
14
 
15
15
  export type JoinPanelMode = 'default' | 'halo-only';
16
16
 
17
- export type JoinPanelInitialDisposition = 'default' | 'accept-halo-invitation';
17
+ export type JoinPanelInitialDisposition = 'default' | 'accept-halo-invitation' | 'recover-identity';
18
18
 
19
19
  export type JoinStepProps = Omit<StepProps, 'send' | 'onDone'> & {
20
20
  send: JoinSend;
@@ -312,6 +312,11 @@ const joinMachine = createMachine<JoinMachineContext, JoinEvent>(
312
312
  target: '#join.choosingIdentity.acceptingHaloInvitation',
313
313
  actions: 'log',
314
314
  },
315
+ {
316
+ cond: 'initiallyRecoveringIdentity',
317
+ target: '#join.choosingIdentity.recoveringIdentity',
318
+ actions: 'log',
319
+ },
315
320
  { cond: 'noSelectedIdentity', target: 'choosingIdentity', actions: 'log' },
316
321
  { target: 'acceptingSpaceInvitation', actions: 'log' },
317
322
  ],
@@ -364,6 +369,8 @@ const joinMachine = createMachine<JoinMachineContext, JoinEvent>(
364
369
  noSelectedIdentity: ({ identity }, _event) => !identity,
365
370
  initiallyAcceptingHaloInvitation: ({ identity, initialDisposition }, _event) =>
366
371
  !identity && initialDisposition === 'accept-halo-invitation',
372
+ initiallyRecoveringIdentity: ({ identity, initialDisposition }, _event) =>
373
+ !identity && initialDisposition === 'recover-identity',
367
374
  hasHaloUnredeemedCode: ({ halo }, _event) => !!halo.unredeemedCode,
368
375
  noSpaceInvitation: ({ space }, _event) => !space.invitation && !space.unredeemedCode,
369
376
  },
@@ -50,8 +50,6 @@ export const AdditionMethodChooser = (viewStateProps: AdditionMethodChooserProps
50
50
  </CompoundButton>
51
51
  <CompoundButton
52
52
  {...sharedButtonProps}
53
- // TODO(mykola): Implement recover.
54
- disabled={true}
55
53
  description={t('recover identity description')}
56
54
  before={<Textbox className={getSize(6)} />}
57
55
  onClick={() => send({ type: 'recoverIdentity' })}
@@ -28,16 +28,28 @@ export const IdentityInput = (props: IdentityInputProps) => {
28
28
  const client = useClient();
29
29
  const { t } = useTranslation('os');
30
30
  const [validationMessage, setValidationMessage] = useState('');
31
- const createIdentity = (displayName: string) => {
32
- void client.halo.createIdentity({ [isRecover ? 'seedphrase' : 'displayName']: displayName }).then(
33
- (identity) => {
34
- send?.({ type: 'selectIdentity' as const, identity });
35
- },
36
- (error) => {
37
- log.catch(error);
38
- setValidationMessage(t(isRecover ? 'failed to recover identity message' : 'failed to create identity message'));
39
- },
40
- );
31
+ const createIdentity = (value: string) => {
32
+ if (isRecover) {
33
+ void client.halo.recoverIdentity({ seedphrase: value }).then(
34
+ (identity) => {
35
+ send?.({ type: 'selectIdentity' as const, identity });
36
+ },
37
+ (error) => {
38
+ log.catch(error);
39
+ setValidationMessage(t('failed to recover identity message'));
40
+ },
41
+ );
42
+ } else {
43
+ void client.halo.createIdentity({ displayName: value }).then(
44
+ (identity) => {
45
+ send?.({ type: 'selectIdentity' as const, identity });
46
+ },
47
+ (error) => {
48
+ log.catch(error);
49
+ setValidationMessage(t('failed to create identity message'));
50
+ },
51
+ );
52
+ }
41
53
  };
42
54
  return <IdentityInputImpl {...props} onDisplayNameConfirm={createIdentity} validationMessage={validationMessage} />;
43
55
  };
@@ -53,7 +53,7 @@ export const Default = (props: any) => {
53
53
  Default.parameters = { layout: 'fullscreen' };
54
54
 
55
55
  export default {
56
- title: 'sdk/react-shell/All',
56
+ title: 'sdk/shell/All',
57
57
  decorators: [withTheme],
58
58
  component: StoryRow,
59
59
  parameters: { chromatic: { disableSnapshot: false }, translations: [osTranslations] },
@@ -17,7 +17,7 @@ import { SpaceManagerImpl } from './steps';
17
17
  import { InvitationListItemImpl, SpaceMemberListImpl, InvitationList } from '../../components';
18
18
  import { StorybookDialog } from '../../components/StorybookDialog';
19
19
  import { InvitationManager, type InvitationManagerProps } from '../../steps';
20
- import { inviteWithState } from '../../testing';
20
+ import { inviteWithState } from '../../testing/fixtures';
21
21
 
22
22
  const noOpProps: SpacePanelImplProps = {
23
23
  titleId: 'storybookSpacePanel__title',
@@ -28,7 +28,7 @@ const noOpProps: SpacePanelImplProps = {
28
28
  };
29
29
 
30
30
  export default {
31
- title: 'sdk/react-shell/SpacePanel',
31
+ title: 'sdk/shell/SpacePanel',
32
32
  component: SpacePanelImpl,
33
33
  decorators: [withTheme],
34
34
  parameters: { chromatic: { disableSnapshot: false } },
@@ -6,7 +6,6 @@ import { expect, type Browser, type ConsoleMessage } from '@playwright/test';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
8
  import { type Invitation } from '@dxos/react-client/invitations';
9
- import { ConnectionState } from '@dxos/react-client/mesh';
10
9
  import { setupPage } from '@dxos/test-utils/playwright';
11
10
 
12
11
  import { ScopedShellManager } from '../testing';
@@ -32,7 +31,7 @@ export class InvitationsManager extends ScopedShellManager {
32
31
  }
33
32
 
34
33
  const { page } = await setupPage(this._browser, {
35
- url: storybookUrl('invitations--default'),
34
+ url: storybookUrl('sdk-shell-invitations--default'),
36
35
  });
37
36
 
38
37
  this.page = page;
@@ -56,9 +55,9 @@ export class InvitationsManager extends ScopedShellManager {
56
55
 
57
56
  try {
58
57
  await selector.waitFor({ timeout: 500 });
59
- return ConnectionState.OFFLINE;
58
+ return 0;
60
59
  } catch {
61
- return ConnectionState.ONLINE;
60
+ return 1;
62
61
  }
63
62
  }
64
63
 
@@ -144,7 +143,8 @@ export class InvitationsManager extends ScopedShellManager {
144
143
  },
145
144
  { id, type, options },
146
145
  );
147
- return this._invitationCode.wait();
146
+
147
+ return this._invitationCode.wait({ timeout: 1_000 });
148
148
  }
149
149
 
150
150
  async acceptInvitation(id: number, type: 'device' | 'space', invitation: string) {
@@ -5,11 +5,16 @@
5
5
  import { expect, test } from '@playwright/test';
6
6
 
7
7
  import { sleep } from '@dxos/async';
8
- import { Invitation } from '@dxos/react-client/invitations';
9
- import { ConnectionState } from '@dxos/react-client/mesh';
10
8
 
11
9
  import { InvitationsManager } from './invitations-manager';
12
10
 
11
+ // TODO(wittjosiah): Can't import these because of ESM/CJS issues.
12
+ // import { Invitation } from '@dxos/react-client/invitations';
13
+ // import { ConnectionState } from '@dxos/react-client/mesh';
14
+ const InvitationAuthMethodNone = 0;
15
+ const ConnectionStateOffline = 0;
16
+ const ConnectionStateOnline = 1;
17
+
13
18
  test.describe('Invitations', () => {
14
19
  let manager: InvitationsManager;
15
20
 
@@ -44,7 +49,6 @@ test.describe('Invitations', () => {
44
49
  await manager.acceptInvitation(1, 'device', invitation);
45
50
  await manager.readyToAuthenticate('device', manager.peer(1));
46
51
  await manager.authenticateInvitation('device', authCode, manager.peer(1));
47
- await manager.doneInvitation('device', manager.peer(1));
48
52
 
49
53
  expect(await manager.getDisplayName(0)).toEqual(await manager.getDisplayName(1));
50
54
  });
@@ -52,11 +56,10 @@ test.describe('Invitations', () => {
52
56
  test('no auth method', async () => {
53
57
  await manager.createIdentity(0);
54
58
  await manager.openPanel(0, 'devices');
55
- const invitation = await manager.createInvitation(0, 'device', { authMethod: Invitation.AuthMethod.NONE });
59
+ const invitation = await manager.createInvitation(0, 'device', { authMethod: InvitationAuthMethodNone });
56
60
 
57
61
  await manager.openPanel(1, 'identity');
58
62
  await manager.acceptInvitation(1, 'device', invitation);
59
- await manager.doneInvitation('device', manager.peer(1));
60
63
 
61
64
  expect(await manager.getDisplayName(0)).toEqual(await manager.getDisplayName(1));
62
65
  });
@@ -72,7 +75,6 @@ test.describe('Invitations', () => {
72
75
  await manager.authenticateInvitation('device', '000000', manager.peer(1));
73
76
  await manager.clearAuthCode('device', manager.peer(1));
74
77
  await manager.authenticateInvitation('device', authCode, manager.peer(1));
75
- await manager.doneInvitation('device', manager.peer(1));
76
78
 
77
79
  expect(await manager.getDisplayName(0)).toEqual(await manager.getDisplayName(1));
78
80
  });
@@ -99,7 +101,6 @@ test.describe('Invitations', () => {
99
101
  await manager.invitationInputContinue('device', manager.peer(1));
100
102
  await manager.clearAuthCode('device', manager.peer(1));
101
103
  await manager.authenticateInvitation('device', authCode, manager.peer(1));
102
- await manager.doneInvitation('device', manager.peer(1));
103
104
 
104
105
  expect(await manager.getDisplayName(0)).toEqual(await manager.getDisplayName(1));
105
106
  });
@@ -144,7 +145,6 @@ test.describe('Invitations', () => {
144
145
  await manager.invitationInputContinue('device', manager.peer(1));
145
146
  await manager.clearAuthCode('device', manager.peer(1));
146
147
  await manager.authenticateInvitation('device', authCode, manager.peer(1));
147
- await manager.doneInvitation('device', manager.peer(1));
148
148
 
149
149
  expect(await manager.getDisplayName(0)).toEqual(await manager.getDisplayName(1));
150
150
  });
@@ -160,14 +160,13 @@ test.describe('Invitations', () => {
160
160
  await manager.acceptInvitation(1, 'device', invitation);
161
161
  expect(await manager.readyToAuthenticate('device', manager.peer(1))).toBe(true);
162
162
  await manager.toggleNetworkStatus(0);
163
- expect(await manager.getNetworkStatus(0)).toEqual(ConnectionState.OFFLINE);
163
+ expect(await manager.getNetworkStatus(0)).toEqual(ConnectionStateOffline);
164
164
  await manager.toggleNetworkStatus(0);
165
- expect(await manager.getNetworkStatus(0)).toEqual(ConnectionState.ONLINE);
165
+ expect(await manager.getNetworkStatus(0)).toEqual(ConnectionStateOnline);
166
166
  await manager.resetInvitation(manager.peer(1));
167
167
  await manager.invitationInputContinue('device', manager.peer(1));
168
168
  await manager.clearAuthCode('device', manager.peer(1));
169
169
  await manager.authenticateInvitation('device', authCode, manager.peer(1));
170
- await manager.doneInvitation('device', manager.peer(1));
171
170
 
172
171
  expect(await manager.getDisplayName(0)).toEqual(await manager.getDisplayName(1));
173
172
  });
@@ -186,7 +185,6 @@ test.describe('Invitations', () => {
186
185
  await manager.acceptInvitation(1, 'space', invitation);
187
186
  await manager.readyToAuthenticate('space', manager.peer(1));
188
187
  await manager.authenticateInvitation('space', authCode, manager.peer(1));
189
- await manager.doneInvitation('space', manager.peer(1));
190
188
 
191
189
  await manager.openPanel(0, 'spaces');
192
190
  expect(await manager.getSpaceName(0, 1)).toEqual(await manager.getSpaceName(1, 1));
@@ -196,17 +194,15 @@ test.describe('Invitations', () => {
196
194
  await manager.createIdentity(0);
197
195
  await manager.createSpace(0);
198
196
  await manager.openPanel(0, 1);
199
- const invitation1 = await manager.createInvitation(0, 'space', { authMethod: Invitation.AuthMethod.NONE });
197
+ const invitation1 = await manager.createInvitation(0, 'space', { authMethod: InvitationAuthMethodNone });
200
198
  const invitation2 = await manager.createInvitation(0, 'space');
201
199
 
202
200
  await manager.createIdentity(1);
203
201
  await manager.openPanel(1, 'join');
204
202
  await manager.acceptInvitation(1, 'space', invitation1);
205
- await manager.doneInvitation('space', manager.peer(1));
206
203
 
207
204
  await manager.openPanel(1, 'join');
208
205
  await manager.acceptInvitation(1, 'space', invitation2);
209
- await manager.doneInvitation('space', manager.peer(1));
210
206
 
211
207
  expect(await manager.getSpaceMembersCount(0)).toEqual(2);
212
208
  });
@@ -215,12 +211,11 @@ test.describe('Invitations', () => {
215
211
  await manager.createIdentity(0);
216
212
  await manager.createSpace(0);
217
213
  await manager.openPanel(0, 1);
218
- const invitation = await manager.createInvitation(0, 'space', { authMethod: Invitation.AuthMethod.NONE });
214
+ const invitation = await manager.createInvitation(0, 'space', { authMethod: InvitationAuthMethodNone });
219
215
 
220
216
  await manager.createIdentity(1);
221
217
  await manager.openPanel(1, 'join');
222
218
  await manager.acceptInvitation(1, 'space', invitation);
223
- await manager.doneInvitation('space', manager.peer(1));
224
219
 
225
220
  await manager.openPanel(0, 'spaces');
226
221
  expect(await manager.getSpaceName(0, 1)).toEqual(await manager.getSpaceName(1, 1));
@@ -242,7 +237,6 @@ test.describe('Invitations', () => {
242
237
 
243
238
  await manager.clearAuthCode('space', manager.peer(1));
244
239
  await manager.authenticateInvitation('space', authCode, manager.peer(1));
245
- await manager.doneInvitation('space', manager.peer(1));
246
240
 
247
241
  await manager.openPanel(0, 'spaces');
248
242
  expect(await manager.getSpaceName(0, 1)).toEqual(await manager.getSpaceName(1, 1));
@@ -272,7 +266,6 @@ test.describe('Invitations', () => {
272
266
  await manager.invitationInputContinue('space', manager.peer(1));
273
267
  await manager.clearAuthCode('space', manager.peer(1));
274
268
  await manager.authenticateInvitation('space', authCode, manager.peer(1));
275
- await manager.doneInvitation('space', manager.peer(1));
276
269
 
277
270
  await manager.openPanel(0, 'spaces');
278
271
  expect(await manager.getSpaceName(0, 1)).toEqual(await manager.getSpaceName(1, 1));
@@ -323,7 +316,6 @@ test.describe('Invitations', () => {
323
316
  await manager.invitationInputContinue('space', manager.peer(1));
324
317
  await manager.clearAuthCode('space', manager.peer(1));
325
318
  await manager.authenticateInvitation('space', authCode, manager.peer(1));
326
- await manager.doneInvitation('space', manager.peer(1));
327
319
 
328
320
  await manager.openPanel(0, 'spaces');
329
321
  expect(await manager.getSpaceName(0, 1)).toEqual(await manager.getSpaceName(1, 1));
@@ -342,14 +334,13 @@ test.describe('Invitations', () => {
342
334
  await manager.acceptInvitation(1, 'space', invitation);
343
335
  expect(await manager.readyToAuthenticate('space', manager.peer(1))).toBe(true);
344
336
  await manager.toggleNetworkStatus(0);
345
- expect(await manager.getNetworkStatus(0)).toEqual(ConnectionState.OFFLINE);
337
+ expect(await manager.getNetworkStatus(0)).toEqual(ConnectionStateOffline);
346
338
  await manager.toggleNetworkStatus(0);
347
- expect(await manager.getNetworkStatus(0)).toEqual(ConnectionState.ONLINE);
339
+ expect(await manager.getNetworkStatus(0)).toEqual(ConnectionStateOnline);
348
340
  await manager.resetInvitation(manager.peer(1));
349
341
  await manager.invitationInputContinue('space', manager.peer(1));
350
342
  await manager.clearAuthCode('space', manager.peer(1));
351
343
  await manager.authenticateInvitation('space', authCode, manager.peer(1));
352
- await manager.doneInvitation('space', manager.peer(1));
353
344
 
354
345
  await manager.openPanel(0, 'spaces');
355
346
  expect(await manager.getSpaceName(0, 1)).toEqual(await manager.getSpaceName(1, 1));
@@ -380,8 +371,6 @@ test.describe('Invitations', () => {
380
371
  // Helps to ensure both auth codes are fully input (especially in webkit).
381
372
  await sleep(100);
382
373
  await manager.authenticateInvitation('space', authCode2, manager.peer(2));
383
- await manager.doneInvitation('space', manager.peer(1));
384
- await manager.doneInvitation('space', manager.peer(2));
385
374
 
386
375
  await manager.openPanel(0, 'spaces');
387
376
  expect(await manager.getSpaceName(0, 1)).toEqual(await manager.getSpaceName(1, 1));
@@ -15,7 +15,7 @@ import { Action, Actions, StepHeading, Input } from '../components';
15
15
  type ConfirmResetOptions = Partial<{
16
16
  onCancel: () => void;
17
17
  onConfirm: () => Promise<void>;
18
- mode: 'join new identity' | 'reset storage';
18
+ mode: 'join new identity' | 'recover' | 'reset storage';
19
19
  }>;
20
20
 
21
21
  export type ConfirmResetProps = StepProps & ConfirmResetOptions;
@@ -64,7 +64,8 @@ export const ConfirmResetImpl = ({
64
64
  const { t } = useTranslation('os');
65
65
  const confirmationValue = t('confirmation value');
66
66
  const [inputValue, setInputValue] = useState('');
67
- const testIdAffix = mode === 'join new identity' ? 'join-new-identity' : 'reset-storage';
67
+ const testIdAffix =
68
+ mode === 'join new identity' ? 'join-new-identity' : mode === 'recover' ? 'recover' : 'reset-storage';
68
69
  return (
69
70
  <>
70
71
  <div role='none' className='grow flex flex-col gap-2 justify-center'>
@@ -79,9 +80,16 @@ export const ConfirmResetImpl = ({
79
80
  {...{ validationMessage }}
80
81
  label={
81
82
  <StepHeading className='text-start mlb-2'>
82
- {t(mode === 'join new identity' ? 'join new identity input label' : 'reset storage input label', {
83
- confirmationValue,
84
- })}
83
+ {t(
84
+ mode === 'join new identity'
85
+ ? 'join new identity input label'
86
+ : mode === 'recover'
87
+ ? 'recover reset input label'
88
+ : 'reset storage input label',
89
+ {
90
+ confirmationValue,
91
+ },
92
+ )}
85
93
  </StepHeading>
86
94
  }
87
95
  disabled={disabled}
@@ -14,7 +14,7 @@ import { type Space, type SpaceMember, useSpaces } from '@dxos/react-client/echo
14
14
  import { useIdentity } from '@dxos/react-client/halo';
15
15
  import { Invitation, InvitationEncoder } from '@dxos/react-client/invitations';
16
16
  import { ConnectionState, useNetworkStatus } from '@dxos/react-client/mesh';
17
- import { ClientRepeater } from '@dxos/react-client/testing';
17
+ import { useMultiClient, withMultiClientProvider } from '@dxos/react-client/testing';
18
18
  import { Button, ButtonGroup, List } from '@dxos/react-ui';
19
19
  import { getSize, groupSurface } from '@dxos/react-ui-theme';
20
20
  import { withLayout, withTheme } from '@dxos/storybook-utils';
@@ -24,7 +24,7 @@ import { IdentityPanel, JoinPanel, SpacePanel } from '../panels';
24
24
  import { osTranslations } from '../translations';
25
25
 
26
26
  export default {
27
- title: 'Invitations',
27
+ title: 'sdk/shell/Invitations',
28
28
  };
29
29
 
30
30
  export type PanelType = Space | 'identity' | 'devices' | 'join';
@@ -113,8 +113,8 @@ const Panel = ({ id, panel, setPanel }: { id: number; panel?: PanelType; setPane
113
113
  }
114
114
  };
115
115
 
116
- const Invitations = (args: { id: number; count: number }) => {
117
- const { id }: { id: number } = args;
116
+ const Invitations = () => {
117
+ const { id } = useMultiClient();
118
118
  const client = useClient();
119
119
  const networkStatus = useNetworkStatus().swarm;
120
120
  const identity = useIdentity();
@@ -220,12 +220,19 @@ const Invitations = (args: { id: number; count: number }) => {
220
220
  // The issue appears to be related to dynamic imports during client initialization.
221
221
  // This does not seem to be a problem in other browsers nor in Safari in the app.
222
222
  export const Default = {
223
- render: (args: { id: number }) => (
224
- <ClipboardProvider>
225
- <ClientRepeater component={Invitations} count={3} />
226
- </ClipboardProvider>
227
- ),
228
- decorators: [withTheme, withLayout({ tooltips: true })],
223
+ render: () => {
224
+ return (
225
+ // TODO(wittjosiah): Factor out ClipboardProvider to react-ui and include in layout decorator.
226
+ <ClipboardProvider>
227
+ <Invitations />
228
+ </ClipboardProvider>
229
+ );
230
+ },
231
+ decorators: [
232
+ withMultiClientProvider({ numClients: 3 }),
233
+ withLayout({ tooltips: true, classNames: 'grid grid-cols-3' }),
234
+ withTheme,
235
+ ],
229
236
  parameters: {
230
237
  chromatic: { disableSnapshot: true },
231
238
  translations: [osTranslations],
@@ -2,6 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './fixtures';
5
+ // NOTE: Not exporting fixtures as they depend on esm-only packages.
6
+
6
7
  export * from './scoped-shell-manager';
7
8
  export * from './shell-manager';
@@ -153,4 +153,6 @@ export const os = {
153
153
  'agent requested description':
154
154
  'The agent service is creating an agent for you. Once the agent connects, it will display in the devices list.',
155
155
  'authenticating label': 'Authenticating…',
156
+ 'create recovery code label': 'Create recovery code',
157
+ 'choose recover identity label': 'Recover identity',
156
158
  };