Update VPN proxy client behavior
Build and Deploy Gateway / build-and-push (push) Successful in 18s
Build and Deploy Gateway / deploy (push) Successful in 13s

This commit is contained in:
2026-08-09 11:55:02 +03:00
parent 71ede44be0
commit 90433d7cd8
27 changed files with 770 additions and 254 deletions
@@ -413,35 +413,40 @@ export function SubscriptionPanel({ feature, statusSlot, serverSlot }: Subscript
inert={editing ? true : undefined}
>
<div className="client-subscription-heading">
<span className="client-subscription-label">Ваша подписка</span>
<span className="client-icon-tooltip client-tooltip-anchor">
<button
className="client-subscription-refresh"
type="button"
aria-label="Обновить подписку"
disabled={refreshing || refreshBlocked}
onClick={feature.refresh}
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M21 12a9 9 0 0 0-15.2-6.5L3 8m0-5v5h5M3 12a9 9 0 0 0 15.2 6.5L21 16m0 5v-5h-5" />
</svg>
</button>
<CloudTooltip>Обновить подписку</CloudTooltip>
<span className="client-subscription-status">
<i aria-hidden="true" />
Сохранена
</span>
<span className="client-icon-tooltip client-tooltip-anchor">
<button
className="client-subscription-delete"
type="button"
aria-label="Удалить подписку"
disabled={deleteBlocked}
onClick={feature.requestDelete}
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path className="client-trash-lid" d="M4 7h16M9 7V4h6v3" />
<path d="m6 7 1 13h10l1-13M10 11v5M14 11v5" />
</svg>
</button>
<CloudTooltip>Удалить подписку</CloudTooltip>
<span className="client-subscription-actions">
<span className="client-icon-tooltip client-tooltip-anchor">
<button
className="client-subscription-refresh"
type="button"
aria-label="Обновить подписку"
disabled={refreshing || refreshBlocked}
onClick={feature.refresh}
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M21 12a9 9 0 0 0-15.2-6.5L3 8m0-5v5h5M3 12a9 9 0 0 0 15.2 6.5L21 16m0 5v-5h-5" />
</svg>
</button>
<CloudTooltip>Обновить подписку</CloudTooltip>
</span>
<span className="client-icon-tooltip client-tooltip-anchor">
<button
className="client-subscription-delete"
type="button"
aria-label="Удалить подписку"
disabled={deleteBlocked}
onClick={feature.requestDelete}
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path className="client-trash-lid" d="M4 7h16M9 7V4h6v3" />
<path d="m6 7 1 13h10l1-13M10 11v5M14 11v5" />
</svg>
</button>
<CloudTooltip>Удалить подписку</CloudTooltip>
</span>
</span>
</div>
<button
@@ -450,6 +455,7 @@ export function SubscriptionPanel({ feature, statusSlot, serverSlot }: Subscript
tabIndex={editing ? -1 : 0}
onClick={feature.edit}
>
<span className="client-subscription-label">Подписка</span>
<strong>{subscriptionDomain(subscription?.host)}</strong>
</button>
</div>
@@ -508,11 +514,13 @@ export function SubscriptionPanel({ feature, statusSlot, serverSlot }: Subscript
{hasSubscription && contentReady && hasUsage && (
<section className={`client-usage${usageUpdated ? ' is-updated' : ''}`} aria-label="Статистика подписки">
<span>Использовано</span>
<strong>
{formatBytes(displayedUsed)}
<small> / {usage.total ? formatBytes(usage.total) : 'без лимита'}</small>
</strong>
<div className="client-usage-summary">
<span>Использовано</span>
<strong>
{formatBytes(displayedUsed)}
<small> из {usage.total ? formatBytes(usage.total) : 'без лимита'}</small>
</strong>
</div>
{usage.percent !== null && (
<div
className="client-usage-bar"
@@ -527,10 +535,11 @@ export function SubscriptionPanel({ feature, statusSlot, serverSlot }: Subscript
)}
<div className="client-usage-details">
{usage.expiresAt && !Number.isNaN(usage.expiresAt.getTime()) && (
<span>
до {usage.expiresAt.toLocaleDateString('ru-RU', { day: 'numeric', month: 'long' })}
{' · '}{subscriptionDaysLeft(usage.expiresAt)}
</span>
<>
<span>Действует до</span>
<strong>{usage.expiresAt.toLocaleDateString('ru-RU', { day: 'numeric', month: 'long' })}</strong>
<small>{subscriptionDaysLeft(usage.expiresAt)}</small>
</>
)}
</div>
</section>