@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.
- package/dist/bundle/shell.mjs +16256 -15872
- package/dist/bundle/shell.mjs.map +1 -1
- package/dist/bundle/shell.umd.js +146 -108
- package/dist/bundle/shell.umd.js.map +1 -1
- package/dist/bundle/style.css +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react.mjs +428 -229
- package/dist/lib/browser/react.mjs.map +4 -4
- package/dist/lib/browser/testing/index.mjs +3 -46
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/chunk-Q7SFCCGT.cjs +33 -0
- package/dist/lib/node/chunk-Q7SFCCGT.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -0
- package/dist/lib/node/react.cjs +4763 -0
- package/dist/lib/node/react.cjs.map +7 -0
- package/dist/lib/node/react.css +7 -0
- package/dist/lib/node/react.css.map +7 -0
- package/dist/lib/node/testing/index.cjs +181 -0
- package/dist/lib/node/testing/index.cjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/react.css +7 -0
- package/dist/lib/node-esm/react.css.map +7 -0
- package/dist/lib/node-esm/react.mjs +4809 -0
- package/dist/lib/node-esm/react.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +161 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/components/CompoundButton/CompoundButton.stories.js +1 -1
- package/dist/types/src/components/CompoundButton/CompoundButton.stories.js.map +1 -1
- package/dist/types/src/components/DeviceList/DeviceList.d.ts +1 -1
- package/dist/types/src/components/DeviceList/DeviceList.d.ts.map +1 -1
- package/dist/types/src/components/DeviceList/DeviceList.js +2 -2
- package/dist/types/src/components/DeviceList/DeviceList.js.map +1 -1
- package/dist/types/src/components/DeviceList/DeviceListItem.d.ts.map +1 -1
- package/dist/types/src/components/DeviceList/DeviceListItem.js +4 -1
- package/dist/types/src/components/DeviceList/DeviceListItem.js.map +1 -1
- package/dist/types/src/components/DeviceList/DeviceListProps.d.ts +2 -0
- package/dist/types/src/components/DeviceList/DeviceListProps.d.ts.map +1 -1
- package/dist/types/src/components/IdentityList/SpaceMemberList.stories.d.ts +0 -3
- package/dist/types/src/components/IdentityList/SpaceMemberList.stories.d.ts.map +1 -1
- package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js +3 -4
- package/dist/types/src/components/IdentityList/SpaceMemberList.stories.js.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationList.stories.d.ts +0 -3
- package/dist/types/src/components/InvitationList/InvitationList.stories.d.ts.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationList.stories.js +11 -12
- package/dist/types/src/components/InvitationList/InvitationList.stories.js.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationListContainer.js +2 -2
- package/dist/types/src/components/InvitationList/InvitationListContainer.js.map +1 -1
- package/dist/types/src/components/Panel/Panel.stories.d.ts +0 -3
- package/dist/types/src/components/Panel/Panel.stories.d.ts.map +1 -1
- package/dist/types/src/components/Panel/Panel.stories.js +1 -2
- package/dist/types/src/components/Panel/Panel.stories.js.map +1 -1
- package/dist/types/src/components/Viewport/Viewport.stories.js +1 -1
- package/dist/types/src/components/Viewport/Viewport.stories.js.map +1 -1
- package/dist/types/src/composites/Shell/Shell.d.ts.map +1 -1
- package/dist/types/src/composites/Shell/Shell.js +14 -3
- package/dist/types/src/composites/Shell/Shell.js.map +1 -1
- package/dist/types/src/composites/Shell/run-shell.js +1 -1
- package/dist/types/src/composites/Shell/run-shell.js.map +1 -1
- package/dist/types/src/panels/IdentityPanel/IdentityPanel.d.ts.map +1 -1
- package/dist/types/src/panels/IdentityPanel/IdentityPanel.js +44 -25
- package/dist/types/src/panels/IdentityPanel/IdentityPanel.js.map +1 -1
- package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.d.ts.map +1 -1
- package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.js +7 -2
- package/dist/types/src/panels/IdentityPanel/IdentityPanel.stories.js.map +1 -1
- package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts +6 -5
- package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts.map +1 -1
- package/dist/types/src/panels/IdentityPanel/identityMachine.d.ts +1 -1
- package/dist/types/src/panels/IdentityPanel/identityMachine.d.ts.map +1 -1
- package/dist/types/src/panels/IdentityPanel/identityMachine.js +2 -0
- package/dist/types/src/panels/IdentityPanel/identityMachine.js.map +1 -1
- package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.d.ts +3 -5
- package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.d.ts.map +1 -1
- package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js +5 -3
- package/dist/types/src/panels/IdentityPanel/steps/IdentityActionChooser.js.map +1 -1
- package/dist/types/src/panels/IdentityPanel/useAgentHandlers.d.ts +1 -1
- package/dist/types/src/panels/IdentityPanel/useAgentHandlers.d.ts.map +1 -1
- package/dist/types/src/panels/IdentityPanel/useAgentHandlers.js +10 -108
- package/dist/types/src/panels/IdentityPanel/useAgentHandlers.js.map +1 -1
- package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.d.ts +8 -0
- package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.d.ts.map +1 -0
- package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.js +84 -0
- package/dist/types/src/panels/IdentityPanel/useEdgeAgentsHandlers.js.map +1 -0
- package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.d.ts +8 -0
- package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.d.ts.map +1 -0
- package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.js +119 -0
- package/dist/types/src/panels/IdentityPanel/useKubeAgentHandlers.js.map +1 -0
- package/dist/types/src/panels/JoinPanel/JoinPanel.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/JoinPanel.js +24 -16
- package/dist/types/src/panels/JoinPanel/JoinPanel.js.map +1 -1
- package/dist/types/src/panels/JoinPanel/JoinPanel.stories.d.ts +3 -0
- package/dist/types/src/panels/JoinPanel/JoinPanel.stories.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/JoinPanel.stories.js +3 -2
- package/dist/types/src/panels/JoinPanel/JoinPanel.stories.js.map +1 -1
- package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts +8 -4
- package/dist/types/src/panels/JoinPanel/JoinPanelProps.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/joinMachine.js +8 -0
- package/dist/types/src/panels/JoinPanel/joinMachine.js.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.js +1 -3
- package/dist/types/src/panels/JoinPanel/steps/AdditionMethodChooser.js.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/IdentityInput.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/IdentityInput.js +17 -7
- package/dist/types/src/panels/JoinPanel/steps/IdentityInput.js.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.d.ts +3 -1
- package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.js +9 -6
- package/dist/types/src/panels/JoinPanel/steps/InvitationAuthenticator.js.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/InvitationInput.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/steps/InvitationInput.js +8 -2
- package/dist/types/src/panels/JoinPanel/steps/InvitationInput.js.map +1 -1
- package/dist/types/src/panels/Panels.stories.js +1 -1
- package/dist/types/src/panels/Panels.stories.js.map +1 -1
- package/dist/types/src/panels/SpacePanel/SpacePanel.js +1 -1
- package/dist/types/src/panels/SpacePanel/SpacePanel.js.map +1 -1
- package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js +16 -16
- package/dist/types/src/panels/SpacePanel/SpacePanel.stories.js.map +1 -1
- package/dist/types/src/panels/SpacePanel/SpacePanelProps.d.ts +4 -4
- package/dist/types/src/panels/SpacePanel/SpacePanelProps.d.ts.map +1 -1
- package/dist/types/src/playwright/invitations-manager.d.ts +2 -3
- package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/playwright/invitations-manager.js +8 -15
- package/dist/types/src/playwright/invitations-manager.js.map +1 -1
- package/dist/types/src/playwright/invitations.spec.js +40 -53
- package/dist/types/src/playwright/invitations.spec.js.map +1 -1
- package/dist/types/src/playwright/playwright.config.d.ts +2 -2
- package/dist/types/src/playwright/playwright.config.d.ts.map +1 -1
- package/dist/types/src/playwright/playwright.config.js +12 -2
- package/dist/types/src/playwright/playwright.config.js.map +1 -1
- package/dist/types/src/steps/ConfirmReset.d.ts +1 -1
- package/dist/types/src/steps/ConfirmReset.d.ts.map +1 -1
- package/dist/types/src/steps/ConfirmReset.js +6 -2
- package/dist/types/src/steps/ConfirmReset.js.map +1 -1
- package/dist/types/src/stories/Invitations.e2e-stories.d.ts +1 -3
- package/dist/types/src/stories/Invitations.e2e-stories.d.ts.map +1 -1
- package/dist/types/src/stories/Invitations.e2e-stories.js +14 -6
- package/dist/types/src/stories/Invitations.e2e-stories.js.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -1
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/index.js +1 -1
- package/dist/types/src/testing/index.js.map +1 -1
- package/dist/types/src/testing/shell-manager.d.ts +1 -0
- package/dist/types/src/testing/shell-manager.d.ts.map +1 -1
- package/dist/types/src/testing/shell-manager.js +2 -7
- package/dist/types/src/testing/shell-manager.js.map +1 -1
- package/dist/types/src/translations/locales/en-US.d.ts +3 -0
- package/dist/types/src/translations/locales/en-US.d.ts.map +1 -1
- package/dist/types/src/translations/locales/en-US.js +6 -3
- package/dist/types/src/translations/locales/en-US.js.map +1 -1
- package/package.json +42 -29
- package/src/components/CompoundButton/CompoundButton.stories.tsx +1 -1
- package/src/components/DeviceList/DeviceList.tsx +2 -1
- package/src/components/DeviceList/DeviceListItem.tsx +8 -0
- package/src/components/DeviceList/DeviceListProps.ts +2 -0
- package/src/components/IdentityList/SpaceMemberList.stories.tsx +2 -3
- package/src/components/InvitationList/InvitationList.stories.tsx +2 -3
- package/src/components/InvitationList/InvitationListContainer.tsx +6 -3
- package/src/components/Panel/Panel.stories.tsx +1 -2
- package/src/components/Viewport/Viewport.stories.tsx +1 -1
- package/src/composites/Shell/Shell.tsx +16 -4
- package/src/composites/Shell/run-shell.tsx +1 -1
- package/src/panels/IdentityPanel/IdentityPanel.stories.tsx +7 -2
- package/src/panels/IdentityPanel/IdentityPanel.tsx +81 -47
- package/src/panels/IdentityPanel/IdentityPanelProps.ts +6 -4
- package/src/panels/IdentityPanel/identityMachine.ts +3 -1
- package/src/panels/IdentityPanel/steps/IdentityActionChooser.tsx +21 -10
- package/src/panels/IdentityPanel/useAgentHandlers.ts +9 -114
- package/src/panels/IdentityPanel/useEdgeAgentsHandlers.ts +96 -0
- package/src/panels/IdentityPanel/useKubeAgentHandlers.ts +128 -0
- package/src/panels/JoinPanel/JoinPanel.stories.tsx +3 -2
- package/src/panels/JoinPanel/JoinPanel.tsx +31 -9
- package/src/panels/JoinPanel/JoinPanelProps.ts +8 -4
- package/src/panels/JoinPanel/joinMachine.ts +9 -0
- package/src/panels/JoinPanel/steps/AdditionMethodChooser.tsx +0 -2
- package/src/panels/JoinPanel/steps/IdentityInput.tsx +22 -10
- package/src/panels/JoinPanel/steps/InvitationAuthenticator.tsx +29 -16
- package/src/panels/JoinPanel/steps/InvitationInput.tsx +9 -17
- package/src/panels/Panels.stories.tsx +1 -1
- package/src/panels/SpacePanel/SpacePanel.stories.tsx +2 -2
- package/src/panels/SpacePanel/SpacePanel.tsx +3 -3
- package/src/panels/SpacePanel/SpacePanelProps.ts +4 -4
- package/src/playwright/invitations-manager.ts +9 -13
- package/src/playwright/invitations.spec.ts +42 -54
- package/src/playwright/playwright.config.ts +13 -2
- package/src/steps/ConfirmReset.tsx +13 -5
- package/src/stories/Invitations.e2e-stories.tsx +17 -10
- package/src/testing/index.ts +2 -1
- package/src/testing/shell-manager.ts +4 -9
- package/src/translations/locales/en-US.ts +6 -3
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Key, Plugs, PlugsConnected } from '@phosphor-icons/react';
|
|
5
|
+
import { FirstAidKit, Key, Plugs, PlugsConnected } from '@phosphor-icons/react';
|
|
6
6
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { generateName } from '@dxos/display-name';
|
|
9
|
+
import { invariant } from '@dxos/invariant';
|
|
9
10
|
import { log } from '@dxos/log';
|
|
10
11
|
import { useClient } from '@dxos/react-client';
|
|
11
12
|
import { type Identity, useIdentity, useDevices, useHaloInvitations } from '@dxos/react-client/halo';
|
|
12
13
|
import { useInvitationStatus } from '@dxos/react-client/invitations';
|
|
13
14
|
import { type CancellableInvitationObservable } from '@dxos/react-client/invitations';
|
|
14
15
|
import { useNetworkStatus, ConnectionState } from '@dxos/react-client/mesh';
|
|
15
|
-
import { Avatar,
|
|
16
|
+
import { Avatar, Input, Toolbar, Tooltip, useId, useTranslation } from '@dxos/react-ui';
|
|
16
17
|
import { getSize } from '@dxos/react-ui-theme';
|
|
17
18
|
import { hexToEmoji, hexToHue, keyToFallback } from '@dxos/util';
|
|
18
19
|
|
|
@@ -51,6 +52,7 @@ const IdentityHeading = ({
|
|
|
51
52
|
connectionState,
|
|
52
53
|
onChangeConnectionState,
|
|
53
54
|
}: IdentityPanelHeadingProps) => {
|
|
55
|
+
const client = useClient();
|
|
54
56
|
const fallbackValue = keyToFallback(identity.identityKey);
|
|
55
57
|
const { t } = useTranslation('os');
|
|
56
58
|
const [displayName, setDisplayName] = useState(identity.profile?.displayName ?? '');
|
|
@@ -58,7 +60,7 @@ const IdentityHeading = ({
|
|
|
58
60
|
const [hue, setHueDirectly] = useState<string>(getHueValue(identity));
|
|
59
61
|
const { textValue, setTextValue } = useClipboardContext();
|
|
60
62
|
const identityHex = identity.identityKey.toHex();
|
|
61
|
-
const
|
|
63
|
+
const publicKeyCopied = textValue === identityHex;
|
|
62
64
|
|
|
63
65
|
const setEmoji = (nextEmoji: string) => {
|
|
64
66
|
setEmojiDirectly(nextEmoji);
|
|
@@ -70,9 +72,15 @@ const IdentityHeading = ({
|
|
|
70
72
|
void onUpdateProfile?.({ ...identity.profile, data: { ...identity.profile?.data, hue: nextHue } });
|
|
71
73
|
};
|
|
72
74
|
|
|
73
|
-
const
|
|
75
|
+
const handleRecoveryCode = async () => {
|
|
76
|
+
invariant(client.services.services.IdentityService, 'IdentityService not available');
|
|
77
|
+
// TODO(wittjosiah): This needs a proper api.
|
|
78
|
+
const { seedphrase } = await client.services.services.IdentityService.createRecoveryPhrase();
|
|
79
|
+
void setTextValue(seedphrase);
|
|
80
|
+
};
|
|
74
81
|
|
|
75
|
-
const
|
|
82
|
+
const isConnected = connectionState === ConnectionState.ONLINE;
|
|
83
|
+
const isProduction = client.config.values.runtime?.app?.env?.DX_ENVIRONMENT === 'production';
|
|
76
84
|
|
|
77
85
|
return (
|
|
78
86
|
<Heading titleId={titleId} title={title} corner={<CloseButton onDone={onDone} />}>
|
|
@@ -103,47 +111,61 @@ const IdentityHeading = ({
|
|
|
103
111
|
<Toolbar.Root classNames='flex justify-center items-center gap-1 pt-3'>
|
|
104
112
|
<EmojiPickerToolbarButton emoji={emoji} onChangeEmoji={setEmoji} classNames='bs-[--rail-action]' />
|
|
105
113
|
<HuePickerToolbarButton hue={hue} onChangeHue={setHue} classNames='bs-[--rail-action]' />
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<Tooltip.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
</Tooltip.Content>
|
|
142
|
-
</Tooltip.Portal>
|
|
143
|
-
</Tooltip.Root>
|
|
144
|
-
</Tooltip.Root>
|
|
145
|
-
</>
|
|
114
|
+
<Tooltip.Root>
|
|
115
|
+
<Tooltip.Trigger asChild>
|
|
116
|
+
<Toolbar.Button
|
|
117
|
+
classNames='bs-[--rail-action]'
|
|
118
|
+
data-testid='update-profile-form-copy-key'
|
|
119
|
+
onClick={() => setTextValue(identityHex)}
|
|
120
|
+
>
|
|
121
|
+
<span className='sr-only'>
|
|
122
|
+
{t(publicKeyCopied ? 'copy success label' : 'copy self public key label')}
|
|
123
|
+
</span>
|
|
124
|
+
<Key className={getSize(5)} />
|
|
125
|
+
</Toolbar.Button>
|
|
126
|
+
</Tooltip.Trigger>
|
|
127
|
+
<Tooltip.Portal>
|
|
128
|
+
<Tooltip.Content side='bottom' classNames='z-50'>
|
|
129
|
+
{t(publicKeyCopied ? 'copy success label' : 'copy self public key label')}
|
|
130
|
+
<Tooltip.Arrow />
|
|
131
|
+
</Tooltip.Content>
|
|
132
|
+
</Tooltip.Portal>
|
|
133
|
+
</Tooltip.Root>
|
|
134
|
+
{/* TODO(wittjosiah): Remove. This should have its own flow. */}
|
|
135
|
+
{!isProduction && (
|
|
136
|
+
<Tooltip.Root>
|
|
137
|
+
<Tooltip.Trigger asChild>
|
|
138
|
+
<Toolbar.Button classNames='bs-[--rail-action]' onClick={handleRecoveryCode}>
|
|
139
|
+
<FirstAidKit className={getSize(5)} />
|
|
140
|
+
</Toolbar.Button>
|
|
141
|
+
</Tooltip.Trigger>
|
|
142
|
+
<Tooltip.Portal>
|
|
143
|
+
<Tooltip.Content side='bottom' classNames='z-50'>
|
|
144
|
+
{t('create recovery code label')}
|
|
145
|
+
<Tooltip.Arrow />
|
|
146
|
+
</Tooltip.Content>
|
|
147
|
+
</Tooltip.Portal>
|
|
148
|
+
</Tooltip.Root>
|
|
146
149
|
)}
|
|
150
|
+
<Tooltip.Root>
|
|
151
|
+
<Tooltip.Trigger asChild>
|
|
152
|
+
<Toolbar.Button
|
|
153
|
+
classNames={['bs-[--rail-action]', !isConnected && 'text-error-500']}
|
|
154
|
+
onClick={() =>
|
|
155
|
+
onChangeConnectionState?.(isConnected ? ConnectionState.OFFLINE : ConnectionState.ONLINE)
|
|
156
|
+
}
|
|
157
|
+
>
|
|
158
|
+
<span className='sr-only'>{t(isConnected ? 'disconnect label' : 'connect label')}</span>
|
|
159
|
+
{isConnected ? <PlugsConnected className={getSize(5)} /> : <Plugs className={getSize(5)} />}
|
|
160
|
+
</Toolbar.Button>
|
|
161
|
+
</Tooltip.Trigger>
|
|
162
|
+
<Tooltip.Portal>
|
|
163
|
+
<Tooltip.Content side='bottom' classNames='z-50'>
|
|
164
|
+
{t(isConnected ? 'disconnect label' : 'connect label')}
|
|
165
|
+
<Tooltip.Arrow />
|
|
166
|
+
</Tooltip.Content>
|
|
167
|
+
</Tooltip.Portal>
|
|
168
|
+
</Tooltip.Root>
|
|
147
169
|
</Toolbar.Root>
|
|
148
170
|
</Avatar.Root>
|
|
149
171
|
</Heading>
|
|
@@ -157,6 +179,7 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
157
179
|
activeView,
|
|
158
180
|
onUpdateProfile,
|
|
159
181
|
onResetStorage,
|
|
182
|
+
onRecover,
|
|
160
183
|
onJoinNewIdentity,
|
|
161
184
|
IdentityActionChooser: IdentityActionChooserComponent = IdentityActionChooser,
|
|
162
185
|
InvitationManager: InvitationManagerComponent = InvitationManager,
|
|
@@ -178,7 +201,7 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
178
201
|
const onCancelReset = () => rest.send?.('unchooseAction');
|
|
179
202
|
|
|
180
203
|
return (
|
|
181
|
-
|
|
204
|
+
<>
|
|
182
205
|
<IdentityHeading
|
|
183
206
|
{...{ identity, titleId, title, onDone, onUpdateProfile, connectionState, onChangeConnectionState }}
|
|
184
207
|
/>
|
|
@@ -207,6 +230,15 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
207
230
|
onCancel={onCancelReset}
|
|
208
231
|
/>
|
|
209
232
|
</Viewport.View>
|
|
233
|
+
<Viewport.View classNames={viewStyles} id='confirm recover'>
|
|
234
|
+
<ConfirmReset
|
|
235
|
+
active={activeView === 'confirm recover'}
|
|
236
|
+
{...rest}
|
|
237
|
+
mode='recover'
|
|
238
|
+
onConfirm={onRecover}
|
|
239
|
+
onCancel={onCancelReset}
|
|
240
|
+
/>
|
|
241
|
+
</Viewport.View>
|
|
210
242
|
<Viewport.View classNames={viewStyles} id='confirm reset storage'>
|
|
211
243
|
<ConfirmReset
|
|
212
244
|
active={activeView === 'confirm reset storage'}
|
|
@@ -218,7 +250,7 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
218
250
|
</Viewport.View>
|
|
219
251
|
</Viewport.Views>
|
|
220
252
|
</Viewport.Root>
|
|
221
|
-
|
|
253
|
+
</>
|
|
222
254
|
);
|
|
223
255
|
};
|
|
224
256
|
|
|
@@ -270,6 +302,8 @@ export const IdentityPanel = ({
|
|
|
270
302
|
return 'device invitation manager';
|
|
271
303
|
case identityState.matches('confirmingResetStorage'):
|
|
272
304
|
return 'confirm reset storage';
|
|
305
|
+
case identityState.matches('confirmingRecover'):
|
|
306
|
+
return 'confirm recover';
|
|
273
307
|
case identityState.matches('confirmingJoinNewIdentity'):
|
|
274
308
|
return 'confirm join new identity';
|
|
275
309
|
default:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import type { cloneElement } from 'react';
|
|
5
|
+
import type { FC, cloneElement } from 'react';
|
|
6
6
|
import type { Event, SingleOrArray } from 'xstate';
|
|
7
7
|
|
|
8
8
|
import type { Device, Identity } from '@dxos/react-client/halo';
|
|
@@ -10,7 +10,7 @@ import type { InvitationStatus } from '@dxos/react-client/invitations';
|
|
|
10
10
|
import type { ConnectionState } from '@dxos/react-client/mesh';
|
|
11
11
|
|
|
12
12
|
import type { IdentityEvent } from './identityMachine';
|
|
13
|
-
import {
|
|
13
|
+
import type { AgentFormProps } from '../../components';
|
|
14
14
|
import type { InvitationManagerProps } from '../../steps';
|
|
15
15
|
|
|
16
16
|
export type IdentityPanelInitialDisposition = 'default' | 'manage-device-invitation';
|
|
@@ -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,14 +30,15 @@ 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;
|
|
35
37
|
onDone?: () => void;
|
|
36
38
|
doneActionParent?: Parameters<typeof cloneElement>[0];
|
|
37
39
|
invitationUrl?: string;
|
|
38
|
-
IdentityActionChooser?:
|
|
39
|
-
InvitationManager?:
|
|
40
|
+
IdentityActionChooser?: FC<IdentityPanelStepProps>;
|
|
41
|
+
InvitationManager?: FC<InvitationManagerProps>;
|
|
40
42
|
} & Partial<InvitationStatus> &
|
|
41
43
|
Partial<AgentFormProps>;
|
|
42
44
|
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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={
|
|
59
|
-
onClickJoinExisting={
|
|
60
|
-
|
|
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)} />}
|
|
@@ -2,127 +2,22 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
6
|
-
|
|
7
5
|
import { type CancellableInvitation } from '@dxos/client-protocol';
|
|
8
|
-
import {
|
|
9
|
-
import { log } from '@dxos/log';
|
|
10
|
-
import { useClient, useAgentHostingClient } from '@dxos/react-client';
|
|
6
|
+
import { useClient } from '@dxos/react-client';
|
|
11
7
|
import { type Identity } from '@dxos/react-client/halo';
|
|
12
|
-
import { Invitation, InvitationEncoder } from '@dxos/react-client/invitations';
|
|
13
8
|
|
|
9
|
+
import { useEdgeAgentHandlers } from './useEdgeAgentsHandlers';
|
|
10
|
+
import { useKubeAgentHandlers } from './useKubeAgentHandlers';
|
|
14
11
|
import { type AgentFormProps } from '../../components';
|
|
15
12
|
|
|
16
|
-
export const useAgentHandlers = ({
|
|
17
|
-
invitations,
|
|
18
|
-
identity,
|
|
19
|
-
}: {
|
|
13
|
+
export const useAgentHandlers = (params: {
|
|
20
14
|
invitations: CancellableInvitation[];
|
|
21
15
|
identity: Identity | null;
|
|
22
16
|
}): AgentFormProps => {
|
|
23
|
-
const [validationMessage, setValidationMessage] = useState('');
|
|
24
|
-
const [agentStatus, setAgentStatus] = useState<AgentFormProps['agentStatus']>('getting');
|
|
25
|
-
const agentHostingProviderClient = useAgentHostingClient();
|
|
26
17
|
const client = useClient();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
};
|
|
18
|
+
if (client.config.values?.runtime?.client?.edgeFeatures?.agents) {
|
|
19
|
+
return useEdgeAgentHandlers(params);
|
|
20
|
+
} else {
|
|
21
|
+
return useKubeAgentHandlers(params);
|
|
22
|
+
}
|
|
128
23
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type CancellableInvitation } from '@dxos/client-protocol';
|
|
8
|
+
import { invariant } from '@dxos/invariant';
|
|
9
|
+
import { QueryAgentStatusResponse } from '@dxos/protocols/proto/dxos/client/services';
|
|
10
|
+
import { useClient } from '@dxos/react-client';
|
|
11
|
+
import { type Identity } from '@dxos/react-client/halo';
|
|
12
|
+
|
|
13
|
+
import { type AgentFormProps } from '../../components';
|
|
14
|
+
|
|
15
|
+
export const useEdgeAgentHandlers = ({
|
|
16
|
+
identity,
|
|
17
|
+
}: {
|
|
18
|
+
invitations: CancellableInvitation[];
|
|
19
|
+
identity: Identity | null;
|
|
20
|
+
}): AgentFormProps => {
|
|
21
|
+
const [validationMessage, setValidationMessage] = useState('');
|
|
22
|
+
const [lastReceivedStatus, setLastReceivedStatus] = useState<QueryAgentStatusResponse.AgentStatus>(
|
|
23
|
+
QueryAgentStatusResponse.AgentStatus.UNKNOWN,
|
|
24
|
+
);
|
|
25
|
+
const [agentStatus, setAgentStatus] = useState<AgentFormProps['agentStatus']>('getting');
|
|
26
|
+
const client = useClient();
|
|
27
|
+
const agentHostingEnabled = Boolean(client.config.values.runtime?.client?.edgeFeatures?.agents);
|
|
28
|
+
|
|
29
|
+
const handleStatus = (status: QueryAgentStatusResponse.AgentStatus) => {
|
|
30
|
+
switch (status) {
|
|
31
|
+
case QueryAgentStatusResponse.AgentStatus.ACTIVE:
|
|
32
|
+
case QueryAgentStatusResponse.AgentStatus.INACTIVE:
|
|
33
|
+
setAgentStatus('created');
|
|
34
|
+
break;
|
|
35
|
+
case QueryAgentStatusResponse.AgentStatus.NOT_FOUND:
|
|
36
|
+
setAgentStatus('creatable');
|
|
37
|
+
break;
|
|
38
|
+
case QueryAgentStatusResponse.AgentStatus.UNKNOWN:
|
|
39
|
+
setAgentStatus('getting');
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const stream = client.services.services.EdgeAgentService?.queryAgentStatus();
|
|
46
|
+
stream?.subscribe(({ status }) => {
|
|
47
|
+
setLastReceivedStatus(status);
|
|
48
|
+
handleStatus(status);
|
|
49
|
+
});
|
|
50
|
+
return () => {
|
|
51
|
+
void stream?.close().catch(() => {});
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const onAgentCreate = async () => {
|
|
56
|
+
invariant(identity, 'Identity not found');
|
|
57
|
+
const service = client.services.services.EdgeAgentService;
|
|
58
|
+
if (!service) {
|
|
59
|
+
setAgentStatus('error');
|
|
60
|
+
setValidationMessage('Agent service not initialized.');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!agentHostingEnabled) {
|
|
64
|
+
setAgentStatus('error');
|
|
65
|
+
setValidationMessage('Edge agents are disabled in config.');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
setAgentStatus('creating');
|
|
69
|
+
setValidationMessage('');
|
|
70
|
+
try {
|
|
71
|
+
await service.createAgent();
|
|
72
|
+
setAgentStatus('created');
|
|
73
|
+
} catch (err: any) {
|
|
74
|
+
setAgentStatus('error');
|
|
75
|
+
setValidationMessage(`Error creating an agent: ${err.message}`);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const onAgentDestroy = async () => {
|
|
80
|
+
setValidationMessage('Agents are non-destructible.');
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const onAgentRefresh = async () => {
|
|
84
|
+
setValidationMessage('');
|
|
85
|
+
handleStatus(lastReceivedStatus);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
onAgentCreate,
|
|
90
|
+
onAgentDestroy,
|
|
91
|
+
onAgentRefresh,
|
|
92
|
+
validationMessage,
|
|
93
|
+
agentStatus,
|
|
94
|
+
agentHostingEnabled,
|
|
95
|
+
};
|
|
96
|
+
};
|