From d349ca5e29f6850debe833523a46a0e4417d45b9 Mon Sep 17 00:00:00 2001 From: Dmitriy Petrov Date: Sun, 9 Aug 2026 14:37:11 +0300 Subject: [PATCH] Improve gateway traffic dashboard and connection branding --- monitoring/grafana/harbor-gateway.json | 119 ++++++++++++++---- src/shared/versions.ts | 4 +- src/web/components/ClientOverviewPage.tsx | 16 +-- .../features/connection/ConnectionPanel.tsx | 13 +- src/web/styles/features/connection.css | 26 +++- src/web/styles/layout.css | 30 +++-- test/web/connection-panel-contract.test.js | 5 +- test/web/device-inventory-contract.test.js | 4 +- test/web/prometheus-instructions.test.js | 47 +++++-- test/web/responsive-layout-contract.test.js | 8 +- test/web/style-boundaries.test.js | 22 ++-- 11 files changed, 208 insertions(+), 86 deletions(-) diff --git a/monitoring/grafana/harbor-gateway.json b/monitoring/grafana/harbor-gateway.json index 7730d48..f9b762c 100644 --- a/monitoring/grafana/harbor-gateway.json +++ b/monitoring/grafana/harbor-gateway.json @@ -37,7 +37,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "Сколько секунд прошло с последнего успешного обновления. До 60 секунд — штатно, 60–119 — задержка, от 120 — данные устарели.", + "description": "Сколько секунд прошло с последнего успешного обновления к концу выбранного периода. До 60 секунд — штатно, 60–119 — задержка, от 120 — данные устарели.", "fieldConfig": { "defaults": { "color": { @@ -106,7 +106,7 @@ "refId": "B" } ], - "title": "Свежесть данных сейчас", + "title": "Свежесть данных в конце выбранного периода", "type": "stat" }, { @@ -114,18 +114,24 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "Текущая суммарная скорость всех устройств, сглаженная за последние 5 минут.", + "description": "Суммарная скорость всех устройств в выбранном периоде. Окно усреднения автоматически адаптируется к масштабу времени; скачивание показано вверх, отправка — вниз.", "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": true, "drawStyle": "line", "fillOpacity": 10, "lineInterpolation": "smooth", "lineWidth": 2, "pointSize": 4, + "scaleDistribution": { + "linearThreshold": 1048576, + "log": 2, + "type": "symlog" + }, "showPoints": "never", "spanNulls": false, "stacking": { @@ -167,6 +173,18 @@ } } ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] } ] }, @@ -195,20 +213,20 @@ "targets": [ { "editorMode": "code", - "expr": "sum(rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"download\"}[5m])) > 0", + "expr": "sum(rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"download\"}[$__rate_interval])) > 0", "legendFormat": "Скачивание", "range": true, "refId": "A" }, { "editorMode": "code", - "expr": "sum(rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"upload\"}[5m])) > 0", + "expr": "sum(rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"upload\"}[$__rate_interval])) > 0", "legendFormat": "Отправка", "range": true, "refId": "B" } ], - "title": "Скорость сейчас, средняя за 5 минут", + "title": "Скорость за выбранный период", "type": "timeseries" }, { @@ -345,13 +363,14 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "Суммарная скорость Gateway/Proxy и upload/download для каждого активного устройства из фильтра, средняя за последние 5 минут. Нулевые устройства скрыты.", + "description": "Скорость скачивания и отправки каждого активного устройства в выбранном периоде. Окно усреднения адаптируется к масштабу времени; скачивание показано вверх, отправка — вниз. Нулевые series скрыты.", "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": true, "drawStyle": "line", "fillOpacity": 6, "lineInterpolation": "smooth", @@ -373,7 +392,20 @@ "noValue": "Нет активного трафика", "unit": "Bps" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] }, "gridPos": { "h": 9, @@ -401,13 +433,20 @@ "targets": [ { "editorMode": "code", - "expr": "(sum by (device_id) (rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\"}[5m])) > 0) * on (device_id) group_left (name, ip) max by (device_id, name, ip) (harbor_device_info)", - "legendFormat": "{{name}} · {{ip}}", + "expr": "(sum by (device_id) (rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"download\"}[$__rate_interval])) > 0) * on (device_id) group_left (name, ip) max by (device_id, name, ip) (harbor_device_info)", + "legendFormat": "{{name}} · {{ip}} · скачивание", "range": true, "refId": "A" + }, + { + "editorMode": "code", + "expr": "(sum by (device_id) (rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"upload\"}[$__rate_interval])) > 0) * on (device_id) group_left (name, ip) max by (device_id, name, ip) (harbor_device_info)", + "legendFormat": "{{name}} · {{ip}} · отправка", + "range": true, + "refId": "B" } ], - "title": "Скорость по устройствам сейчас", + "title": "Скорость по устройствам", "type": "timeseries" }, { @@ -415,18 +454,24 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "Скорость выбранного scope по Gateway/Proxy и upload/download, средняя за последние 5 минут. При выборе «Все устройства» остаётся максимум четыре суммарные series; нулевые series скрыты.", + "description": "Скорость выбранного scope по Gateway/Proxy и направлениям в выбранном периоде. Окно усреднения адаптируется к масштабу времени; скачивание показано вверх, отправка — вниз. Нулевые series скрыты.", "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": true, "drawStyle": "line", "fillOpacity": 8, "lineInterpolation": "smooth", "lineWidth": 2, "pointSize": 4, + "scaleDistribution": { + "linearThreshold": 1048576, + "log": 2, + "type": "symlog" + }, "showPoints": "never", "spanNulls": false, "stacking": { @@ -438,7 +483,20 @@ "noValue": "Нет данных за период", "unit": "Bps" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] }, "gridPos": { "h": 9, @@ -466,13 +524,20 @@ "targets": [ { "editorMode": "code", - "expr": "sum by (source, direction) (rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\"}[5m])) > 0", - "legendFormat": "{{source}} · {{direction}}", + "expr": "sum by (source) (rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"download\"}[$__rate_interval])) > 0", + "legendFormat": "{{source}} · скачивание", "range": true, "refId": "A" + }, + { + "editorMode": "code", + "expr": "sum by (source) (rate(harbor_device_traffic_bytes_total{device_id=~\"$device_id\", direction=\"upload\"}[$__rate_interval])) > 0", + "legendFormat": "{{source}} · отправка", + "range": true, + "refId": "B" } ], - "title": "Скорость по источникам и направлениям сейчас", + "title": "Скорость по источникам и направлениям", "type": "timeseries" }, { @@ -480,7 +545,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "Накопленные счётчики выбранного scope за всё время хранения Harbor. При «Все устройства» счётчики суммируются; нулевые series скрыты.", + "description": "Трафик выбранного scope в текущем диапазоне времени. При «Все устройства» значения суммируются; нулевые series скрыты.", "fieldConfig": { "defaults": { "color": { @@ -520,14 +585,14 @@ "targets": [ { "editorMode": "code", - "expr": "sum by (source, direction) (harbor_device_traffic_bytes_total{device_id=~\"$device_id\"}) > 0", + "expr": "sum by (source, direction) (increase(harbor_device_traffic_bytes_total{device_id=~\"$device_id\"}[$__range])) > 0", "instant": true, "legendFormat": "{{source}} · {{direction}}", "range": false, "refId": "A" } ], - "title": "Накоплено по источникам и направлениям", + "title": "Трафик по источникам и направлениям за выбранный период", "type": "bargauge" }, { @@ -700,7 +765,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "Накопленный объём всех счётчиков Harbor за всё время хранения.", + "description": "Объём всех счётчиков Harbor в выбранном диапазоне времени.", "fieldConfig": { "defaults": { "color": { @@ -737,14 +802,14 @@ "targets": [ { "editorMode": "code", - "expr": "sum(harbor_traffic_bytes_total)", + "expr": "sum(increase(harbor_traffic_bytes_total[$__range]))", "instant": true, "legendFormat": "Учтено Harbor", "range": false, "refId": "A" } ], - "title": "Накоплено: весь Harbor", + "title": "Весь Harbor за выбранный период", "type": "stat" }, { @@ -752,7 +817,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "Накопленные счётчики за всё время хранения отдельно для Gateway и Proxy.", + "description": "Объём трафика Gateway и Proxy в выбранном диапазоне времени.", "fieldConfig": { "defaults": { "color": { @@ -823,14 +888,14 @@ "targets": [ { "editorMode": "code", - "expr": "sum by (source) (harbor_traffic_bytes_total) > 0", + "expr": "sum by (source) (increase(harbor_traffic_bytes_total[$__range])) > 0", "instant": true, "legendFormat": "{{source}}", "range": false, "refId": "A" } ], - "title": "Накоплено: источники", + "title": "Источники за выбранный период", "type": "bargauge" } ], @@ -866,7 +931,7 @@ "query": "query_result(label_join(max by (device_id, name, ip) (harbor_device_info), \"display\", \" · \", \"name\", \"ip\"))", "refId": "PrometheusVariableQueryEditor-VariableQuery" }, - "refresh": 1, + "refresh": 2, "regex": "/display=\"(?[^\"]+)\"|device_id=\"(?[^\"]+)\"/g", "skipUrlSync": false, "sort": 1, @@ -891,6 +956,6 @@ "timezone": "browser", "title": "Harbor Gateway: трафик", "uid": "harbor-gateway-traffic", - "version": 6, + "version": 7, "weekStart": "monday" } diff --git a/src/shared/versions.ts b/src/shared/versions.ts index cf6fabb..10ecf0f 100644 --- a/src/shared/versions.ts +++ b/src/shared/versions.ts @@ -1,6 +1,6 @@ export const HARBOR_VERSIONS = Object.freeze({ - macClient: '0.21.5', - gatewayClient: '0.22.0', + macClient: '0.21.6', + gatewayClient: '0.22.1', gatewayBackend: '0.22.5', }); diff --git a/src/web/components/ClientOverviewPage.tsx b/src/web/components/ClientOverviewPage.tsx index 2593904..00355ab 100644 --- a/src/web/components/ClientOverviewPage.tsx +++ b/src/web/components/ClientOverviewPage.tsx @@ -537,14 +537,6 @@ export function ClientOverviewPage({
{copyAnnouncement.text}
- {(isGateway || (hasSubscription && subscriptionContentReady)) &&