Add UI-controlled TProxy bypass for devices

This commit is contained in:
2026-05-24 13:38:52 +03:00
parent 0092ec4cde
commit ab6de6996f
12 changed files with 265 additions and 12 deletions

View File

@@ -224,7 +224,19 @@ function App() {
proxyDefaultMode: data.proxyDefaultMode || 'vpn',
devices: data.devices || [],
});
setState((prev) => prev ? { ...prev, devicesUpdatedAt: data.devicesUpdatedAt } : prev);
setState((prev) => prev ? {
...prev,
devicesUpdatedAt: data.devicesUpdatedAt,
sourceBypassCidrs: data.sourceBypassCidrs,
} : prev);
if (data.sourceBypassResult && data.sourceBypassResult.success === false) {
pushToast({
kind: 'warning',
title: 'Bypass сохранён, но не применён',
message: data.sourceBypassResult.error,
duration: 7000,
});
}
} catch (err) {
pushToast({ kind: 'danger', title: 'Не удалось сохранить устройства', message: err.message });
}

View File

@@ -19,6 +19,7 @@ const OUTBOUND_KIND = {
};
const DEVICE_MODES = {
bypass: { kind: 'warning', label: 'bypass TProxy', hint: 'мимо sing-box; ручной proxy отдельно' },
direct: { kind: 'success', label: 'direct', hint: 'fallback после global rules' },
vpn: { kind: 'info', label: 'VPN', hint: 'fallback после global rules' },
rules: { kind: 'neutral', label: 'default', hint: 'использует transparent default' },
@@ -28,6 +29,7 @@ const DEVICE_MODES = {
function DeviceModeSelect({ value, onChange }) {
return (
<select className="select sm" value={value || 'rules'} onChange={(e) => onChange(e.target.value)}>
<option value="bypass">bypass TProxy</option>
<option value="direct">direct</option>
<option value="vpn">VPN</option>
<option value="rules">default</option>
@@ -46,7 +48,7 @@ function DevicesCard({ devicesConfig, onDefaultsChange, onAdd, onUpdate, onRemov
<div className="card-header">
<div>
<h2>Устройства</h2>
<small className="muted">Global rules применяются первыми. Эти значения fallback после них.</small>
<small className="muted">bypass TProxy применяется до sing-box. Остальные режимы fallback после global rules.</small>
</div>
<div className="btn-group">
<label className="field" style={{ minWidth: 180, margin: 0 }}>