@dxos/shell 0.6.13 → 0.6.14-main.69511f5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/dist/bundle/shell.mjs +16256 -15872
  2. package/dist/bundle/shell.mjs.map +1 -1
  3. package/dist/bundle/shell.umd.js +146 -108
  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 +428 -229
  8. package/dist/lib/browser/react.mjs.map +4 -4
  9. package/dist/lib/browser/testing/index.mjs +3 -46
  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.d.ts +0 -3
  41. package/dist/types/src/components/IdentityList/SpaceMemberList.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js +3 -4
  43. package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js.map +1 -1
  44. package/dist/types/src/components/InvitationList/InvitationList.stories.d.ts +0 -3
  45. package/dist/types/src/components/InvitationList/InvitationList.stories.d.ts.map +1 -1
  46. package/dist/types/src/components/InvitationList/InvitationList.stories.js +11 -12
  47. package/dist/types/src/components/InvitationList/InvitationList.stories.js.map +1 -1
  48. package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -1
  49. package/dist/types/src/components/InvitationList/InvitationListContainer.js +2 -2
  50. package/dist/types/src/components/InvitationList/InvitationListContainer.js.map +1 -1
  51. package/dist/types/src/components/Panel/Panel.stories.d.ts +0 -3
  52. package/dist/types/src/components/Panel/Panel.stories.d.ts.map +1 -1
  53. package/dist/types/src/components/Panel/Panel.stories.js +1 -2
  54. package/dist/types/src/components/Panel/Panel.stories.js.map +1 -1
  55. package/dist/types/src/components/Viewport/Viewport.stories.js +1 -1
  56. package/dist/types/src/components/Viewport/Viewport.stories.js.map +1 -1
  57. package/dist/types/src/composites/Shell/Shell.d.ts.map +1 -1
  58. package/dist/types/src/composites/Shell/Shell.js +14 -3
  59. package/dist/types/src/composites/Shell/Shell.js.map +1 -1
  60. package/dist/types/src/composites/Shell/run-shell.js +1 -1
  61. package/dist/types/src/composites/Shell/run-shell.js.map +1 -1
  62. package/dist/types/src/panels/IdentityPanel/IdentityPanel.d.ts.map +1 -1
  63. package/dist/types/src/panels/IdentityPanel/IdentityPanel.js +44 -25
  64. package/dist/types/src/panels/IdentityPanel/IdentityPanel.js.map +1 -1
  65. package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.d.ts.map +1 -1
  66. package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.js +7 -2
  67. package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.js.map +1 -1
  68. package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts +6 -5
  69. package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts.map +1 -1
  70. package/dist/types/src/panels/IdentityPanel/identityMachine.d.ts +1 -1
  71. package/dist/types/src/panels/IdentityPanel/identityMachine.d.ts.map +1 -1
  72. package/dist/types/src/panels/IdentityPanel/identityMachine.js +2 -0
  73. package/dist/types/src/panels/IdentityPanel/identityMachine.js.map +1 -1
  74. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.d.ts +3 -5
  75. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.d.ts.map +1 -1
  76. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js +5 -3
  77. package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js.map +1 -1
  78. package/dist/types/src/panels/IdentityPanel/useAgentHandlers.d.ts +1 -1
  79. package/dist/types/src/panels/IdentityPanel/useAgentHandlers.d.ts.map +1 -1
  80. package/dist/types/src/panels/IdentityPanel/useAgentHandlers.js +10 -108
  81. package/dist/types/src/panels/IdentityPanel/useAgentHandlers.js.map +1 -1
  82. package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.d.ts +8 -0
  83. package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.d.ts.map +1 -0
  84. package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.js +84 -0
  85. package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.js.map +1 -0
  86. package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.d.ts +8 -0
  87. package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.d.ts.map +1 -0
  88. package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.js +119 -0
  89. package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.js.map +1 -0
  90. package/dist/types/src/panels/JoinPanel/JoinPanel.d.ts.map +1 -1
  91. package/dist/types/src/panels/JoinPanel/JoinPanel.js +24 -16
  92. package/dist/types/src/panels/JoinPanel/JoinPanel.js.map +1 -1
  93. package/dist/types/src/panels/JoinPanel/JoinPanel.stories.d.ts +3 -0
  94. package/dist/types/src/panels/JoinPanel/JoinPanel.stories.d.ts.map +1 -1
  95. package/dist/types/src/panels/JoinPanel/JoinPanel.stories.js +3 -2
  96. package/dist/types/src/panels/JoinPanel/JoinPanel.stories.js.map +1 -1
  97. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts +8 -4
  98. package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts.map +1 -1
  99. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -1
  100. package/dist/types/src/panels/JoinPanel/joinMachine.js +8 -0
  101. package/dist/types/src/panels/JoinPanel/joinMachine.js.map +1 -1
  102. package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.d.ts.map +1 -1
  103. package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.js +1 -3
  104. package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.js.map +1 -1
  105. package/dist/types/src/panels/JoinPanel/steps/IdentityInput.d.ts.map +1 -1
  106. package/dist/types/src/panels/JoinPanel/steps/IdentityInput.js +17 -7
  107. package/dist/types/src/panels/JoinPanel/steps/IdentityInput.js.map +1 -1
  108. package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.d.ts +3 -1
  109. package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.d.ts.map +1 -1
  110. package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.js +9 -6
  111. package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.js.map +1 -1
  112. package/dist/types/src/panels/JoinPanel/steps/InvitationInput.d.ts.map +1 -1
  113. package/dist/types/src/panels/JoinPanel/steps/InvitationInput.js +8 -2
  114. package/dist/types/src/panels/JoinPanel/steps/InvitationInput.js.map +1 -1
  115. package/dist/types/src/panels/Panels.stories.js +1 -1
  116. package/dist/types/src/panels/Panels.stories.js.map +1 -1
  117. package/dist/types/src/panels/SpacePanel/SpacePanel.js +1 -1
  118. package/dist/types/src/panels/SpacePanel/SpacePanel.js.map +1 -1
  119. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js +16 -16
  120. package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js.map +1 -1
  121. package/dist/types/src/panels/SpacePanel/SpacePanelProps.d.ts +4 -4
  122. package/dist/types/src/panels/SpacePanel/SpacePanelProps.d.ts.map +1 -1
  123. package/dist/types/src/playwright/invitations-manager.d.ts +2 -3
  124. package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
  125. package/dist/types/src/playwright/invitations-manager.js +8 -15
  126. package/dist/types/src/playwright/invitations-manager.js.map +1 -1
  127. package/dist/types/src/playwright/invitations.spec.js +40 -53
  128. package/dist/types/src/playwright/invitations.spec.js.map +1 -1
  129. package/dist/types/src/playwright/playwright.config.d.ts +2 -2
  130. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -1
  131. package/dist/types/src/playwright/playwright.config.js +12 -2
  132. package/dist/types/src/playwright/playwright.config.js.map +1 -1
  133. package/dist/types/src/steps/ConfirmReset.d.ts +1 -1
  134. package/dist/types/src/steps/ConfirmReset.d.ts.map +1 -1
  135. package/dist/types/src/steps/ConfirmReset.js +6 -2
  136. package/dist/types/src/steps/ConfirmReset.js.map +1 -1
  137. package/dist/types/src/stories/Invitations.e2e-stories.d.ts +1 -3
  138. package/dist/types/src/stories/Invitations.e2e-stories.d.ts.map +1 -1
  139. package/dist/types/src/stories/Invitations.e2e-stories.js +14 -6
  140. package/dist/types/src/stories/Invitations.e2e-stories.js.map +1 -1
  141. package/dist/types/src/testing/index.d.ts +0 -1
  142. package/dist/types/src/testing/index.d.ts.map +1 -1
  143. package/dist/types/src/testing/index.js +1 -1
  144. package/dist/types/src/testing/index.js.map +1 -1
  145. package/dist/types/src/testing/shell-manager.d.ts +1 -0
  146. package/dist/types/src/testing/shell-manager.d.ts.map +1 -1
  147. package/dist/types/src/testing/shell-manager.js +2 -7
  148. package/dist/types/src/testing/shell-manager.js.map +1 -1
  149. package/dist/types/src/translations/locales/en-US.d.ts +3 -0
  150. package/dist/types/src/translations/locales/en-US.d.ts.map +1 -1
  151. package/dist/types/src/translations/locales/en-US.js +6 -3
  152. package/dist/types/src/translations/locales/en-US.js.map +1 -1
  153. package/package.json +42 -29
  154. package/src/components/CompoundButton/CompoundButton.stories.tsx +1 -1
  155. package/src/components/DeviceList/DeviceList.tsx +2 -1
  156. package/src/components/DeviceList/DeviceListItem.tsx +8 -0
  157. package/src/components/DeviceList/DeviceListProps.ts +2 -0
  158. package/src/components/IdentityList/SpaceMemberList.stories.tsx +2 -3
  159. package/src/components/InvitationList/InvitationList.stories.tsx +2 -3
  160. package/src/components/InvitationList/InvitationListContainer.tsx +6 -3
  161. package/src/components/Panel/Panel.stories.tsx +1 -2
  162. package/src/components/Viewport/Viewport.stories.tsx +1 -1
  163. package/src/composites/Shell/Shell.tsx +16 -4
  164. package/src/composites/Shell/run-shell.tsx +1 -1
  165. package/src/panels/IdentityPanel/IdentityPanel.stories.tsx +7 -2
  166. package/src/panels/IdentityPanel/IdentityPanel.tsx +81 -47
  167. package/src/panels/IdentityPanel/IdentityPanelProps.ts +6 -4
  168. package/src/panels/IdentityPanel/identityMachine.ts +3 -1
  169. package/src/panels/IdentityPanel/steps/IdentityActionChooser.tsx +21 -10
  170. package/src/panels/IdentityPanel/useAgentHandlers.ts +9 -114
  171. package/src/panels/IdentityPanel/useEdgeAgentsHandlers.ts +96 -0
  172. package/src/panels/IdentityPanel/useKubeAgentHandlers.ts +128 -0
  173. package/src/panels/JoinPanel/JoinPanel.stories.tsx +3 -2
  174. package/src/panels/JoinPanel/JoinPanel.tsx +31 -9
  175. package/src/panels/JoinPanel/JoinPanelProps.ts +8 -4
  176. package/src/panels/JoinPanel/joinMachine.ts +9 -0
  177. package/src/panels/JoinPanel/steps/AdditionMethodChooser.tsx +0 -2
  178. package/src/panels/JoinPanel/steps/IdentityInput.tsx +22 -10
  179. package/src/panels/JoinPanel/steps/InvitationAuthenticator.tsx +29 -16
  180. package/src/panels/JoinPanel/steps/InvitationInput.tsx +9 -17
  181. package/src/panels/Panels.stories.tsx +1 -1
  182. package/src/panels/SpacePanel/SpacePanel.stories.tsx +2 -2
  183. package/src/panels/SpacePanel/SpacePanel.tsx +3 -3
  184. package/src/panels/SpacePanel/SpacePanelProps.ts +4 -4
  185. package/src/playwright/invitations-manager.ts +9 -13
  186. package/src/playwright/invitations.spec.ts +42 -54
  187. package/src/playwright/playwright.config.ts +13 -2
  188. package/src/steps/ConfirmReset.tsx +13 -5
  189. package/src/stories/Invitations.e2e-stories.tsx +17 -10
  190. package/src/testing/index.ts +2 -1
  191. package/src/testing/shell-manager.ts +4 -9
  192. package/src/translations/locales/en-US.ts +6 -3
