Refine failover channel status layout
Build and Deploy Gateway / build-and-push (push) Successful in 43s
Build and Deploy Gateway / deploy (push) Successful in 6s

This commit is contained in:
2026-08-31 14:52:36 +03:00
parent 3c2eefe108
commit e0bdafd25e
7 changed files with 47 additions and 36 deletions
+11 -6
View File
@@ -482,6 +482,9 @@ export function FailoverPanel({
const selectedId = channelOptions.find(({ target }) => (
target.profileId === draft[channel].profileId && target.serverId === draft[channel].serverId
))?.id || '';
const failureProgress = !checking && channel === 'primary' && snapshot.reason === 'failure-window'
? `${seconds(Math.max(0, Date.now() - Date.parse(snapshot.primary.stateSince || new Date().toISOString())))} / ${seconds(draft.failureWindowMs)} с`
: '';
const healthLabel = missing
? 'Сервер не найден'
: !draft.enabled
@@ -490,15 +493,20 @@ export function FailoverPanel({
? 'VPN выключен'
: snapshot.activation === 'pending'
? 'Проверим после запуска VPN'
: channel === 'primary' && snapshot.reason === 'failure-window'
? `Проверяем основной канал · ${seconds(Math.max(0, Date.now() - Date.parse(snapshot.primary.stateSince || new Date().toISOString())))} из ${seconds(draft.failureWindowMs)} с`
: checking
? `Проверяем ${channel === 'primary' ? 'основной' : 'резервный'} канал`
: failureProgress
? 'Проверяем основной канал'
: channel === 'primary' && snapshot.currentRole === 'reserve' && health === 'healthy' && snapshot.reason === 'recovery-hold'
? 'Проверяем восстановление'
: health === 'healthy' ? 'Работает' : health === 'unhealthy' ? 'Недоступен' : health === 'not-monitoring' ? 'Проверка выключена' : 'Ждёт проверки';
return <div className="client-failover-channel-slot" key={channel}><article className="client-failover-channel" data-channel={channel}>
<div className="client-failover-channel-title">
<h3>{channel === 'primary' ? 'Основной' : 'Резервный'}</h3>
<strong className={health === 'healthy' ? 'is-healthy' : health === 'unhealthy' || missing ? 'is-unhealthy' : ''}>{healthLabel}</strong>
</div>
<div className="client-failover-channel-status">
<strong className={healthLabel === 'Работает' ? 'is-healthy' : healthLabel === 'Недоступен' || missing ? 'is-unhealthy' : ''}>{healthLabel}</strong>
<span className="client-failover-channel-progress">{failureProgress}</span>
</div>
<FailoverPicker
id={`client-failover-${channel}-options`}
@@ -510,9 +518,6 @@ export function FailoverPanel({
onOpenChange={(open) => setOpenPicker(open ? channel : '')}
onChange={(optionId) => updateTarget(channel, optionId)}
/>
<span className={`client-failover-channel-checking${checking ? ' is-visible' : ''}`} aria-hidden="true">
Проверяем {channel === 'primary' ? 'основной' : 'резервный'} канал
</span>
</article>{channel === 'primary' && <div className="client-failover-channel-actions" aria-label="Действия с каналами">
<button
className={`client-failover-check-action client-tooltip-anchor${checking ? ' is-running' : ''}`}