Add Gateway connectivity diagnostics and traffic chart improvements
This commit is contained in:
@@ -16,6 +16,7 @@ import { instructionBlocks } from '../instructions.js';
|
||||
import { operationBlocked } from '../state/operations.js';
|
||||
import { ConfirmationPopup } from './ConfirmationPopup.jsx';
|
||||
import { DevicesPanel } from './DevicesPanel.jsx';
|
||||
import { ConnectivityDiagnosticsPanel } from './ConnectivityDiagnosticsPanel.jsx';
|
||||
import { ServerPicker } from './ServerPicker.jsx';
|
||||
import { ERROR_DEFINITIONS } from '../../shared/errors.js';
|
||||
import { canAppendRouteRule } from '../../shared/routingRules.js';
|
||||
@@ -642,6 +643,7 @@ export function ClientOverviewPage({
|
||||
const [instructionsOpen, setInstructionsOpen] = useState(false);
|
||||
const [localRulesOpen, setLocalRulesOpen] = useState(false);
|
||||
const [devicesOpen, setDevicesOpen] = useState(false);
|
||||
const [diagnosticsOpen, setDiagnosticsOpen] = useState(false);
|
||||
const [localRulesDraft, setLocalRulesDraft] = useState([]);
|
||||
const [localRulesRevision, setLocalRulesRevision] = useState(state?.route?.localRulesRevision || 0);
|
||||
const [confirmingLocalRulesClose, setConfirmingLocalRulesClose] = useState(false);
|
||||
@@ -660,6 +662,9 @@ export function ClientOverviewPage({
|
||||
const devicesPanelRef = useRef(null);
|
||||
const devicesToggleRef = useRef(null);
|
||||
const devicesCloseRef = useRef(null);
|
||||
const diagnosticsPanelRef = useRef(null);
|
||||
const diagnosticsToggleRef = useRef(null);
|
||||
const diagnosticsCloseRef = useRef(null);
|
||||
const localRulesBaselineRef = useRef('[]');
|
||||
const previousHasSubscriptionRef = useRef(hasSubscription);
|
||||
const gatewayAddress = isGateway ? window.location.hostname : '127.0.0.1';
|
||||
@@ -794,6 +799,8 @@ export function ClientOverviewPage({
|
||||
setEditingSubscription(true);
|
||||
setInstructionsOpen(false);
|
||||
setLocalRulesOpen(false);
|
||||
setDevicesOpen(false);
|
||||
setDiagnosticsOpen(false);
|
||||
}
|
||||
}, [hasSubscription]);
|
||||
|
||||
@@ -876,6 +883,28 @@ export function ClientOverviewPage({
|
||||
};
|
||||
}, [devicesOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!diagnosticsOpen) return undefined;
|
||||
const frame = requestAnimationFrame(() => diagnosticsCloseRef.current?.focus());
|
||||
const closeDiagnostics = (event) => {
|
||||
if (event.type === 'keydown' && event.key !== 'Escape') return;
|
||||
if (event.type !== 'keydown' && (
|
||||
diagnosticsPanelRef.current?.contains(event.target) || diagnosticsToggleRef.current?.contains(event.target)
|
||||
)) return;
|
||||
setDiagnosticsOpen(false);
|
||||
};
|
||||
document.addEventListener('pointerdown', closeDiagnostics);
|
||||
document.addEventListener('keydown', closeDiagnostics);
|
||||
return () => {
|
||||
cancelAnimationFrame(frame);
|
||||
document.removeEventListener('pointerdown', closeDiagnostics);
|
||||
document.removeEventListener('keydown', closeDiagnostics);
|
||||
requestAnimationFrame(() => {
|
||||
if (diagnosticsPanelRef.current?.contains(document.activeElement)) diagnosticsToggleRef.current?.focus();
|
||||
});
|
||||
};
|
||||
}, [diagnosticsOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!localRulesOpen) return undefined;
|
||||
const frame = requestAnimationFrame(() => localRulesCloseRef.current?.focus());
|
||||
@@ -1021,6 +1050,7 @@ export function ClientOverviewPage({
|
||||
const rules = state?.route?.localRules || [];
|
||||
setInstructionsOpen(false);
|
||||
setDevicesOpen(false);
|
||||
setDiagnosticsOpen(false);
|
||||
localRulesBaselineRef.current = localRulesSignature(rules);
|
||||
setLocalRulesDraft(rules.map(createLocalRuleDraft));
|
||||
setLocalRulesRevision(state?.route?.localRulesRevision || 0);
|
||||
@@ -1107,6 +1137,7 @@ export function ClientOverviewPage({
|
||||
onClick={() => {
|
||||
if (localRulesOpen && !requestCloseLocalRules()) return;
|
||||
setDevicesOpen(false);
|
||||
setDiagnosticsOpen(false);
|
||||
setInstructionsOpen((open) => !open);
|
||||
}}
|
||||
>
|
||||
@@ -1126,6 +1157,7 @@ export function ClientOverviewPage({
|
||||
onClick={() => {
|
||||
if (localRulesOpen && !requestCloseLocalRules()) return;
|
||||
setInstructionsOpen(false);
|
||||
setDiagnosticsOpen(false);
|
||||
setDevicesOpen((open) => !open);
|
||||
}}
|
||||
>
|
||||
@@ -1136,6 +1168,25 @@ export function ClientOverviewPage({
|
||||
</svg>
|
||||
<span>Устройства</span>
|
||||
</button>}
|
||||
{isGateway && <button
|
||||
ref={diagnosticsToggleRef}
|
||||
className={`client-instructions-toggle client-diagnostics-toggle${diagnosticsOpen ? ' is-open' : ''}`}
|
||||
type="button"
|
||||
aria-expanded={diagnosticsOpen}
|
||||
aria-controls="client-diagnostics"
|
||||
aria-label={diagnosticsOpen ? 'Закрыть диагностику' : 'Проверить маршруты Gateway'}
|
||||
onClick={() => {
|
||||
if (localRulesOpen && !requestCloseLocalRules()) return;
|
||||
setInstructionsOpen(false);
|
||||
setDevicesOpen(false);
|
||||
setDiagnosticsOpen((open) => !open);
|
||||
}}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M3 12h4l2.2-5 4.2 10 2.1-5H21" />
|
||||
</svg>
|
||||
<span>Диагностика</span>
|
||||
</button>}
|
||||
<button
|
||||
ref={localRulesToggleRef}
|
||||
className={`client-local-rules-toggle${localRulesOpen ? ' is-open' : ''}${localRulesPendingRestart ? ' has-pending' : ''}`}
|
||||
@@ -1485,6 +1536,13 @@ export function ClientOverviewPage({
|
||||
onClose={() => setDevicesOpen(false)}
|
||||
/>}
|
||||
|
||||
{hasSubscription && subscriptionContentReady && isGateway && <ConnectivityDiagnosticsPanel
|
||||
open={diagnosticsOpen}
|
||||
panelRef={diagnosticsPanelRef}
|
||||
closeRef={diagnosticsCloseRef}
|
||||
onClose={() => setDiagnosticsOpen(false)}
|
||||
/>}
|
||||
|
||||
{hasSubscription && subscriptionContentReady && <LocalRulesPanel
|
||||
open={localRulesOpen}
|
||||
rules={localRulesDraft}
|
||||
|
||||
Reference in New Issue
Block a user