diff --git a/README.md b/README.md index ad16a07..cbac19a 100644 --- a/README.md +++ b/README.md @@ -437,6 +437,11 @@ InErrors, InDroppedDma, AllocFails, SkbAllocFails и Restarts через ethtool ## Карта трафика NPM + CrowdSec (v0.20.0) +С v0.20.1 страница помещается в высоту окна: карта и лента в центре, +счётчики сверху, график и рейтинги снизу. На телефоне доступны вкладки +«Карта / События / Статистика». Последние 100 событий листаются по страницам; +нажатие на строку открывает полные подробности. + Откройте **Настройки → Карта трафика**, включите страницу и выберите агент VM/LXC, где установлены Nginx Proxy Manager и CrowdSec. Например, `nginxproxymanager · VMID 102`. Необязательно выберите страну сервера для diff --git a/assets/traffic.html b/assets/traffic.html index 00b4ee8..74cf241 100644 --- a/assets/traffic.html +++ b/assets/traffic.html @@ -1,47 +1,64 @@ Карта трафика · Proxmox Dashboard -
PROXMOX DASHBOARD / TRAFFIC OBSERVATORY

Мир обращается к вашим сервисам

HTTP-запросы и события CrowdSec · последние 24 часа
-
-
Получаем данные выбранного агента…
-
- -
ИСТОЧНИКИ ЗАПРОСОВ—
ЗапросСрабатываниеРешение
Без геолокации: —
Точки обозначают страны, а не точное местоположение людей.
- -
-

HTTP-запросы в минуту · последний час

— req/s · среднее за 60 сек.

IP · события

