fix: collapse ping section by default, expand on click
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -632,6 +632,7 @@ function WorkstationCard({
|
||||
const [updateMsg, setUpdateMsg] = useState<string | null>(null)
|
||||
const [testResults, setTestResults] = useState<Record<string, { ok: boolean; msg: string } | null>>({})
|
||||
const [testingDeviceId, setTestingDeviceId] = useState<string | null>(null)
|
||||
const [showPing, setShowPing] = useState(false)
|
||||
const [pingHost, setPingHost] = useState('')
|
||||
const [pinging, setPinging] = useState(false)
|
||||
const [pingResult, setPingResult] = useState<{ ok: boolean; output?: string; error?: string } | null>(null)
|
||||
@@ -959,35 +960,47 @@ function WorkstationCard({
|
||||
{/* Ping tool — only when agent is online */}
|
||||
{ws.isOnline && (
|
||||
<div className="pt-2 border-t border-slate-100 dark:border-slate-700">
|
||||
<p className="text-xs text-slate-400 dark:text-slate-500 mb-2">Пинг через агента</p>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
value={pingHost}
|
||||
onChange={e => setPingHost(e.target.value)}
|
||||
onKeyDown={e => e.key === 'Enter' && pingNow()}
|
||||
placeholder="192.168.1.1 или hostname"
|
||||
className="input text-sm font-mono flex-1 py-1.5"
|
||||
/>
|
||||
<button
|
||||
onClick={pingNow}
|
||||
disabled={pinging || !pingHost.trim()}
|
||||
className="btn-secondary py-1.5 px-3 text-sm flex items-center gap-1.5 shrink-0 h-9 whitespace-nowrap"
|
||||
>
|
||||
{pinging ? <RefreshCw size={13} className="animate-spin" /> : <Network size={13} />}
|
||||
{pinging ? 'Пинг...' : 'Пинг'}
|
||||
</button>
|
||||
</div>
|
||||
{pingResult && (
|
||||
<div className={cn(
|
||||
'mt-2 rounded-lg text-xs',
|
||||
pingResult.ok
|
||||
? 'bg-emerald-50 dark:bg-emerald-900/20 text-emerald-700 dark:text-emerald-400'
|
||||
: 'bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400',
|
||||
)}>
|
||||
{pingResult.ok && pingResult.output ? (
|
||||
<pre className="p-3 whitespace-pre-wrap font-mono text-xs overflow-x-auto">{pingResult.output.trim()}</pre>
|
||||
) : (
|
||||
<p className="p-3 flex items-center gap-1.5"><X size={11} />{pingResult.error ?? 'Ошибка'}</p>
|
||||
<button
|
||||
onClick={() => { setShowPing(v => !v); setPingResult(null) }}
|
||||
className="flex items-center gap-1.5 text-xs text-slate-400 hover:text-slate-600 dark:hover:text-slate-300 transition-colors"
|
||||
>
|
||||
<Network size={12} />
|
||||
Пинг через агента
|
||||
{showPing ? <ChevronDown size={11} /> : <ChevronRight size={11} />}
|
||||
</button>
|
||||
{showPing && (
|
||||
<div className="mt-2">
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
value={pingHost}
|
||||
onChange={e => setPingHost(e.target.value)}
|
||||
onKeyDown={e => e.key === 'Enter' && pingNow()}
|
||||
placeholder="192.168.1.1 или hostname"
|
||||
className="input text-sm font-mono flex-1 py-1.5"
|
||||
autoFocus
|
||||
/>
|
||||
<button
|
||||
onClick={pingNow}
|
||||
disabled={pinging || !pingHost.trim()}
|
||||
className="btn-secondary py-1.5 px-3 text-sm flex items-center gap-1.5 shrink-0 h-9 whitespace-nowrap"
|
||||
>
|
||||
{pinging ? <RefreshCw size={13} className="animate-spin" /> : <Network size={13} />}
|
||||
{pinging ? 'Пинг...' : 'Пинг'}
|
||||
</button>
|
||||
</div>
|
||||
{pingResult && (
|
||||
<div className={cn(
|
||||
'mt-2 rounded-lg text-xs',
|
||||
pingResult.ok
|
||||
? 'bg-emerald-50 dark:bg-emerald-900/20 text-emerald-700 dark:text-emerald-400'
|
||||
: 'bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400',
|
||||
)}>
|
||||
{pingResult.ok && pingResult.output ? (
|
||||
<pre className="p-3 whitespace-pre-wrap font-mono text-xs overflow-x-auto">{pingResult.output.trim()}</pre>
|
||||
) : (
|
||||
<p className="p-3 flex items-center gap-1.5"><X size={11} />{pingResult.error ?? 'Ошибка'}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user