Add per-row connectivity diagnostic refresh controls
This commit is contained in:
@@ -109,6 +109,34 @@ function Status({ value, route }: { value: StatusValue; route: string }) {
|
||||
</span>;
|
||||
}
|
||||
|
||||
function RowRefresh({
|
||||
label,
|
||||
running,
|
||||
disabled,
|
||||
onRun,
|
||||
}: {
|
||||
label: string;
|
||||
running: boolean;
|
||||
disabled: boolean;
|
||||
onRun: () => void;
|
||||
}) {
|
||||
return <span className="client-diagnostics-row-refresh-wrap client-tooltip-anchor">
|
||||
<button
|
||||
className={`client-diagnostics-refresh client-diagnostics-row-refresh${running ? ' is-running' : ''}`}
|
||||
type="button"
|
||||
aria-label={`Проверить: ${label}`}
|
||||
aria-busy={running}
|
||||
disabled={disabled}
|
||||
onClick={onRun}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M20 11a8 8 0 1 0-2.3 6.7M20 5v6h-6" />
|
||||
</svg>
|
||||
</button>
|
||||
<Tooltip>Проверить только эту строку</Tooltip>
|
||||
</span>;
|
||||
}
|
||||
|
||||
function ipResult(path: DiagnosticPath | undefined, source: IpSourceDefinition) {
|
||||
if (!path?.available) return null;
|
||||
return source.family === 6
|
||||
@@ -222,6 +250,7 @@ export function ConnectivityDiagnosticsPanel({
|
||||
const sheetRef = useRef<HTMLDivElement>(null);
|
||||
const runnerRef = useRef<HTMLSpanElement>(null);
|
||||
const previousTargetRef = useRef<string | null>(null);
|
||||
const retryTargetRef = useRef<string | undefined>(undefined);
|
||||
const requestError = requestDetails(error);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -264,12 +293,13 @@ export function ConnectivityDiagnosticsPanel({
|
||||
previousTargetRef.current = activeTarget;
|
||||
}, [activeTarget]);
|
||||
|
||||
async function run() {
|
||||
async function run(onlyTarget?: string) {
|
||||
retryTargetRef.current = onlyTarget;
|
||||
setStatus('running');
|
||||
setError(null);
|
||||
try {
|
||||
let next = result;
|
||||
const targets = [
|
||||
const targets = onlyTarget ? [onlyTarget] : [
|
||||
CONNECTIVITY_NETWORK_SOURCE.id,
|
||||
...CONNECTIVITY_IP_SOURCES.map(({ id }) => `ip:${id}`),
|
||||
...sites.map(({ id }) => `site:${id}`),
|
||||
@@ -379,7 +409,7 @@ export function ConnectivityDiagnosticsPanel({
|
||||
aria-label="Проверить маршруты"
|
||||
aria-busy={pending}
|
||||
disabled={pending}
|
||||
onClick={run}
|
||||
onClick={() => run()}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M20 11a8 8 0 1 0-2.3 6.7M20 5v6h-6" />
|
||||
@@ -393,7 +423,7 @@ export function ConnectivityDiagnosticsPanel({
|
||||
{Boolean(error) && <div className="client-diagnostics-feedback">
|
||||
<div className="client-diagnostics-error" role="alert">
|
||||
<span>{requestError.message}</span>
|
||||
{requestError.retryable && <button type="button" onClick={run}>Повторить</button>}
|
||||
{requestError.retryable && <button type="button" onClick={() => run(retryTargetRef.current)}>Повторить</button>}
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
@@ -412,7 +442,15 @@ export function ConnectivityDiagnosticsPanel({
|
||||
data-diagnostic-target={CONNECTIVITY_NETWORK_SOURCE.id}
|
||||
className={activeTarget === CONNECTIVITY_NETWORK_SOURCE.id ? 'is-running' : undefined}
|
||||
>
|
||||
<th scope="row">{CONNECTIVITY_NETWORK_SOURCE.label}</th>
|
||||
<th scope="row" aria-label={CONNECTIVITY_NETWORK_SOURCE.label}><span className="client-diagnostics-row-name">
|
||||
<span>{CONNECTIVITY_NETWORK_SOURCE.label}</span>
|
||||
<RowRefresh
|
||||
label={CONNECTIVITY_NETWORK_SOURCE.label}
|
||||
running={activeTarget === CONNECTIVITY_NETWORK_SOURCE.id}
|
||||
disabled={pending}
|
||||
onRun={() => run(CONNECTIVITY_NETWORK_SOURCE.id)}
|
||||
/>
|
||||
</span></th>
|
||||
<td><NetworkCell
|
||||
path={result?.direct}
|
||||
pending={activeTarget === CONNECTIVITY_NETWORK_SOURCE.id}
|
||||
@@ -428,7 +466,15 @@ export function ConnectivityDiagnosticsPanel({
|
||||
const target = `ip:${source.id}`;
|
||||
const running = activeTarget === target;
|
||||
return <tr key={source.id} data-diagnostic-target={target} className={running ? 'is-running' : undefined}>
|
||||
<th scope="row">{source.label}</th>
|
||||
<th scope="row" aria-label={source.label}><span className="client-diagnostics-row-name">
|
||||
<span>{source.label}</span>
|
||||
<RowRefresh
|
||||
label={source.label}
|
||||
running={running}
|
||||
disabled={pending}
|
||||
onRun={() => run(target)}
|
||||
/>
|
||||
</span></th>
|
||||
<td><IpCell path={result?.direct} source={source} pending={running} route={`Напрямую, ${source.label}`} /></td>
|
||||
<td><IpCell path={result?.vpn} source={source} pending={running} route={`VPN, ${source.label}`} /></td>
|
||||
</tr>})}</tbody>
|
||||
@@ -460,7 +506,15 @@ export function ConnectivityDiagnosticsPanel({
|
||||
style={{ viewTransitionName: removing ? 'none' : `diagnostic-service-${site.id}` }}
|
||||
inert={removing ? true : undefined}
|
||||
>
|
||||
<span role="rowheader" className="client-diagnostics-service-name">{site.label}</span>
|
||||
<span role="rowheader" aria-label={site.label} className="client-diagnostics-service-name client-diagnostics-row-name">
|
||||
<span>{site.label}</span>
|
||||
<RowRefresh
|
||||
label={site.label}
|
||||
running={running}
|
||||
disabled={pending}
|
||||
onRun={() => run(`site:${site.id}`)}
|
||||
/>
|
||||
</span>
|
||||
<span role="cell"><Status value={resultStatus(direct, running)} route={`Напрямую, ${site.label}`} /></span>
|
||||
<span role="cell"><Status value={resultStatus(vpn, running, result?.vpn?.available !== false)} route={`VPN, ${site.label}`} /></span>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user