import { useTranslation } from "react-i18next"; import { Pencil, RefreshCw, Trash2 } from "lucide-react"; import { type Backend } from "#/api/backend-registry/types"; import { isCloudBackendLoggedOutHealthError, isInvalidBackendApiKeyHealthError, type BackendHealth, } from "#/hooks/query/use-backends-health"; import { I18nKey } from "#/i18n/declaration"; import { cn } from "#/utils/utils"; import { BackendStatusDot } from "./backend-status-dot"; import { BackendVersion } from "./backend-version"; import { DeviceFlowAuth } from "./device-flow-auth"; import { getBackendStatusLabel } from "./backend-status-label"; import { getLockedCloudHost } from "#/api/agent-server-config"; const ROW_ACTION_BUTTON_CLASS = "inline-flex cursor-pointer items-center justify-center rounded-md p-1 text-muted transition-colors hover:bg-interactive-hover hover:text-white"; interface BackendRowProps { backend: Backend; health: BackendHealth | undefined; orgLabel?: string; onSelect: () => void; onEdit: () => void; onRemove: () => void; onLogin?: (apiKey: string) => void; } export function BackendRow({ backend, health, orgLabel, onSelect, onEdit, onRemove, onLogin, }: BackendRowProps) { const { t } = useTranslation("openhands"); const isInvalidApiKey = isInvalidBackendApiKeyHealthError(health?.lastError); const isCloudLoggedOut = backend.kind === "cloud" && isCloudBackendLoggedOutHealthError(health?.lastError); const statusDetail = !isInvalidApiKey && !isCloudLoggedOut && health?.isConnected === false && health.lastError ? health.lastError : null; const statusLabel = isCloudLoggedOut ? t(I18nKey.BACKEND$LOGGED_OUT) : getBackendStatusLabel(t, backend, health); const statusClassName = health?.isConnected === true ? "text-green-300" : health?.isConnected === false ? "text-red-300" : "text-[var(--oh-muted)]"; const dotStatus = isInvalidApiKey ? false : (health?.isConnected ?? null); const canSelect = health?.isConnected === true && !isInvalidApiKey; const lockedCloudHost = getLockedCloudHost(); return (