internal/gui: wire real checker.Run + CancelCheck binding + RawHex display
- RunCheck now drives internal/checker.Run instead of the fake 7-step sleep loop. Streams checker.Result events as "check:result" with Duration converted to milliseconds; emits "check:done" summary on channel close. Re-running while a check is in flight cancels the previous run and waits for its goroutine to drain so two emitter goroutines never race on event order. - New CancelCheck method (no-op when nothing is running) is bound through wailsjs/go/gui/App.js and surfaced in useDrover as cancelCheck() with a "check cancelled by user" log line. - Classic.jsx: while phase==='checking', the Check button collapses to a disabled "Checking…" pill side-by-side with a Cancel button (uses Stop's secondary visual weight, t.danger on hover). The expanded failure row now renders r.rawHex (truncated to 64 chars) on its own mono line and the copy button includes raw=<hex> when present. - CheckResult struct gains RawHex (json:"rawHex") and Attempt fields. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -121,9 +121,18 @@ export function ClassicWindow({ mode = 'dark', initial, onToggleMode }) {
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<PrimaryBtn t={t} onClick={D.runCheck} disabled={D.phase === 'checking' || isActive}>
|
||||
{D.phase === 'checking' ? 'Checking…' : 'Check connection'}
|
||||
</PrimaryBtn>
|
||||
{D.phase === 'checking' ? (
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<PrimaryBtn t={t} onClick={D.runCheck} disabled style={{ flex: 1 }}>
|
||||
Checking…
|
||||
</PrimaryBtn>
|
||||
<ClassicCancelBtn t={t} onClick={D.cancelCheck} />
|
||||
</div>
|
||||
) : (
|
||||
<PrimaryBtn t={t} onClick={D.runCheck} disabled={isActive}>
|
||||
Check connection
|
||||
</PrimaryBtn>
|
||||
)}
|
||||
|
||||
{/* Status */}
|
||||
<div style={{ height: 18 }} />
|
||||
@@ -316,8 +325,19 @@ function ClassicStatus({ t, D, palette, fontMono }) {
|
||||
}}>
|
||||
<div style={{ color: t.danger, fontWeight: 600, marginBottom: 2 }}>{r.error}</div>
|
||||
<div style={{ color: t.dim }}>{r.hint}</div>
|
||||
{r.rawHex && (
|
||||
<div style={{
|
||||
fontFamily: fontMono, fontSize: 10.5, color: t.dimmer,
|
||||
marginTop: 4, padding: '4px 6px',
|
||||
background: t.panelAlt, borderRadius: 2,
|
||||
overflowX: 'auto', whiteSpace: 'nowrap',
|
||||
}}>
|
||||
{r.rawHex.length > 64 ? r.rawHex.slice(0, 64) + '…' : r.rawHex}
|
||||
</div>
|
||||
)}
|
||||
<div style={{ display:'flex', gap: 6, marginTop: 6 }}>
|
||||
<button onClick={() => navigator.clipboard?.writeText(`[${test.label}] ${r.error} — ${r.metric}`)}
|
||||
<button onClick={() => navigator.clipboard?.writeText(
|
||||
`[${test.label}] ${r.error} — ${r.metric}` + (r.rawHex ? ` — raw=${r.rawHex}` : ''))}
|
||||
style={smallBtn(t, fontMono)}>
|
||||
<IconCopy color={t.dim}/> copy
|
||||
</button>
|
||||
@@ -388,6 +408,22 @@ function ClassicStartBtn({ t, D, fontMono }) {
|
||||
);
|
||||
}
|
||||
|
||||
function ClassicCancelBtn({ t, onClick }) {
|
||||
const [hover, setHover] = React.useState(false);
|
||||
return (
|
||||
<button onClick={onClick}
|
||||
onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
|
||||
style={{
|
||||
width: 92, padding: '9px 12px', borderRadius: 3, fontWeight: 600, fontSize: 12.5,
|
||||
background: t.btnBg, color: hover ? t.danger : t.text,
|
||||
border: `1px solid ${hover ? t.danger : t.border}`, cursor: 'pointer',
|
||||
transition: 'color .12s, border-color .12s',
|
||||
}}>
|
||||
Cancel
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function ClassicStopBtn({ t, D }) {
|
||||
const enabled = D.phase === 'active';
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user