diff --git a/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx b/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx index 19d8621cbc1..bd7d31f9652 100644 --- a/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx +++ b/src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx @@ -592,10 +592,14 @@ export function RuntimeEnvironmentsPane({ await window.api.runtimeEnvironments.disconnect({ selector: environment.id }) // Why: disconnect is non-destructive; keep the saved server but show the // user that this live client is no longer attached to it. - useAppStore.getState().setRuntimeEnvironmentStatus(environment.id, { - status: null, - checkedAt: Date.now() - }) + useAppStore.getState().setRuntimeEnvironmentStatus( + environment.id, + { + status: null, + checkedAt: Date.now() + }, + { suppressDisconnectToast: true } + ) if (mountedRef.current) { setDetailsByEnvironmentId((current) => ({ ...current, diff --git a/src/renderer/src/components/status-bar/SshStatusSegment.tsx b/src/renderer/src/components/status-bar/SshStatusSegment.tsx index d67fb82cf80..42049cb5a25 100644 --- a/src/renderer/src/components/status-bar/SshStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/SshStatusSegment.tsx @@ -254,7 +254,11 @@ export function SshStatusSegment({ async (environmentId: string): Promise => { try { await window.api.runtimeEnvironments.disconnect({ selector: environmentId }) - setRuntimeEnvironmentStatus(environmentId, { status: null, checkedAt: Date.now() }) + setRuntimeEnvironmentStatus( + environmentId, + { status: null, checkedAt: Date.now() }, + { suppressDisconnectToast: true } + ) recordFeatureInteraction('ssh') } catch (err) { toast.error( diff --git a/src/renderer/src/store/slices/runtime-status.test.ts b/src/renderer/src/store/slices/runtime-status.test.ts index ac04c0d3e22..2950a63115e 100644 --- a/src/renderer/src/store/slices/runtime-status.test.ts +++ b/src/renderer/src/store/slices/runtime-status.test.ts @@ -240,6 +240,22 @@ describe('runtime-status slice', () => { expect(toast.warning).not.toHaveBeenCalled() }) + it('does not report an intentional disconnect as an outage', () => { + const store = createSliceStore() + store.getState().setRuntimeEnvironmentStatus('env-a', { status: makeStatus(), checkedAt: 1 }) + + store + .getState() + .setRuntimeEnvironmentStatus( + 'env-a', + { status: null, checkedAt: 2 }, + { suppressDisconnectToast: true } + ) + + expect(toast.warning).not.toHaveBeenCalled() + expect(store.getState().runtimeStatusByEnvironmentId.get('env-a')?.status).toBeNull() + }) + it('clears a single environment entry', () => { const store = createSliceStore() store.getState().setRuntimeEnvironmentStatus('env-a', { status: makeStatus(), checkedAt: 1 }) diff --git a/src/renderer/src/store/slices/runtime-status.ts b/src/renderer/src/store/slices/runtime-status.ts index 2cd0d1cfbf0..1c7ff9a60ac 100644 --- a/src/renderer/src/store/slices/runtime-status.ts +++ b/src/renderer/src/store/slices/runtime-status.ts @@ -46,7 +46,11 @@ export type RuntimeStatusSlice = { * retires state owned by any environment that just left the saved list. */ setRuntimeEnvironments: (environments: PublicKnownRuntimeEnvironment[]) => void /** Merges one environment's status. Replaces the prior entry for that id. */ - setRuntimeEnvironmentStatus: (environmentId: string, status: RuntimeEnvironmentStatus) => void + setRuntimeEnvironmentStatus: ( + environmentId: string, + status: RuntimeEnvironmentStatus, + options?: { suppressDisconnectToast?: boolean } + ) => void /** Drops a removed environment so stale hosts don't linger in the registry. */ clearRuntimeEnvironmentStatus: (environmentId: string) => void /** Drops every entry whose id is not in the saved-environments set. */ @@ -223,7 +227,7 @@ export const createRuntimeStatusSlice: StateCreator { + setRuntimeEnvironmentStatus: (environmentId, status, options) => { const previous = get().runtimeStatusByEnvironmentId.get(environmentId) // Why: a non-null status proves the runtime just answered, so drop any stale // "offline" compat failure before this online transition fires the @@ -249,7 +253,12 @@ export const createRuntimeStatusSlice: StateCreator