Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
123 lines
4.7 KiB
TypeScript
123 lines
4.7 KiB
TypeScript
/**
|
|
* Terminal Connection Progress
|
|
* Displays connection progress with logs and timeout
|
|
*/
|
|
import { Loader2, Play } from 'lucide-react';
|
|
import React from 'react';
|
|
import { useI18n } from '../../application/i18n/I18nProvider';
|
|
import { Button } from '../ui/button';
|
|
import { ScrollArea } from '../ui/scroll-area';
|
|
|
|
export interface TerminalConnectionProgressProps {
|
|
status: 'connecting' | 'connected' | 'disconnected';
|
|
error: string | null;
|
|
timeLeft: number;
|
|
isAwaitingUserInput?: boolean;
|
|
showEnterReconnectHint?: boolean;
|
|
isCancelling: boolean;
|
|
showLogs: boolean;
|
|
progressLogs: string[];
|
|
onCancelConnect: () => void;
|
|
onCloseSession: () => void;
|
|
onRetry?: () => void;
|
|
reconnectLabel?: string;
|
|
}
|
|
|
|
export interface TerminalConnectionLogListProps {
|
|
progressLogs: string[];
|
|
error?: string | null;
|
|
}
|
|
|
|
export const TerminalConnectionLogList: React.FC<TerminalConnectionLogListProps> = ({
|
|
progressLogs,
|
|
error,
|
|
}) => (
|
|
<div className="rounded-md border border-border/35 bg-background/40">
|
|
<ScrollArea className="max-h-44">
|
|
<div className="space-y-1 p-2.5 pb-4 pr-4 text-xs text-foreground/90">
|
|
{progressLogs.map((line, idx) => (
|
|
<div key={idx} className="flex items-start gap-2">
|
|
<div className="mt-[0.4rem] h-1.5 w-1.5 flex-shrink-0 rounded-full bg-emerald-500" />
|
|
<div className="min-w-0 break-words leading-5">{line}</div>
|
|
</div>
|
|
))}
|
|
{error && (
|
|
<div className="flex items-start gap-2 text-destructive">
|
|
<div className="mt-[0.4rem] h-1.5 w-1.5 flex-shrink-0 rounded-full bg-destructive" />
|
|
<div className="min-w-0 break-words leading-5">{error}</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
);
|
|
|
|
export const TerminalConnectionProgress: React.FC<TerminalConnectionProgressProps> = ({
|
|
status,
|
|
error,
|
|
timeLeft,
|
|
isAwaitingUserInput = false,
|
|
showEnterReconnectHint = false,
|
|
isCancelling: _isCancelling,
|
|
showLogs,
|
|
progressLogs,
|
|
onCancelConnect: _onCancelConnect,
|
|
onCloseSession,
|
|
onRetry,
|
|
reconnectLabel,
|
|
}) => {
|
|
const { t } = useI18n();
|
|
|
|
return (
|
|
<>
|
|
<div className="flex items-start justify-between gap-3 text-[11px] text-muted-foreground">
|
|
<div className="flex min-w-0 items-start gap-2">
|
|
{status === 'connecting' ? (
|
|
<>
|
|
<Loader2 className="h-3 w-3 mt-0.5 flex-shrink-0 animate-spin" />
|
|
<span className="min-w-0 whitespace-pre-wrap break-words leading-5">
|
|
{isAwaitingUserInput
|
|
? t('terminal.progress.waitingForUserInput')
|
|
: t('terminal.progress.timeoutIn', { seconds: timeLeft })}
|
|
</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<div className="mt-[0.4rem] h-1.5 w-1.5 flex-shrink-0 rounded-full bg-destructive" />
|
|
<span className="min-w-0 whitespace-pre-wrap break-words leading-5 text-destructive">
|
|
{error || t('terminal.progress.disconnected')}
|
|
</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{showLogs && (
|
|
<TerminalConnectionLogList progressLogs={progressLogs} error={error} />
|
|
)}
|
|
|
|
{status !== 'connecting' && (
|
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
{showEnterReconnectHint && (
|
|
<div className="min-w-0 break-words text-[11px] leading-5 text-muted-foreground">
|
|
{t('terminal.progress.enterReconnectHint')}
|
|
</div>
|
|
)}
|
|
<div className="ml-auto flex shrink-0 justify-end gap-2">
|
|
<Button variant="ghost" size="sm" className="h-7 px-3 text-[11px]" onClick={onCloseSession}>
|
|
{t('terminal.toolbar.closeSession')}
|
|
</Button>
|
|
{onRetry && (
|
|
<Button size="sm" className="h-7 px-3 text-[11px]" onClick={onRetry}>
|
|
<Play className="h-3 w-3 mr-1.5" /> {reconnectLabel ?? t('terminal.progress.startOver')}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default TerminalConnectionProgress;
|