@dxos/shell 0.6.13 → 0.6.14-main.1366248
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 +15995 -15601
- 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 +432 -230
- 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 +4766 -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 +4812 -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 +51 -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 +7 -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 +89 -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 +92 -48
- package/src/panels/IdentityPanel/IdentityPanelProps.ts +7 -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 +103 -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
|
|
|
@@ -46,11 +47,13 @@ const IdentityHeading = ({
|
|
|
46
47
|
titleId,
|
|
47
48
|
title,
|
|
48
49
|
identity,
|
|
50
|
+
hideRecover,
|
|
49
51
|
onDone,
|
|
50
52
|
onUpdateProfile,
|
|
51
53
|
connectionState,
|
|
52
54
|
onChangeConnectionState,
|
|
53
55
|
}: IdentityPanelHeadingProps) => {
|
|
56
|
+
const client = useClient();
|
|
54
57
|
const fallbackValue = keyToFallback(identity.identityKey);
|
|
55
58
|
const { t } = useTranslation('os');
|
|
56
59
|
const [displayName, setDisplayName] = useState(identity.profile?.displayName ?? '');
|
|
@@ -58,7 +61,7 @@ const IdentityHeading = ({
|
|
|
58
61
|
const [hue, setHueDirectly] = useState<string>(getHueValue(identity));
|
|
59
62
|
const { textValue, setTextValue } = useClipboardContext();
|
|
60
63
|
const identityHex = identity.identityKey.toHex();
|
|
61
|
-
const
|
|
64
|
+
const publicKeyCopied = textValue === identityHex;
|
|
62
65
|
|
|
63
66
|
const setEmoji = (nextEmoji: string) => {
|
|
64
67
|
setEmojiDirectly(nextEmoji);
|
|
@@ -70,9 +73,14 @@ const IdentityHeading = ({
|
|
|
70
73
|
void onUpdateProfile?.({ ...identity.profile, data: { ...identity.profile?.data, hue: nextHue } });
|
|
71
74
|
};
|
|
72
75
|
|
|
73
|
-
const
|
|
76
|
+
const handleRecoveryCode = async () => {
|
|
77
|
+
invariant(client.services.services.IdentityService, 'IdentityService not available');
|
|
78
|
+
// TODO(wittjosiah): This needs a proper api.
|
|
79
|
+
const { seedphrase } = await client.services.services.IdentityService.createRecoveryPhrase();
|
|
80
|
+
void setTextValue(seedphrase);
|
|
81
|
+
};
|
|
74
82
|
|
|
75
|
-
const
|
|
83
|
+
const isConnected = connectionState === ConnectionState.ONLINE;
|
|
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
|
+
{!hideRecover && (
|
|
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,
|
|
@@ -176,11 +199,21 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
176
199
|
}, [activeView, t]);
|
|
177
200
|
|
|
178
201
|
const onCancelReset = () => rest.send?.('unchooseAction');
|
|
202
|
+
const hideRecover = rest.agentStatus !== 'created';
|
|
179
203
|
|
|
180
204
|
return (
|
|
181
|
-
|
|
205
|
+
<>
|
|
182
206
|
<IdentityHeading
|
|
183
|
-
{...{
|
|
207
|
+
{...{
|
|
208
|
+
identity,
|
|
209
|
+
titleId,
|
|
210
|
+
title,
|
|
211
|
+
hideRecover,
|
|
212
|
+
onDone,
|
|
213
|
+
onUpdateProfile,
|
|
214
|
+
connectionState,
|
|
215
|
+
onChangeConnectionState,
|
|
216
|
+
}}
|
|
184
217
|
/>
|
|
185
218
|
<Viewport.Root activeView={activeView}>
|
|
186
219
|
<Viewport.Views>
|
|
@@ -207,6 +240,15 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
207
240
|
onCancel={onCancelReset}
|
|
208
241
|
/>
|
|
209
242
|
</Viewport.View>
|
|
243
|
+
<Viewport.View classNames={viewStyles} id='confirm recover'>
|
|
244
|
+
<ConfirmReset
|
|
245
|
+
active={activeView === 'confirm recover'}
|
|
246
|
+
{...rest}
|
|
247
|
+
mode='recover'
|
|
248
|
+
onConfirm={onRecover}
|
|
249
|
+
onCancel={onCancelReset}
|
|
250
|
+
/>
|
|
251
|
+
</Viewport.View>
|
|
210
252
|
<Viewport.View classNames={viewStyles} id='confirm reset storage'>
|
|
211
253
|
<ConfirmReset
|
|
212
254
|
active={activeView === 'confirm reset storage'}
|
|
@@ -218,7 +260,7 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
218
260
|
</Viewport.View>
|
|
219
261
|
</Viewport.Views>
|
|
220
262
|
</Viewport.Root>
|
|
221
|
-
|
|
263
|
+
</>
|
|
222
264
|
);
|
|
223
265
|
};
|
|
224
266
|
|
|
@@ -270,6 +312,8 @@ export const IdentityPanel = ({
|
|
|
270
312
|
return 'device invitation manager';
|
|
271
313
|
case identityState.matches('confirmingResetStorage'):
|
|
272
314
|
return 'confirm reset storage';
|
|
315
|
+
case identityState.matches('confirmingRecover'):
|
|
316
|
+
return 'confirm recover';
|
|
273
317
|
case identityState.matches('confirmingJoinNewIdentity'):
|
|
274
318
|
return 'confirm join new identity';
|
|
275
319
|
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
|
|
|
@@ -47,6 +49,7 @@ export type IdentityPanelHeadingProps = Pick<
|
|
|
47
49
|
'titleId' | 'identity' | 'onDone' | 'onUpdateProfile' | 'connectionState' | 'onChangeConnectionState'
|
|
48
50
|
> & {
|
|
49
51
|
title: string;
|
|
52
|
+
hideRecover?: boolean;
|
|
50
53
|
};
|
|
51
54
|
|
|
52
55
|
export type IdentityPanelStepProps = Pick<
|
|
@@ -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={agentProps.agentStatus === 'created' ? onClickRecover : undefined}
|
|
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,103 @@
|
|
|
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 { EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
11
|
+
import { useClient } from '@dxos/react-client';
|
|
12
|
+
import { type Identity } from '@dxos/react-client/halo';
|
|
13
|
+
|
|
14
|
+
import { type AgentFormProps } from '../../components';
|
|
15
|
+
|
|
16
|
+
export const useEdgeAgentHandlers = ({
|
|
17
|
+
identity,
|
|
18
|
+
}: {
|
|
19
|
+
invitations: CancellableInvitation[];
|
|
20
|
+
identity: Identity | null;
|
|
21
|
+
}): AgentFormProps => {
|
|
22
|
+
const [validationMessage, setValidationMessage] = useState('');
|
|
23
|
+
const [lastReceivedStatus, setLastReceivedStatus] = useState<QueryAgentStatusResponse.AgentStatus>(
|
|
24
|
+
QueryAgentStatusResponse.AgentStatus.UNKNOWN,
|
|
25
|
+
);
|
|
26
|
+
const [agentStatus, setAgentStatus] = useState<AgentFormProps['agentStatus']>('getting');
|
|
27
|
+
const client = useClient();
|
|
28
|
+
// TODO(wittjosiah): This should be based on HALO credentials.
|
|
29
|
+
const agentHostingEnabled = Boolean(client.config.values.runtime?.client?.edgeFeatures?.agents);
|
|
30
|
+
|
|
31
|
+
const handleStatus = (status: QueryAgentStatusResponse.AgentStatus) => {
|
|
32
|
+
switch (status) {
|
|
33
|
+
case QueryAgentStatusResponse.AgentStatus.ACTIVE:
|
|
34
|
+
case QueryAgentStatusResponse.AgentStatus.INACTIVE:
|
|
35
|
+
setAgentStatus('created');
|
|
36
|
+
break;
|
|
37
|
+
case QueryAgentStatusResponse.AgentStatus.NOT_FOUND:
|
|
38
|
+
setAgentStatus('creatable');
|
|
39
|
+
break;
|
|
40
|
+
case QueryAgentStatusResponse.AgentStatus.UNKNOWN:
|
|
41
|
+
setAgentStatus('getting');
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const stream = client.services.services.EdgeAgentService?.queryAgentStatus();
|
|
48
|
+
stream?.subscribe(({ status }) => {
|
|
49
|
+
setLastReceivedStatus(status);
|
|
50
|
+
handleStatus(status);
|
|
51
|
+
});
|
|
52
|
+
return () => {
|
|
53
|
+
void stream?.close().catch(() => {});
|
|
54
|
+
};
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
const onAgentCreate = async () => {
|
|
58
|
+
invariant(identity, 'Identity not found');
|
|
59
|
+
const service = client.services.services.EdgeAgentService;
|
|
60
|
+
if (!service) {
|
|
61
|
+
setAgentStatus('error');
|
|
62
|
+
setValidationMessage('Agent service not initialized.');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (!agentHostingEnabled) {
|
|
66
|
+
setAgentStatus('error');
|
|
67
|
+
setValidationMessage('Edge agents are disabled in config.');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
setAgentStatus('creating');
|
|
71
|
+
setValidationMessage('');
|
|
72
|
+
try {
|
|
73
|
+
await service.createAgent();
|
|
74
|
+
await Promise.all(
|
|
75
|
+
client.spaces
|
|
76
|
+
.get()
|
|
77
|
+
.map((space) => space?.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED)),
|
|
78
|
+
);
|
|
79
|
+
setAgentStatus('created');
|
|
80
|
+
} catch (err: any) {
|
|
81
|
+
setAgentStatus('error');
|
|
82
|
+
setValidationMessage(`Error creating an agent: ${err.message}`);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const onAgentDestroy = async () => {
|
|
87
|
+
setValidationMessage('Agents are non-destructible.');
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const onAgentRefresh = async () => {
|
|
91
|
+
setValidationMessage('');
|
|
92
|
+
handleStatus(lastReceivedStatus);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
onAgentCreate,
|
|
97
|
+
onAgentDestroy,
|
|
98
|
+
onAgentRefresh,
|
|
99
|
+
validationMessage,
|
|
100
|
+
agentStatus,
|
|
101
|
+
agentHostingEnabled,
|
|
102
|
+
};
|
|
103
|
+
};
|