feat: добавлена возможность обхода правил для трафика
All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 19s
All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 19s
- Реализована функция для включения и отключения обхода правил. - Обновлены компоненты интерфейса для управления режимом обхода. - Добавлена обработка состояния обхода в API. Refs: None
This commit is contained in:
@@ -175,6 +175,17 @@ function App() {
|
||||
});
|
||||
}
|
||||
|
||||
async function toggleBypass() {
|
||||
const next = !state?.bypassMode;
|
||||
return withBusy(
|
||||
next ? 'Обход правил включён — весь трафик напрямую' : 'Обход правил отключён',
|
||||
async () => {
|
||||
await api.bypass(next);
|
||||
await loadState();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// === Rules CRUD ===
|
||||
function emptyRule() {
|
||||
return {
|
||||
@@ -309,6 +320,7 @@ function App() {
|
||||
onStop={stopSingbox}
|
||||
onShowConfig={() => setConfigOpen(true)}
|
||||
onNav={navigate}
|
||||
onBypassToggle={toggleBypass}
|
||||
/>
|
||||
)}
|
||||
{page === 'servers' && (
|
||||
|
||||
@@ -72,6 +72,12 @@ export const api = {
|
||||
pingAll: () => request("/api/servers/ping-all", { method: "POST" }),
|
||||
},
|
||||
|
||||
bypass: (enabled) =>
|
||||
request("/api/bypass", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ enabled }),
|
||||
}),
|
||||
|
||||
route: {
|
||||
check: ({ host, ip, port, network }) =>
|
||||
request("/api/route/check", {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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} />
|
||||
|
||||
Reference in New Issue
Block a user