diff --git a/src/shared/versions.js b/src/shared/versions.js index 1e93a52..4a767d0 100644 --- a/src/shared/versions.js +++ b/src/shared/versions.js @@ -1,6 +1,6 @@ export const HARBOR_VERSIONS = Object.freeze({ - macClient: '0.18.0', - gatewayClient: '0.19.0', + macClient: '0.18.1', + gatewayClient: '0.19.1', gatewayBackend: '0.19.0', }); diff --git a/src/web/components/ClientOverviewPage.jsx b/src/web/components/ClientOverviewPage.jsx index f088127..2b19323 100644 --- a/src/web/components/ClientOverviewPage.jsx +++ b/src/web/components/ClientOverviewPage.jsx @@ -1338,31 +1338,6 @@ export function ClientOverviewPage({ }
- {isGateway &&
- Сейчас -

- {appliedServer?.label || 'VPN-сервер не используется'} -

-
- {switchingServer && Переключаем на {desiredServer.label}} -
-
- Учтено Harbor - {formatByteString(globalTraffic?.totalBytes || '0')} -
-
- -
-
- {trafficSourceError - ? `Трафик не обновляется · последние данные ${trafficFreshness}` - : globalTraffic?.observedAt ? `Обновлено ${trafficFreshness}` : 'Ожидаем первые данные трафика'} -
-
} {showPower && (
{isGateway ? + {isGateway &&
+ Сейчас + + {appliedServer?.label || 'VPN-сервер не используется'} + +
+ {switchingServer && Переключаем на {desiredServer.label}} +
+
}
{connected ? (
+ {isGateway &&
+
+ Учтено Harbor + {formatByteString(globalTraffic?.totalBytes || '0')} +
+
+ +
+
+ {trafficSourceError + ? `Трафик не обновляется · последние данные ${trafficFreshness}` + : globalTraffic?.observedAt ? `Обновлено ${trafficFreshness}` : 'Ожидаем первые данные трафика'} +
+
} +
{!isGateway && ( diff --git a/src/web/styles.css b/src/web/styles.css index 52a35ee..26389cb 100644 --- a/src/web/styles.css +++ b/src/web/styles.css @@ -2616,15 +2616,10 @@ p { } .client-gateway-summary { - grid-column: 1; - align-self: center; - justify-self: end; - width: min(360px, 100%); + width: min(300px, 100%); display: grid; - gap: 8px; - padding-right: clamp(20px, 4vw, 64px); - text-align: left; - animation: client-power-arrive 850ms cubic-bezier(0.16, 1, 0.3, 1) both; + gap: 6px; + text-align: center; } .client-gateway-summary-kicker, @@ -2636,22 +2631,34 @@ p { text-transform: uppercase; } -.client-gateway-summary h2 { - min-height: 29px; - margin: 0; +.client-gateway-route-summary { + min-height: 54px; + display: grid; + justify-items: center; + gap: 2px; + margin-top: 6px; +} + +.client-gateway-route-summary strong { + max-width: min(300px, 100%); + min-height: 20px; overflow: hidden; color: var(--client-text); - font-size: 22px; - letter-spacing: -0.045em; + font-size: 15px; + letter-spacing: -0.035em; text-overflow: ellipsis; white-space: nowrap; } .client-gateway-route-slot { - min-height: 18px; + width: 100%; + min-height: 16px; + overflow: hidden; color: var(--client-accent); font-size: 9px; font-weight: 700; + text-overflow: ellipsis; + white-space: nowrap; } .client-gateway-traffic-heading { @@ -2659,7 +2666,6 @@ p { align-items: baseline; justify-content: space-between; gap: 12px; - margin-top: 10px; } .client-gateway-traffic-heading strong { @@ -2671,18 +2677,18 @@ p { .client-gateway-traffic-chart { width: 100%; - min-height: 118px; + min-height: 88px; } .client-gateway-traffic-chart .client-device-traffic-chart { grid-column: auto; grid-row: auto; width: 100%; - height: 118px; + height: 88px; } .client-gateway-traffic-freshness { - min-height: 28px; + min-height: 26px; color: var(--client-muted); font-size: 8.5px; line-height: 1.5; @@ -2764,6 +2770,10 @@ p { min-height: 76px; } +.client-panel.is-gateway-home .client-state-copy { + min-height: 136px; +} + .client-power-control { width: 96px; height: 96px; @@ -4532,7 +4542,6 @@ p { } .client-power-section, - .client-gateway-summary, .client-form, .client-panel.is-setup .client-form { grid-column: 1; @@ -4544,12 +4553,6 @@ p { order: 1; } - .client-gateway-summary { - order: 2; - justify-self: center; - padding-right: 0; - } - .client-form { height: auto; max-height: none; @@ -5176,7 +5179,6 @@ p { .client-subscription-refresh, .client-subscription-delete, .client-power-section, - .client-gateway-summary, .client-gateway-traffic-chart, .client-gateway-traffic-freshness, .client-subscription-drawer, diff --git a/test/web/device-inventory-contract.test.js b/test/web/device-inventory-contract.test.js index e66b855..04ac22a 100644 --- a/test/web/device-inventory-contract.test.js +++ b/test/web/device-inventory-contract.test.js @@ -171,6 +171,7 @@ test('Gateway Home reuses the canonical device snapshot for applied route and gl assert.match(overview, /selectedServerId !== appliedServerId[\s\S]*Переключаем на \{desiredServer\.label\}/); assert.match(overview, /formatByteString\(globalTraffic\?\.totalBytes \|\| '0'\)/); assert.match(overview, /samples=\{globalTraffic\?\.history \|\| \[\]\}[\s\S]*capacity=\{deviceSnapshot\?\.trafficHistoryCapacity \|\| 120\}[\s\S]*routeLabel="Gateway"/); + assert.match(overview, /
assert.match(styles, /\.client-panel\.has-subscription \{[\s\S]*transform:\s*translateY\(-9vh\)/); assert.match(styles, /\.client-panel\.has-subscription \.client-power-section \{[\s\S]*height:\s*var\(--client-work-height\);[\s\S]*padding-top:\s*var\(--client-power-top\)/); assert.match(styles, /\.client-panel\.has-subscription \.client-form-content \{[\s\S]*padding-top:\s*var\(--client-power-top\)/); - assert.match(rule('.client-gateway-summary'), /grid-column:\s*1/); - assert.match(rule('.client-gateway-summary'), /justify-self:\s*end/); + assert.match(rule('.client-gateway-summary'), /width:\s*min\(300px, 100%\)/); + assert.doesNotMatch(rule('.client-gateway-summary'), /grid-column|justify-self|padding-right/); + assert.match(rule('.client-gateway-route-slot'), /min-height:\s*16px[\s\S]*overflow:\s*hidden[\s\S]*text-overflow:\s*ellipsis[\s\S]*white-space:\s*nowrap/); assert.match(component, /client-panel\$\{showPower \? '' : ' is-setup'\}[\s\S]*is-gateway-home/); assert.match(component, /const showPower = isGateway \|\| \(hasSubscription && Boolean\(selectedServerId\)\)/); }); @@ -72,9 +73,8 @@ test('tablet and mobile regions use normal flow with viewport-safe widths', () = assert.match(responsive, /grid-template-columns:\s*minmax\(0, 1fr\)/); assert.match(responsive, /\.client-power-section,[\s\S]*\.client-form,[\s\S]*grid-column:\s*1/); - assert.match(responsive, /\.client-gateway-summary/); assert.match(responsive, /\.client-power-section \{[\s\S]*order:\s*1/); - assert.match(responsive, /\.client-gateway-summary \{[\s\S]*order:\s*2/); + assert.doesNotMatch(responsive, /\.client-gateway-summary/); assert.match(responsive, /width:\s*min\(100%, 380px\)/); assert.match(responsive, /max-height:\s*none/); assert.match(responsive, /overflow-y:\s*visible/);