@dxos/shell 0.6.13-staging.1e988a3 → 0.6.14-main.2b6a0f3
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 +12070 -15401
- package/dist/bundle/shell.mjs.map +1 -1
- package/dist/bundle/shell.umd.js +87 -94
- 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 +551 -453
- package/dist/lib/browser/react.mjs.map +4 -4
- package/dist/lib/browser/testing/index.mjs +2 -7
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- 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/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 +1 -2
- 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 +1 -2
- package/dist/types/src/components/InvitationList/InvitationList.stories.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 +4 -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.js +1 -1
- 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 +4 -4
- package/dist/types/src/panels/IdentityPanel/IdentityPanelProps.d.ts.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 +7 -3
- 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 +2 -0
- package/dist/types/src/panels/JoinPanel/joinMachine.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 +1 -1
- 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 +1 -1
- package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/playwright/invitations-manager.js +4 -10
- package/dist/types/src/playwright/invitations-manager.js.map +1 -1
- package/dist/types/src/playwright/invitations.spec.js +31 -32
- 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/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 +1 -0
- package/dist/types/src/translations/locales/en-US.d.ts.map +1 -1
- package/dist/types/src/translations/locales/en-US.js +4 -3
- package/dist/types/src/translations/locales/en-US.js.map +1 -1
- package/package.json +29 -27
- package/src/components/CompoundButton/CompoundButton.stories.tsx +1 -1
- package/src/components/IdentityList/SpaceMemberList.stories.tsx +1 -2
- package/src/components/InvitationList/InvitationList.stories.tsx +1 -2
- package/src/components/Panel/Panel.stories.tsx +1 -2
- package/src/components/Viewport/Viewport.stories.tsx +1 -1
- package/src/composites/Shell/Shell.tsx +4 -3
- package/src/composites/Shell/run-shell.tsx +1 -1
- package/src/panels/IdentityPanel/IdentityPanel.stories.tsx +7 -2
- package/src/panels/IdentityPanel/IdentityPanel.tsx +3 -3
- package/src/panels/IdentityPanel/IdentityPanelProps.ts +4 -4
- 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 +7 -3
- package/src/panels/JoinPanel/joinMachine.ts +2 -0
- 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 +1 -1
- package/src/panels/SpacePanel/SpacePanel.tsx +3 -3
- package/src/panels/SpacePanel/SpacePanelProps.ts +4 -4
- package/src/playwright/invitations-manager.ts +4 -8
- package/src/playwright/invitations.spec.ts +32 -33
- package/src/playwright/playwright.config.ts +13 -2
- package/src/testing/shell-manager.ts +4 -9
- package/src/translations/locales/en-US.ts +4 -3
|
@@ -13,10 +13,9 @@ import { InvitationList } from './InvitationList';
|
|
|
13
13
|
import { inviteWithState } from '../../testing';
|
|
14
14
|
|
|
15
15
|
export default {
|
|
16
|
-
title: 'react-shell/InvitationList',
|
|
16
|
+
title: 'sdk/react-shell/InvitationList',
|
|
17
17
|
component: InvitationList,
|
|
18
18
|
decorators: [withTheme, withLayout({ tooltips: true })],
|
|
19
|
-
actions: { argTypesRegex: '^on.*' },
|
|
20
19
|
parameters: { chromatic: { disableSnapshot: false } },
|
|
21
20
|
};
|
|
22
21
|
|
|
@@ -15,9 +15,8 @@ import { Label } from './Label';
|
|
|
15
15
|
import { StorybookDialog } from '../StorybookDialog';
|
|
16
16
|
|
|
17
17
|
export default {
|
|
18
|
-
title: 'react-shell/StorybookDialog',
|
|
18
|
+
title: 'sdk/react-shell/StorybookDialog',
|
|
19
19
|
component: StorybookDialog,
|
|
20
|
-
actions: { argTypesRegex: '^on.*' },
|
|
21
20
|
decorators: [withTheme],
|
|
22
21
|
};
|
|
23
22
|
|
|
@@ -55,7 +55,7 @@ const StorybookViewport = (props: StorybookViewportProps) => {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
export default {
|
|
58
|
-
title: 'react-shell/StorybookViewport',
|
|
58
|
+
title: 'sdk/react-shell/StorybookViewport',
|
|
59
59
|
component: StorybookViewport,
|
|
60
60
|
decorators: [withTheme],
|
|
61
61
|
parameters: { chromatic: { disableSnapshot: false } },
|
|
@@ -88,9 +88,9 @@ export const Shell = ({ runtime }: { runtime: ShellRuntime }) => {
|
|
|
88
88
|
}
|
|
89
89
|
initialInvitationCode={invitationCode}
|
|
90
90
|
onCancelResetStorage={() => runtime.setLayout({ layout: ShellLayout.IDENTITY })}
|
|
91
|
-
onDone={() => {
|
|
91
|
+
onDone={async () => {
|
|
92
92
|
blurActiveElement();
|
|
93
|
-
|
|
93
|
+
await runtime.setAppContext({ display: ShellDisplay.NONE });
|
|
94
94
|
runtime.setLayout({ layout: ShellLayout.DEFAULT });
|
|
95
95
|
}}
|
|
96
96
|
/>
|
|
@@ -110,7 +110,8 @@ export const Shell = ({ runtime }: { runtime: ShellRuntime }) => {
|
|
|
110
110
|
onJoinNewIdentity={async () => {
|
|
111
111
|
runtime.setLayout({ layout: ShellLayout.STATUS });
|
|
112
112
|
await client.reset();
|
|
113
|
-
|
|
113
|
+
// TODO(wittjosiah): Enter join flow without reloading.
|
|
114
|
+
return runtime.setAppContext({ display: ShellDisplay.NONE, reset: true, target: 'deviceInvitation' });
|
|
114
115
|
}}
|
|
115
116
|
onDone={async () => {
|
|
116
117
|
blurActiveElement();
|
|
@@ -27,7 +27,7 @@ export const runShell = async (config: Config = new Config()) => {
|
|
|
27
27
|
createRoot(document.getElementById('root')!).render(
|
|
28
28
|
<StrictMode>
|
|
29
29
|
<ThemeProvider tx={defaultTx} resourceExtensions={[osTranslations]}>
|
|
30
|
-
<ClientProvider config={config} services={services}>
|
|
30
|
+
<ClientProvider config={config} services={services} noBanner>
|
|
31
31
|
<ClipboardProvider>
|
|
32
32
|
<Tooltip.Provider>
|
|
33
33
|
<AgentHostingProvider>
|
|
@@ -37,9 +37,14 @@ const noOpProps: IdentityPanelImplProps = {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
export default {
|
|
40
|
-
title: 'react-shell/IdentityPanel',
|
|
40
|
+
title: 'sdk/react-shell/IdentityPanel',
|
|
41
41
|
decorators: [withTheme],
|
|
42
|
-
parameters: {
|
|
42
|
+
parameters: {
|
|
43
|
+
translations: [osTranslations],
|
|
44
|
+
chromatic: {
|
|
45
|
+
disableSnapshot: false,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
43
48
|
};
|
|
44
49
|
|
|
45
50
|
export const IdentityActionChooser = () => {
|
|
@@ -12,7 +12,7 @@ import { type Identity, useIdentity, useDevices, useHaloInvitations } from '@dxo
|
|
|
12
12
|
import { useInvitationStatus } from '@dxos/react-client/invitations';
|
|
13
13
|
import { type CancellableInvitationObservable } from '@dxos/react-client/invitations';
|
|
14
14
|
import { useNetworkStatus, ConnectionState } from '@dxos/react-client/mesh';
|
|
15
|
-
import { Avatar,
|
|
15
|
+
import { Avatar, Input, Toolbar, Tooltip, useId, useTranslation } from '@dxos/react-ui';
|
|
16
16
|
import { getSize } from '@dxos/react-ui-theme';
|
|
17
17
|
import { hexToEmoji, hexToHue, keyToFallback } from '@dxos/util';
|
|
18
18
|
|
|
@@ -178,7 +178,7 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
178
178
|
const onCancelReset = () => rest.send?.('unchooseAction');
|
|
179
179
|
|
|
180
180
|
return (
|
|
181
|
-
|
|
181
|
+
<>
|
|
182
182
|
<IdentityHeading
|
|
183
183
|
{...{ identity, titleId, title, onDone, onUpdateProfile, connectionState, onChangeConnectionState }}
|
|
184
184
|
/>
|
|
@@ -218,7 +218,7 @@ export const IdentityPanelImpl = (props: IdentityPanelImplProps) => {
|
|
|
218
218
|
</Viewport.View>
|
|
219
219
|
</Viewport.Views>
|
|
220
220
|
</Viewport.Root>
|
|
221
|
-
|
|
221
|
+
</>
|
|
222
222
|
);
|
|
223
223
|
};
|
|
224
224
|
|
|
@@ -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';
|
|
@@ -35,8 +35,8 @@ export type IdentityPanelImplProps = {
|
|
|
35
35
|
onDone?: () => void;
|
|
36
36
|
doneActionParent?: Parameters<typeof cloneElement>[0];
|
|
37
37
|
invitationUrl?: string;
|
|
38
|
-
IdentityActionChooser?:
|
|
39
|
-
InvitationManager?:
|
|
38
|
+
IdentityActionChooser?: FC<IdentityPanelStepProps>;
|
|
39
|
+
InvitationManager?: FC<InvitationManagerProps>;
|
|
40
40
|
} & Partial<InvitationStatus> &
|
|
41
41
|
Partial<AgentFormProps>;
|
|
42
42
|
|
|
@@ -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
|
+
};
|
|
@@ -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/react-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 {
|
|
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
|
-
|
|
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
|
-
|
|
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,
|