@@ -0,0 +1,128 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { useCallback, useEffect, useState } from 'react';
6
+
7
+ import { type CancellableInvitation } from '@dxos/client-protocol';
8
+ import { invariant } from '@dxos/invariant';
9
+ import { log } from '@dxos/log';
10
+ import { useClient, useAgentHostingClient } from '@dxos/react-client';
11
+ import { type Identity } from '@dxos/react-client/halo';
12
+ import { Invitation, InvitationEncoder } from '@dxos/react-client/invitations';
13
+
14
+ import { type AgentFormProps } from '../../components';
15
+
16
+ export const useKubeAgentHandlers = ({
17
+ invitations,
18
+ identity,
19
+ }: {
20
+ invitations: CancellableInvitation[];
21
+ identity: Identity | null;
22
+ }): AgentFormProps => {
23
+ const [validationMessage, setValidationMessage] = useState('');
24
+ const [agentStatus, setAgentStatus] = useState<AgentFormProps['agentStatus']>('getting');
25
+ const agentHostingProviderClient = useAgentHostingClient();
26
+ const client = useClient();
27
+
28
+ const updateAgentStatus = async () => {
29
+ // TODO(nf): if agent exists, subscribe to updates instead of oneshot status
30
+ if (agentHostingProviderClient) {
31
+ setAgentStatus('getting');
32
+ try {
33
+ const agentId = await agentHostingProviderClient?.getAgent(identity?.identityKey.truncate() ?? 'never');
34
+ if (agentId) {
35
+ setAgentStatus('created');
36
+ } else {
37
+ setAgentStatus('creatable');
38
+ }
39
+ } catch (err: any) {
40
+ setAgentStatus('error');
41
+ setValidationMessage(`Couldn’t check agent status: ${err.message}`);
42
+ }
43
+ } else {
44
+ setAgentStatus('error');
45
+ setValidationMessage('No agent provider configured.');
46
+ }
47
+ };
48
+
49
+ const createAgent = async (invitationCode: string) => {
50
+ invariant(identity, 'Identity not found');
51
+ if (agentHostingProviderClient) {
52
+ setAgentStatus('creating');
53
+ setValidationMessage('');
54
+ try {
55
+ const agentId = await agentHostingProviderClient?.createAgent(invitationCode, identity.identityKey.truncate());
56
+ if (agentId) {
57
+ setAgentStatus('created');
58
+ } else {
59
+ setAgentStatus('creatable');
60
+ setValidationMessage('Error creating agent.');
61
+ }
62
+ } catch (err: any) {
63
+ setValidationMessage(`Error creating agent: ${err.message}`);
64
+ return updateAgentStatus();
65
+ }
66
+ } else {
67
+ setAgentStatus('error');
68
+ setValidationMessage('No agent provider configured.');
69
+ }
70
+ };
71
+
72
+ const destroyAgent = async () => {
73
+ invariant(identity, 'Identity not found');
74
+ if (agentHostingProviderClient) {
75
+ setAgentStatus('destroying');
76
+ setValidationMessage('');
77
+ try {
78
+ await agentHostingProviderClient?.destroyAgent(identity.identityKey.truncate());
79
+ setAgentStatus('creatable');
80
+ } catch (err: any) {
81
+ setValidationMessage(`Error destroying agent: ${err.message}`);
82
+ return updateAgentStatus();
83
+ }
84
+ } else {
85
+ setAgentStatus('error');
86
+ setValidationMessage('No agent provider configured.');
87
+ }
88
+ };
89
+
90
+ useEffect(() => {
91
+ void updateAgentStatus();
92
+ }, []);
93
+
94
+ const handleAgentCreate = useCallback(async (invitation: Invitation) => {
95
+ const invitationCode = InvitationEncoder.encode(invitation);
96
+ if (invitation.state === Invitation.State.CONNECTING) {
97
+ log.info(JSON.stringify({ invitationCode, authCode: invitation.authCode }));
98
+ return createAgent(invitationCode);
99
+ }
100
+ }, []);
101
+
102
+ const onAgentCreate = async () => {
103
+ invitations.forEach((invitation) => invitation.cancel());
104
+
105
+ // TODO(nf): do this work in the hosting provider client?
106
+ const invitation = client.halo.share({
107
+ type: Invitation.Type.INTERACTIVE,
108
+ authMethod: Invitation.AuthMethod.NONE,
109
+ multiUse: true,
110
+ });
111
+
112
+ invitation.subscribe(handleAgentCreate);
113
+ };
114
+
115
+ const onAgentRefresh = async () => {
116
+ setValidationMessage('');
117
+ await updateAgentStatus();
118
+ };
119
+
120
+ return {
121
+ onAgentCreate,
122
+ onAgentDestroy: destroyAgent,
123
+ onAgentRefresh,
124
+ validationMessage,
125
+ agentStatus,
126
+ agentHostingEnabled: !!agentHostingProviderClient,
127
+ };
128
+ };
@@ -13,6 +13,7 @@ import { type JoinPanelImplProps } from './JoinPanelProps';
13
13
  import { IdentityInputImpl } from './steps';
