feat: добавлена возможность обхода правил для трафика
All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 19s

- Реализована функция для включения и отключения обхода правил.
- Обновлены компоненты интерфейса для управления режимом обхода.
- Добавлена обработка состояния обхода в API.

Refs: None
This commit is contained in:
2026-05-08 21:28:42 +03:00
parent 11f2c0ccb2
commit eeec4359b0
6 changed files with 119 additions and 23 deletions

View File

@@ -33,23 +33,21 @@ const CATEGORY_BADGE = {
other: { cls: '', label: 'other' },
};
const TRAFFIC_GROUP_WINDOW_MS = 60_000;
function groupTraffic(list) {
const out = [];
const map = new Map();
for (const e of list) {
const key = `${e.category}|${e.host}|${e.port}|${e.matchedRule || ''}`;
const ts = new Date(e.ts).getTime();
const last = out[out.length - 1];
if (last && last._key === key && ts - last._lastTs < TRAFFIC_GROUP_WINDOW_MS) {
last.count += 1;
last._lastTs = ts;
last.lastTs = e.ts;
if (map.has(key)) {
const g = map.get(key);
g.count++;
g._lastTs = ts;
g.lastTs = e.ts;
} else {
out.push({ ...e, _key: key, _lastTs: ts, count: 1, lastTs: e.ts });
map.set(key, { ...e, _key: key, _lastTs: ts, count: 1, lastTs: e.ts });
}
}
return out;
return Array.from(map.values()).sort((a, b) => b._lastTs - a._lastTs);
}
function TrafficTab() {

View File

@@ -55,7 +55,7 @@ function StatusHero({ state, status }) {
);
}
function QuickActions({ state, busy, onRestart, onStop, onShowConfig, onNav }) {
function QuickActions({ state, busy, onRestart, onStop, onShowConfig, onNav, onBypassToggle }) {
return (
<div className="card">
<div className="card-header">
@@ -74,6 +74,14 @@ function QuickActions({ state, busy, onRestart, onStop, onShowConfig, onNav }) {
<button className="btn btn-ghost" disabled={!state?.configExists} onClick={onShowConfig}>
Показать config
</button>
<button
className={`btn ${state?.bypassMode ? 'btn-warning' : 'btn-ghost'}`}
disabled={busy || !state?.singboxRunning}
onClick={onBypassToggle}
title="Весь трафик напрямую — для диагностики"
>
{state?.bypassMode ? '⚠ Обход правил ВКЛЮЧЁН' : '↗ Весь трафик напрямую'}
</button>
</div>
</div>
);
@@ -145,12 +153,21 @@ function RoutingSummary({ state, onNav }) {
);
}
export function OverviewPage({ state, status, busy, onRestart, onStop, onShowConfig, onNav }) {
export function OverviewPage({ state, status, busy, onRestart, onStop, onShowConfig, onNav, onBypassToggle }) {
return (
<div className="section-stack">
{state?.bypassMode && (
<div className="alert alert-warning" style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<strong> Режим обхода правил активен</strong>
<span className="muted"> весь трафик идёт напрямую, VPN-правила не применяются.</span>
<button className="btn btn-sm btn-warning" style={{ marginLeft: 'auto' }} onClick={onBypassToggle}>
Отключить
</button>
</div>
)}
<StatusHero state={state} status={status} />
<div className="grid-2">
<QuickActions state={state} busy={busy} onRestart={onRestart} onStop={onStop} onShowConfig={onShowConfig} onNav={onNav} />
<QuickActions state={state} busy={busy} onRestart={onRestart} onStop={onStop} onShowConfig={onShowConfig} onNav={onNav} onBypassToggle={onBypassToggle} />
<RoutingSummary state={state} onNav={onNav} />
</div>
<RecentEvents onNav={onNav} />