Files
NetMesh/components/terminal/TerminalConnectionProgress.tsx
zhaolei 3c72efcb7f
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
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

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;