14
14
  import { StorybookDialog } from '../../components/StorybookDialog';
15
15
  import { ConfirmResetImpl } from '../../steps';
16
+ import { osTranslations as translations } from '../../translations';
16
17
 
17
18
  const noOpProps: JoinPanelImplProps = {
18
19
  titleId: 'storybookJoinPanel__title',
@@ -29,10 +30,10 @@ const JoinDialog = (args: Partial<JoinPanelImplProps>) => (
29
30
  );
30
31
 
31
32
  export default {
32
- title: 'react-shell/JoinPanel',
33
+ title: 'sdk/shell/JoinPanel',
33
34
  component: JoinDialog,
34
35
  decorators: [withTheme],
35
- parameters: { chromatic: { disableSnapshot: false } },
36
+ parameters: { translations, chromatic: { disableSnapshot: false } },
36
37
  };
37
38
 
38
39
  export const AdditionMethodChooser = () => <JoinDialog mode='halo-only' activeView='addition method chooser' />;
@@ -7,7 +7,7 @@ import React, { useCallback, useEffect, useMemo } from 'react';
7
7
  import { log } from '@dxos/log';
8
8
  import { useClient, useMulticastObservable } from '@dxos/react-client';
9
9
  import { useIdentity } from '@dxos/react-client/halo';
10
- import { DensityProvider, useId, useThemeContext } from '@dxos/react-ui';
10
+ import { useId, useThemeContext } from '@dxos/react-ui';
11
11
 
12
12
  import { JoinHeading } from './JoinHeading';
13
13
  import { type JoinPanelImplProps, type JoinPanelProps } from './JoinPanelProps';
@@ -16,7 +16,6 @@ import {
16
16
  AdditionMethodChooser,
17
17
  IdentityAdded,
18
18
  IdentityInput,
19
- InvitationAccepted,
20
19
  InvitationAuthenticator,
21
20
  InvitationInput,
22
21
  InvitationRescuer,
@@ -35,11 +34,12 @@ export const JoinPanelImpl = (props: JoinPanelImplProps) => {
35
34
  unredeemedCodes,
36
35
  invitationIds,
37
36
  invitationStates,
37
+ invitationAuthMethods,
38
38
  succeededKeys,
39
39
  failReasons,
40
40
  onExit,
41
41
  onHaloDone,
42
- onSpaceDone,
42
+ // onSpaceDone,
43
43
  exitActionParent,
44
44
  doneActionParent,
45
45
  onHaloInvitationCancel,
@@ -52,7 +52,7 @@ export const JoinPanelImpl = (props: JoinPanelImplProps) => {
52
52
  ConfirmReset: ConfirmResetComponent = ConfirmReset,
53
53
  } = props;
54
54
  return (
55
- <DensityProvider density='fine'>
55
+ <>
56
56
  {mode !== 'halo-only' && <JoinHeading {...{ titleId, mode, onExit, exitActionParent }} />}
57
57
  <Viewport.Root focusManaged activeView={activeView}>
58
58
  <Viewport.Views>
@@ -105,13 +105,14 @@ export const JoinPanelImpl = (props: JoinPanelImplProps) => {
105
105
  send={send}
106
106
  Kind='Halo'
107
107
  invitationId={invitationIds?.Halo}
108
+ authMethod={invitationAuthMethods?.Halo}
108
109
  active={activeView === 'halo invitation authenticator'}
109
110
  onInvitationCancel={onHaloInvitationCancel}
110
111
  onInvitationAuthenticate={onHaloInvitationAuthenticate}
111
112
  {...(failed.has('Halo') && { failed: true })}
112
113
  />
113
114
  </Viewport.View>
114
- <Viewport.View classNames={stepStyles} id='halo invitation accepted'>
115
+ {/* <Viewport.View classNames={stepStyles} id='halo invitation accepted'>
115
116
  <InvitationAccepted
116
117
  {...{
117
118
  send,
@@ -121,7 +122,7 @@ export const JoinPanelImpl = (props: JoinPanelImplProps) => {
121
122
  onDone: onHaloDone,
122
123
  }}
123
124
  />
124
- </Viewport.View>
125
+ </Viewport.View> */}
125
126
  <Viewport.View classNames={stepStyles} id='identity added'>
126
127
  <IdentityAdded
127
128
  {...{ send, mode, active: activeView === 'identity added', doneActionParent, onDone: onHaloDone }}
@@ -153,13 +154,14 @@ export const JoinPanelImpl = (props: JoinPanelImplProps) => {
153
154
  send={send}
154
155
  Kind='Space'
155
156
  invitationId={invitationIds?.Space}
157
+ authMethod={invitationAuthMethods?.Space}
156
158
  active={activeView === 'space invitation authenticator'}
157
159
  onInvitationCancel={onSpaceInvitationCancel}
158
160
  onInvitationAuthenticate={onSpaceInvitationAuthenticate}
159
161
  {...(failed.has('Space') && { failed: true })}
160
162
  />
161
163
  </Viewport.View>
162
- <Viewport.View classNames={stepStyles} id='space invitation accepted'>
164
+ {/* <Viewport.View classNames={stepStyles} id='space invitation accepted'>
163
165
  <InvitationAccepted
164
166
  {...{
165
167
  send,
@@ -169,10 +171,10 @@ export const JoinPanelImpl = (props: JoinPanelImplProps) => {
169
171
  onDone: onSpaceDone,
170
172
  }}
171
173
  />
172
- </Viewport.View>
174
+ </Viewport.View> */}
173
175
  </Viewport.Views>
174
176
  </Viewport.Root>
175
- </DensityProvider>
177
+ </>
176
178
  );
177
179
  };
178
180
 
@@ -315,6 +317,17 @@ export const JoinPanel = ({
315
317
  }
316
318
  }, [joinState]);
317
319
 
320
+ useEffect(() => {
321
+ switch (activeView) {
322
+ case 'halo invitation accepted':
323
+ onHaloDone();
324
+ break;
325
+ case 'space invitation accepted':
326
+ onSpaceDone();
327
+ break;
328
+ }
329
+ }, [activeView]);
330
+
318
331
  const failed = useMemo(() => {
319
332
  const result: JoinPanelImplProps['failed'] = new Set();
320
333
  switch (true) {
@@ -363,6 +376,14 @@ export const JoinPanel = ({
363
376
  [joinState],
364
377
  );
365
378
 
379
+ const invitationAuthMethods = useMemo(
380
+ () => ({
381
+ Halo: joinState.context.halo.invitationObservable?.get().authMethod,
382
+ Space: joinState.context.space.invitationObservable?.get().authMethod,
383
+ }),
384
+ [joinState],
385
+ );
386
+
366
387
  const invitationIds = useMemo(
367
388
  () => ({
368
389
  Halo: joinState.context.halo.invitationObservable?.get().invitationId,
@@ -418,6 +439,7 @@ export const JoinPanel = ({
418
439
  unredeemedCodes,
419
440
  invitationIds,
420
441
  invitationStates,
442
+ invitationAuthMethods,
421
443
  succeededKeys,
422
444
  identity,
423
445
  onExit,
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type cloneElement } from 'react';
5
+ import { type FC, type cloneElement } from 'react';
6
6
 
7
7
  import type { Identity } from '@dxos/react-client/halo';
8
8
  import type { Invitation, AuthenticatingInvitationObservable, InvitationResult } from '@dxos/react-client/invitations';
@@ -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;
@@ -55,6 +55,10 @@ export type JoinPanelImplProps = Pick<
55
55
  Halo: Invitation.State;
56
56
  Space: Invitation.State;
57
57
  }>;
58
+ invitationAuthMethods?: Partial<{
59
+ Halo: Invitation.AuthMethod;
60
+ Space: Invitation.AuthMethod;
61
+ }>;
58
62
  succeededKeys?: Partial<{
59
63
  Halo: Set<string>;
60
64
  Space: Set<string>;
@@ -71,8 +75,8 @@ export type JoinPanelImplProps = Pick<
71
75
  onSpaceInvitationAuthenticate?: (authCode: string) => Promise<void> | undefined;
72
76
  onConfirmResetStorage?: () => Promise<void>;
73
77
  onCancelResetStorage?: () => void;
74
- IdentityInput?: React.FC<IdentityInputProps>;
75
- ConfirmReset?: React.FC<ConfirmResetProps>;
78
+ IdentityInput?: FC<IdentityInputProps>;
79
+ ConfirmReset?: FC<ConfirmResetProps>;
76
80
  };
77
81
 
78
82
  export interface IdentityAction {
@@ -312,10 +312,16 @@ 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
  ],
318
323
  },
324
+ // TODO(wittjosiah): Remove.
319
325
  choosingIdentity: {
320
326
  initial: 'unknownAuthMethod',
321
327
  states: {
@@ -343,6 +349,7 @@ const joinMachine = createMachine<JoinMachineContext, JoinEvent>(
343
349
  deselectAuthMethod: { target: '.choosingAuthMethod', actions: 'log' },
344
350
  },
345
351
  },
352
+ // TODO(wittjosiah): Factor out to a machine handling recovery and device invitations.
346
353
  resettingIdentity: {},
347
354
  acceptingSpaceInvitation: acceptingInvitationTemplate('Space', '#join.finishingJoiningSpace'),
348
355
  finishingJoiningSpace: {
@@ -362,6 +369,8 @@ const joinMachine = createMachine<JoinMachineContext, JoinEvent>(
362
369
  noSelectedIdentity: ({ identity }, _event) => !identity,
363
370
  initiallyAcceptingHaloInvitation: ({ identity, initialDisposition }, _event) =>
364
371
  !identity && initialDisposition === 'accept-halo-invitation',
372
+ initiallyRecoveringIdentity: ({ identity, initialDisposition }, _event) =>
373
+ !identity && initialDisposition === 'recover-identity',
365
374
  hasHaloUnredeemedCode: ({ halo }, _event) => !!halo.unredeemedCode,
366
375
  noSpaceInvitation: ({ space }, _event) => !space.invitation && !space.unredeemedCode,
367
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
  };
@@ -4,7 +4,9 @@
4
4
 
5
5
  import React, { type ChangeEvent, useState } from 'react';
6
6
 
7
+ import { Invitation } from '@dxos/react-client/invitations';
7
8
  import { Input, useTranslation } from '@dxos/react-ui';
9
+ import { descriptionText } from '@dxos/react-ui-theme';
8
10
  import { hexToEmoji } from '@dxos/util';
9
11
 
10
12
  import { Actions, Action, Emoji, StepHeading, Label } from '../../../components';
@@ -14,6 +16,7 @@ const pinLength = 6;
14
16
 
15
17
  export interface InvitationAuthenticatorProps extends JoinStepProps {
16
18
  Kind: 'Space' | 'Halo';
19
+ authMethod?: Invitation.AuthMethod;
17
20
  failed?: boolean;
18
21
  pending?: boolean;
19
22
  invitationId?: string;
@@ -24,6 +27,7 @@ export interface InvitationAuthenticatorProps extends JoinStepProps {
24
27
  export const InvitationAuthenticator = ({
25
28
  failed,
26
29
  Kind,
30
+ authMethod,
27
31
  active,
28
32
  pending,
29
33
  invitationId,
@@ -51,22 +55,31 @@ export const InvitationAuthenticator = ({
51
55
  })}
52
56
  >
53
57
  <Input.Label asChild>
54
- <StepHeading>{t('auth code input label')}</StepHeading>
58
+ {authMethod === Invitation.AuthMethod.SHARED_SECRET ? (
59
+ <StepHeading>{t('auth code input label')}</StepHeading>
60
+ ) : (
61
+ <>
62
+ <StepHeading className={descriptionText}>{t('authenticating label')}</StepHeading>
63
+ <div role='none' className='grow' />
64
+ </>
65
+ )}
55
66
  </Input.Label>
56
- <Input.PinInput
57
- {...{
58
- disabled,
59
- length: pinLength,
60
- onChange,
61
- inputMode: 'numeric',
62
- autoComplete: 'off',
63
- pattern: '\\d*',
64
- 'data-autofocus': `connecting${Kind}Invitation inputting${Kind}VerificationCode authenticationFailing${Kind}VerificationCode authenticating${Kind}VerificationCode`,
65
- 'data-prevent-ios-autofocus': true,
66
- 'data-testid': `${invitationType}-auth-code-input`,
67
- 'data-1p-ignore': true,
68
- }}
69
- />
67
+ {authMethod === Invitation.AuthMethod.SHARED_SECRET && (
68
+ <Input.PinInput
69
+ {...{
70
+ disabled,
71
+ length: pinLength,
72
+ onChange,
73
+ inputMode: 'numeric',
74
+ autoComplete: 'off',
75
+ pattern: '\\d*',
76
+ 'data-autofocus': `connecting${Kind}Invitation inputting${Kind}VerificationCode authenticationFailing${Kind}VerificationCode authenticating${Kind}VerificationCode`,
77
+ 'data-prevent-ios-autofocus': true,
78
+ 'data-testid': `${invitationType}-auth-code-input`,
79
+ 'data-1p-ignore': true,
80
+ }}
81
+ />
82
+ )}
70
83
  {failed && (
71
84
  <Input.DescriptionAndValidation classNames='text-center'>
72
85
  <Input.Validation>{t('failed to authenticate message')}</Input.Validation>
@@ -74,7 +87,7 @@ export const InvitationAuthenticator = ({
74
87
  )}
75
88
  </Input.Root>
76
89
 
77
- {invitationId && (
90
+ {invitationId && authMethod === Invitation.AuthMethod.SHARED_SECRET && (
78
91
  <>
79
92
  <Label>{t('auth other device emoji message')}</Label>
80
93
  <div className='flex justify-center'>
@@ -78,25 +78,17 @@ export const InvitationInput = (props: InvitationInputProps) => {
78
78
  />
79
79
  </div>
80
80
  <Actions>
81
- {Kind === 'Halo' ? (
82
- <Action
83
- variant='ghost'
84
- disabled={disabled}
85
- onClick={() => send({ type: 'deselectAuthMethod' })}
86
- data-testid={`${Kind.toLowerCase()}-invitation-input-back`}
87
- >
88
- {t('back label')}
89
- </Action>
90
- ) : exitActionParent ? (
91
- cloneElement(exitActionParent, {}, exitAction)
92
- ) : doneActionParent ? (
93
- cloneElement(doneActionParent, {}, exitAction)
94
- ) : (
95
- exitAction
96
- )}
81
+ {/* TODO(wittjosiah): This disables returning to deprecated identity creation flow. */}
82
+ {Kind === 'Halo'
83
+ ? null
84
+ : exitActionParent
85
+ ? cloneElement(exitActionParent, {}, exitAction)
86
+ : doneActionParent
87
+ ? cloneElement(doneActionParent, {}, exitAction)
88
+ : exitAction}
97
89
  <Action
98
90
  variant='primary'
99
- disabled={disabled}
91
+ disabled={disabled || inputValue.trim().length === 0}
100
92
  onClick={handleNext}
101
93
  data-testid={`${Kind.toLowerCase()}-invitation-input-continue`}
102
94
  >
@@ -53,7 +53,7 @@ export const Default = (props: any) => {
53
53
  Default.parameters = { layout: 'fullscreen' };
54
54
 
55
55
  export default {
56
- title: '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: 'react-shell/SpacePanel',
31
+ title: 'sdk/shell/SpacePanel',
32
32
  component: SpacePanelImpl,
33
33
  decorators: [withTheme],
34
34
  parameters: { chromatic: { disableSnapshot: false } },
@@ -8,7 +8,7 @@ import React, { useEffect, useMemo } from 'react';
8
8
  import { log } from '@dxos/log';
9
9
  import { useInvitationStatus } from '@dxos/react-client/invitations';
10
10
  import type { CancellableInvitationObservable } from '@dxos/react-client/invitations';
11
- import { DensityProvider, useId, useTranslation } from '@dxos/react-ui';
11
+ import { useId, useTranslation } from '@dxos/react-ui';
12
12
 
13
13
  import { type SpacePanelHeadingProps, type SpacePanelImplProps, type SpacePanelProps } from './SpacePanelProps';
14
14
  import { useSpaceMachine } from './spaceMachine';
@@ -46,7 +46,7 @@ export const SpacePanelImpl = (props: SpacePanelImplProps) => {
46
46
  } = props;
47
47
 
48
48
  return (
49
- <DensityProvider density='fine'>
49
+ <>
50
50
  <SpacePanelHeading {...rest} {...{ titleId, space }} />
51
51
  <Viewport.Root activeView={activeView}>
52
52
  <Viewport.Views>
@@ -62,7 +62,7 @@ export const SpacePanelImpl = (props: SpacePanelImplProps) => {
62
62
  </Viewport.View>
63
63
  </Viewport.Views>
64
64
  </Viewport.Root>
65
- </DensityProvider>
65
+ </>
66
66
  );
67
67
  };
68
68
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type cloneElement } from 'react';
5
+ import { type FC, type cloneElement } from 'react';
6
6
  import { type SingleOrArray, type Event } from 'xstate';
7
7
 
8
8
  import { type Space } from '@dxos/react-client/echo';
@@ -23,9 +23,9 @@ export type SpacePanelImplProps = {
23
23
  authCode?: string;
24
24
  onDone?: () => void;
25
25
  doneActionParent?: Parameters<typeof cloneElement>[0];
26
- DoneAction?: React.FC;
27
- SpaceManager?: React.FC<SpaceManagerProps>;
28
- InvitationManager?: React.FC<InvitationManagerProps>;
26
+ DoneAction?: FC;
27
+ SpaceManager?: FC<SpaceManagerProps>;
28
+ InvitationManager?: FC<InvitationManagerProps>;
29
29
  };
30
30
 
31
31
  export type SpacePanelProps = Pick<SpacePanelImplProps, 'space'> &
@@ -2,14 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import type { Browser, ConsoleMessage } from '@playwright/test';
6
- import { expect } from 'chai';
7
- import waitForExpect from 'wait-for-expect';
5
+ import { expect, type Browser, type ConsoleMessage } from '@playwright/test';
8
6
 
9
7
  import { Trigger } from '@dxos/async';
10
8
  import { type Invitation } from '@dxos/react-client/invitations';
11
- import { ConnectionState } from '@dxos/react-client/mesh';
12
- import { setupPage } from '@dxos/test/playwright';
9
+ import { setupPage } from '@dxos/test-utils/playwright';
13
10
 
14
11
  import { ScopedShellManager } from '../testing';
15
12
 
@@ -34,12 +31,12 @@ export class InvitationsManager extends ScopedShellManager {
34
31
  }
35
32
 
36
33
  const { page } = await setupPage(this._browser, {
37
- url: storybookUrl('invitations--default'),
38
- waitFor: (page) => page.getByTestId('invitations.identity-header').first().isVisible(),
34
+ url: storybookUrl('sdk-shell-invitations--default'),
39
35
  });
40
36
 
41
37
  this.page = page;
42
38
  this.page.on('console', (message) => this._onConsoleMessage(message));
39
+ await this.page.getByTestId('invitations.identity-header').first().waitFor({ state: 'visible' });
43
40
  this._initialized = true;
44
41
  }
45
42
 
@@ -58,9 +55,9 @@ export class InvitationsManager extends ScopedShellManager {
58
55
 
59
56
  try {
60
57
  await selector.waitFor({ timeout: 500 });
61
- return ConnectionState.OFFLINE;
58
+ return 0;
62
59
  } catch {
63
- return ConnectionState.ONLINE;
60
+ return 1;
64
61
  }
65
62
  }
66
63
 
@@ -119,9 +116,7 @@ export class InvitationsManager extends ScopedShellManager {
119
116
  const createIdentity = this.peer(id).getByTestId('invitations.create-identity');
120
117
  // TODO(wittjosiah): Clicking on buttons wrapped in tooltips is flaky in webkit playwright.
121
118
  await createIdentity.click();
122
- await waitForExpect(async () => {
123
- expect(await createIdentity.isDisabled()).to.be.true;
124
- });
119
+ await expect(createIdentity).toBeDisabled();
125
120
  }
126
121
 
127
122
  async createSpace(id: number) {
@@ -148,7 +143,8 @@ export class InvitationsManager extends ScopedShellManager {
148
143
  },
149
144
  { id, type, options },
150
145
  );
151
- return this._invitationCode.wait();
146
+
147
+ return this._invitationCode.wait({ timeout: 1_000 });
152
148
  }
153
149
 
154
150
  async acceptInvitation(id: number, type: 'device' | 'space', invitation: string) {