- -
+:root{color-scheme:dark;--bg:#090d13;--panel:#111821;--line:#24303b;--text:#ecf3f9;--muted:#8b9daa;--blue:#5ed8ed;--orange:#ffbc70;--pink:#b7a0ff;--green:#b8ef72}*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;overflow:hidden}body{font:12px/1.4 system-ui,sans-serif;color:var(--text);background:radial-gradient(ellipse at 43% 42%,#17253666,transparent 58%),var(--bg);padding:18px 22px 12px;display:grid;grid-template-rows:48px 34px 78px minmax(0,1fr) 158px 20px;gap:12px}button,select{font:inherit;color:inherit;background:#161e28;border:1px solid var(--line);border-radius:9px;padding:7px 11px;cursor:pointer}button:hover,select:hover{border-color:#607589}button:focus-visible,select:focus-visible,a:focus-visible{outline:2px solid var(--blue);outline-offset:3px}button:disabled{opacity:.35;cursor:default}a{color:var(--muted);text-decoration:none}a:hover{color:var(--text)}header{display:flex;align-items:center;justify-content:space-between;gap:20px;min-width:0}header>div{display:flex;align-items:center;gap:13px;min-width:0}.brand-mark{display:grid;place-items:center;width:38px;height:38px;flex:none;border:1px solid #4d6855;border-radius:12px;background:#17251c;color:var(--green);font-size:24px}.eyebrow{color:var(--muted);font-size:9px;letter-spacing:.19em;font-weight:650}h1{font-size:23px;font-weight:600;letter-spacing:-.055em;margin:1px 0 0}header nav{display:flex;align-items:center;gap:16px;flex:none}.live{font:9px ui-monospace,monospace;letter-spacing:.08em;color:var(--green);border:1px solid #344b32;border-radius:20px;padding:6px 10px;background:#192316}.live.stale{color:var(--orange);border-color:#594733;background:#291f14}.now{font:11px ui-monospace,monospace;color:var(--muted)}.icon-button{padding:6px 10px;font-size:18px;line-height:1;background:transparent}.toolbar{display:flex;align-items:center;gap:8px;min-width:0}.segments{display:flex;gap:3px;border:1px solid var(--line);border-radius:10px;padding:3px;background:#10161e}.segments button{padding:5px 11px;border:0;background:none;color:var(--muted);font-size:11px;white-space:nowrap}.segments button.active{background:#26333f;color:#f4f8fb;box-shadow:0 1px 4px #0004}.toolbar select{max-width:230px;min-width:110px;height:32px;font-size:11px}.toolbar label{color:var(--muted);display:flex;align-items:center;gap:5px;font-size:11px;white-space:nowrap}.toolbar input{accent-color:var(--green)}#pause{margin-left:auto;height:32px;font-size:11px}.metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.metric{border:1px solid var(--line);border-radius:13px;background:linear-gradient(125deg,#17212c,#10171f);padding:11px 16px;display:grid;grid-template-columns:1fr auto;align-items:center;position:relative;overflow:hidden;min-width:0}.metric small{display:block;color:var(--muted);font-size:10px;white-space:nowrap}.metric b{display:block;font-size:29px;font-weight:550;line-height:1.15;letter-spacing:-.05em;font-variant-numeric:tabular-nums}.metric i{font-style:normal;font-size:20px;color:var(--green);background:#263521;border-radius:12px;width:38px;height:38px;display:grid;place-items:center}.metric.request i{color:var(--blue);background:#17333b}.metric.alert i{color:var(--orange);background:#352a20}.metric.decision i{color:var(--pink);background:#2b253d}.metric:after{content:'';position:absolute;height:45px;width:45px;right:-23px;bottom:-25px;background:var(--green);filter:blur(24px);opacity:.2}.dashboard{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:12px;min-height:0}.panel{border:1px solid var(--line);border-radius:14px;background:#10171fbc;min-width:0;min-height:0;overflow:hidden}.map-panel{position:relative;display:grid;grid-template-rows:30px minmax(0,1fr) 25px;padding:10px 13px 7px;background:radial-gradient(ellipse at 55% 52%,#1a304140,transparent 65%),#0e151d}.map-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}.section-label{font-size:10px;font-weight:600;letter-spacing:.12em;color:#a0b1bf}.source-status{display:flex;align-items:center;min-width:0;max-width:65%;gap:8px;border:0;background:none;padding:0;color:var(--muted);font-size:10px}#sourceName{max-width:190px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.status-box{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.status-box.error{color:var(--orange)}.map-stage{position:relative;min-width:0;min-height:0;overflow:hidden}.map-stage:after{content:'';position:absolute;inset:0;pointer-events:none;background:radial-gradient(ellipse,transparent 60%,#0e151d66)}#world{position:absolute;width:100%;height:100%;inset:0;display:block}.map-foot{display:flex;justify-content:space-between;align-items:center;gap:10px;font-size:9px;color:var(--muted);min-width:0}.legend{display:flex;gap:12px}.dot{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--blue);margin-right:5px}.dot.alert{background:var(--orange)}.dot.decision{background:var(--pink)}#unmapped{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.feed-panel{display:grid;grid-template-rows:36px minmax(0,1fr) 30px;padding:0 13px}.feed-heading{display:flex;align-items:center;justify-content:space-between}.panel h2{font-size:11px;font-weight:550;letter-spacing:.01em;margin:0}.note{font-size:10px;color:var(--muted)}.feed{min-height:0;overflow:hidden}.event{height:64px;padding:8px 0;border-top:1px solid #202c36;cursor:pointer;position:relative}.event:hover{background:#1c2b3666}.event:focus-visible{outline:1px solid var(--blue);outline-offset:-1px}.event-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.event-head b{font:11px ui-monospace,monospace;letter-spacing:.01em}.event-head time{font:9px ui-monospace,monospace;color:var(--muted);flex:none}.event .meta{font-size:10px;color:#95a9b8;margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.event .path{font:10px/1.5 ui-monospace,monospace;color:#becad3;margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kind{color:var(--blue)}.kind.alert{color:var(--orange)}.kind.decision{color:var(--pink)}.pager{display:flex;align-items:center;gap:7px;border-top:1px solid var(--line);font-size:9px;color:var(--muted)}.pager button{font-size:10px;border:0;background:none;padding:3px 6px}.pager #latest{margin-left:auto;color:var(--green)}.empty{color:var(--muted);padding:18px 0;font-size:12px}.bottom{display:grid;grid-template-columns:minmax(0,1.6fr) minmax(0,1fr) minmax(0,1fr);gap:12px;min-height:0}.bottom .panel{padding:11px 14px;display:flex;flex-direction:column}.bottom-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}.chart{display:block;width:100%;flex:1;min-height:0}.ranking{display:flex;justify-content:space-between;align-items:center;gap:10px;height:16px;font-size:10px;position:relative}.ranking:before{content:'';position:absolute;inset:2px 0;background:linear-gradient(90deg,#4f809f18,transparent);width:var(--share,0);border-radius:3px}.ranking span{position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ranking b{font:10px ui-monospace,monospace;color:var(--blue);flex:none}.ranking em{font:9px ui-monospace,monospace;color:#617583;margin-right:8px;font-style:normal}footer{display:flex;align-items:center;gap:12px;justify-content:space-between;color:#718695;font-size:9px;min-width:0}footer .credits{display:flex;gap:10px;min-width:0}footer a{color:#8298a6}.footer-help{padding:0;border:0;background:none;color:#8298a6;font-size:9px}.tooltip{position:fixed;pointer-events:none;display:none;padding:10px 14px;border:1px solid #475578;border-radius:9px;background:#101725f5;font-size:12px;z-index:3}dialog{width:min(540px,calc(100vw - 30px));max-height:85dvh;overflow:auto;border:1px solid #384a5a;border-radius:18px;padding:22px;background:#131d27;color:var(--text);box-shadow:0 30px 120px #0009}dialog::backdrop{background:#030810bb;backdrop-filter:blur(7px)}.dialog-head{display:flex;justify-content:space-between;gap:16px;align-items:center;margin-bottom:20px}.dialog-head h2{font-size:18px;margin:0}.detail-row{padding:9px 0;border-top:1px solid var(--line);overflow-wrap:anywhere}.detail-row small{display:block;color:var(--muted);margin-bottom:3px}dialog p{color:#b8c7d2;line-height:1.7}#mobileTabs{display:none} +@media(min-width:1600px){body{padding:24px 30px 16px;grid-template-rows:54px 38px 94px minmax(0,1fr) 184px 22px;gap:16px}.dashboard{grid-template-columns:minmax(0,1fr) 360px}.metric b{font-size:36px}.metric small{font-size:11px}.metric{padding:14px 20px}.ranking{height:18px;font-size:11px}.ranking b{font-size:11px}.map-panel{padding:12px 20px}.feed-panel{padding:0 17px}.bottom .panel{padding:15px 18px}} +@media(max-height:650px) and (min-width:761px){body{padding:10px 16px;grid-template-rows:36px 32px 62px minmax(0,1fr) 130px 16px;gap:8px}.metric{padding:7px 12px}.metric b{font-size:25px}.ranking{height:13px}.bottom .panel{padding:8px 12px}.event{height:56px;padding:5px 0}.dashboard{grid-template-columns:minmax(0,1fr) 290px}h1{font-size:20px}} +@media(max-width:1000px){body{padding:12px;gap:9px}.dashboard{grid-template-columns:minmax(0,1fr) 280px}.segments button{padding:5px 8px;font-size:10px}.toolbar select{max-width:155px}.toolbar label{font-size:10px}header nav{gap:9px}.now{display:none}.metric small{font-size:9px}.metric i{width:28px;height:28px;font-size:16px}.map-foot{font-size:8px}.legend{gap:6px}.bottom{grid-template-columns:1.1fr 1fr 1fr}} +@media(max-width:760px){body{padding:12px;grid-template-rows:42px auto 110px 30px minmax(0,1fr) 18px;gap:10px}header nav{gap:8px}h1{font-size:21px}.brand-mark{width:30px;height:30px;font-size:19px}.eyebrow{font-size:7px}.live{font-size:8px;padding:5px 7px}header nav>a{font-size:0}header nav>a:before{content:'↖';font-size:18px}.toolbar{display:grid;grid-template-columns:1fr auto;gap:7px}.segments{grid-column:1/-1}.segments button{flex:1;padding:5px 7px}.toolbar select{max-width:100%;width:100%;min-width:0}.toolbar label{grid-row:3;font-size:10px}#pause{grid-row:3;grid-column:2;padding:3px 8px;height:26px}.metrics{grid-template-columns:1fr 1fr;gap:7px}.metric{padding:7px 11px;border-radius:10px}.metric b{font-size:23px}.metric small{font-size:8px}.metric i{width:28px;height:28px;font-size:16px}#mobileTabs{display:flex;gap:6px}#mobileTabs button{flex:1;padding:5px;font-size:11px;background:none}#mobileTabs button.active{background:#273743;border-color:#486373}.dashboard{display:block;min-height:0}.map-panel,.feed-panel{height:100%}.feed-panel,.bottom{display:none}body[data-mobile="feed"] .map-panel{display:none}body[data-mobile="feed"] .feed-panel{display:grid}body[data-mobile="stats"] .dashboard{display:none}body[data-mobile="stats"] .bottom{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:minmax(80px,1fr) minmax(165px,1fr);grid-row:5}.bottom .chart-panel{grid-column:1/-1}.bottom .panel{padding:10px}.ranking{height:16px}.map-heading{gap:4px}.section-label{font-size:8px}.source-status{max-width:60%;font-size:8px}.status-box{display:none}.map-foot{font-size:8px;align-items:flex-start}.legend{gap:5px;flex-wrap:wrap}#unmapped{max-width:105px;white-space:normal;text-align:right}.credits .natural-credit,.credits .license-credit{display:none}footer{gap:6px;font-size:8px}.footer-help{font-size:8px}.credits{gap:4px!important}} +@media(max-width:760px) and (max-height:700px){body{padding:10px;gap:6px;grid-template-rows:32px auto 78px 26px minmax(0,1fr) 18px}.metric{padding:4px 9px}.metric b{font-size:19px}.metric i{width:24px;height:24px}.eyebrow{font-size:6px}h1{font-size:18px}} +@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important}} + +
PROXMOX / LIVE OBSERVATORY

Traffic space.

+
+
Уникальные IP · 24 ч—
HTTP-запросы · 24 ч—
Срабатывания · 24 ч—
Решения CrowdSec · 24 ч—
+ +
HTTPСрабатываниеРешение
Без геолокации: —
+
+

Ритм запросов / 60 мин

— req/s

География

ТОП 7 / события

Источники

ТОП 7 / IP
+ +

Подробности

diff --git a/traffic_preview_test.go b/traffic_preview_test.go index c5b6d03..0d7960b 100644 --- a/traffic_preview_test.go +++ b/traffic_preview_test.go @@ -45,7 +45,7 @@ func TestTrafficPreview(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/traffic" { w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.Write([]byte(strings.Replace(trafficHTML, "HTTP-запросы и события CrowdSec · последние 24 часа", "ДЕМОНСТРАЦИЯ · искусственные данные для проверки интерфейса", 1))) + w.Write([]byte(strings.Replace(trafficHTML, "PROXMOX / LIVE OBSERVATORY", "ДЕМО / ИСКУССТВЕННЫЕ ДАННЫЕ", 1))) return } mux.ServeHTTP(w, r)