mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
Clear SSH reset prompt during render (#3389)
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import type { ReactNode } from 'react'
|
||||
import type { SshConnectionState } from '../../../../shared/ssh-types'
|
||||
import { useMountedRef } from '@/hooks/useMountedRef'
|
||||
import { SshDestructiveActionDialog } from './SshDestructiveActionDialog'
|
||||
import { isSshTargetConnecting, type SshTargetBusyAction } from './ssh-target-action-state'
|
||||
import {
|
||||
isSshTargetConnecting,
|
||||
shouldClearPendingSshReset,
|
||||
type SshTargetBusyAction
|
||||
} from './ssh-target-action-state'
|
||||
|
||||
type PendingTargetAction = { id: string; label: string }
|
||||
|
||||
@@ -102,12 +106,17 @@ export function SshTargetDestructiveActions({
|
||||
pendingReset !== null && isSshTargetConnecting(pendingResetStatus)
|
||||
const pendingTerminateIsBusy =
|
||||
pendingTerminate !== null && targetActionsInFlight.get(pendingTerminate.id) === 'terminate'
|
||||
|
||||
useEffect(() => {
|
||||
if (pendingResetBlockedByConnection && !pendingResetIsBusy) {
|
||||
setPendingReset(null)
|
||||
}
|
||||
}, [pendingResetBlockedByConnection, pendingResetIsBusy])
|
||||
const shouldClearReset = shouldClearPendingSshReset({
|
||||
pendingTargetId: pendingReset?.id ?? null,
|
||||
pendingResetIsBusy,
|
||||
connectionStatus: pendingResetStatus
|
||||
})
|
||||
if (shouldClearReset) {
|
||||
// Why: a reconnecting target cannot safely reset its relay; clear the
|
||||
// pending dialog before it paints stale destructive UI.
|
||||
setPendingReset(null)
|
||||
}
|
||||
const dialogPendingReset = shouldClearReset ? null : pendingReset
|
||||
|
||||
const confirmResetRelay = async (): Promise<void> => {
|
||||
if (!pendingReset) {
|
||||
@@ -169,10 +178,10 @@ export function SshTargetDestructiveActions({
|
||||
/>
|
||||
|
||||
<SshDestructiveActionDialog
|
||||
open={!!pendingReset && (!pendingResetBlockedByConnection || pendingResetIsBusy)}
|
||||
open={!!dialogPendingReset && (!pendingResetBlockedByConnection || pendingResetIsBusy)}
|
||||
title="Reset Remote Relay?"
|
||||
description="This force-stops the remote relay for this SSH target. Active remote terminals and port forwards for this target will end."
|
||||
targetLabel={pendingReset?.label}
|
||||
targetLabel={dialogPendingReset?.label}
|
||||
actionLabel="Reset Relay"
|
||||
busyLabel="Resetting"
|
||||
isBusy={pendingResetIsBusy}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { isSshTargetConnecting, shouldClearPendingSshReset } from './ssh-target-action-state'
|
||||
|
||||
describe('ssh target action state', () => {
|
||||
it('classifies connecting statuses as busy connection states', () => {
|
||||
expect(isSshTargetConnecting('connecting')).toBe(true)
|
||||
expect(isSshTargetConnecting('deploying-relay')).toBe(true)
|
||||
expect(isSshTargetConnecting('reconnecting')).toBe(true)
|
||||
expect(isSshTargetConnecting('connected')).toBe(false)
|
||||
expect(isSshTargetConnecting('disconnected')).toBe(false)
|
||||
})
|
||||
|
||||
it('clears pending reset only when a non-busy target starts connecting', () => {
|
||||
expect(
|
||||
shouldClearPendingSshReset({
|
||||
pendingTargetId: 'target-1',
|
||||
pendingResetIsBusy: false,
|
||||
connectionStatus: 'reconnecting'
|
||||
})
|
||||
).toBe(true)
|
||||
|
||||
expect(
|
||||
shouldClearPendingSshReset({
|
||||
pendingTargetId: 'target-1',
|
||||
pendingResetIsBusy: true,
|
||||
connectionStatus: 'reconnecting'
|
||||
})
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
shouldClearPendingSshReset({
|
||||
pendingTargetId: null,
|
||||
pendingResetIsBusy: false,
|
||||
connectionStatus: 'reconnecting'
|
||||
})
|
||||
).toBe(false)
|
||||
|
||||
expect(
|
||||
shouldClearPendingSshReset({
|
||||
pendingTargetId: 'target-1',
|
||||
pendingResetIsBusy: false,
|
||||
connectionStatus: 'connected'
|
||||
})
|
||||
).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -11,3 +11,15 @@ const SSH_TARGET_CONNECTING_STATUSES: ReadonlySet<SshConnectionStatus> = new Set
|
||||
export function isSshTargetConnecting(status: SshConnectionStatus): boolean {
|
||||
return SSH_TARGET_CONNECTING_STATUSES.has(status)
|
||||
}
|
||||
|
||||
export function shouldClearPendingSshReset({
|
||||
pendingTargetId,
|
||||
pendingResetIsBusy,
|
||||
connectionStatus
|
||||
}: {
|
||||
pendingTargetId: string | null
|
||||
pendingResetIsBusy: boolean
|
||||
connectionStatus: SshConnectionStatus
|
||||
}): boolean {
|
||||
return pendingTargetId !== null && !pendingResetIsBusy && isSshTargetConnecting(connectionStatus)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user