fix(desktop): restore cloud reconnect action

This commit is contained in:
Gille 2026-07-10 15:38:38 -06:00 committed by Brooklyn Nicholson
parent 783003179a
commit 71fa56e8ac
2 changed files with 35 additions and 7 deletions

View file

@ -0,0 +1,19 @@
import { describe, expect, it } from 'vitest'
import { savedCloudConnectionUrl } from './gateway-settings'
describe('savedCloudConnectionUrl', () => {
it('normalizes the URL of a persisted cloud connection', () => {
expect(savedCloudConnectionUrl({ mode: 'cloud', remoteUrl: ' HTTPS://AGENT.EXAMPLE/ ' })).toBe(
'https://agent.example'
)
})
it('does not treat a stale cloud URL on a local config as connected', () => {
expect(savedCloudConnectionUrl({ mode: 'local', remoteUrl: 'https://agent.example' })).toBe('')
})
it('does not treat a remote gateway URL as a connected cloud agent', () => {
expect(savedCloudConnectionUrl({ mode: 'remote', remoteUrl: 'https://agent.example' })).toBe('')
})
})

View file

@ -44,6 +44,10 @@ const EMPTY_STATE: GatewaySettingsState = {
cloudOrg: ''
}
export function savedCloudConnectionUrl(config: Pick<GatewaySettingsState, 'mode' | 'remoteUrl'>): string {
return config.mode === 'cloud' ? config.remoteUrl.trim().replace(/\/+$/, '').toLowerCase() : ''
}
function ModeCard({
active,
description,
@ -124,6 +128,12 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
const [state, setState] = useState<GatewaySettingsState>(EMPTY_STATE)
const [remoteToken, setRemoteToken] = useState('')
const [lastTest, setLastTest] = useState<null | string>(null)
const [connectedCloudUrl, setConnectedCloudUrl] = useState('')
const acceptSavedConfig = (config: GatewaySettingsState) => {
setState(config)
setConnectedCloudUrl(savedCloudConnectionUrl(config))
}
// --- Hermes Cloud (cloud mode) state ---
// One portal session powers discovery + the silent per-agent cascade. These
@ -191,7 +201,7 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
return
}
setState(config)
acceptSavedConfig(config)
})
.catch(err => notifyError(err, g.failedLoad))
.finally(() => {
@ -220,7 +230,6 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
// (trim, drop trailing slash, lowercase) or a host-casing difference would
// silently break the connected-highlight.
const normalizeCloudUrl = (url: string) => url.trim().replace(/\/+$/, '').toLowerCase()
const connectedCloudUrl = state.mode === 'cloud' ? normalizeCloudUrl(state.remoteUrl) : ''
const isConnectedAgent = (agent: DesktopCloudAgent) =>
Boolean(connectedCloudUrl && agent.dashboardUrl && normalizeCloudUrl(agent.dashboardUrl) === connectedCloudUrl)
@ -368,7 +377,7 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
? await window.hermesDesktop.applyConnectionConfig(payload())
: await window.hermesDesktop.saveConnectionConfig(payload())
setState(next)
acceptSavedConfig(next)
setRemoteToken('')
notify({
kind: 'success',
@ -404,13 +413,13 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
remoteUrl: trimmedUrl
})
setState(saved)
acceptSavedConfig(saved)
const result = await window.hermesDesktop.oauthLoginConnectionConfig(trimmedUrl)
if (result.connected) {
const refreshed = await window.hermesDesktop.getConnectionConfig(scope)
setState(refreshed)
acceptSavedConfig(refreshed)
notify({ kind: 'success', title: g.signedIn, message: g.connectedTo(providerLabel) })
} else {
notify({
@ -432,7 +441,7 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
try {
await window.hermesDesktop.oauthLogoutConnectionConfig(trimmedUrl || undefined)
const refreshed = await window.hermesDesktop.getConnectionConfig(scope)
setState(refreshed)
acceptSavedConfig(refreshed)
notify({ kind: 'success', title: g.signedOutTitle, message: g.signedOutMessage })
} catch (err) {
notifyError(err, g.signOutFailed)
@ -656,7 +665,7 @@ export function GatewaySettings({ embedded = false }: { embedded?: boolean } = {
cloudOrg: cloudOrgRef.current ?? undefined
})
setState(next)
acceptSavedConfig(next)
notify({ kind: 'success', title: g.cloudConnectedTitle, message: g.cloudConnectedTo(agent.name) })
} catch (err) {
if (err && typeof err === 'object' && 'needsCloudLogin' in err) {