Refine ProxyWarden routing and config flows

This commit is contained in:
2026-07-10 21:15:17 +03:00
parent 9fd0a8c0b9
commit dbba3806cc
31 changed files with 1823 additions and 191 deletions
+109
View File
@@ -0,0 +1,109 @@
import type { ProxiFyreSetupProgress, ProxiFyreSetupStatus } from '../../api/tauriCommands';
interface ProxiFyreSetupStripProps {
setupStatus: ProxiFyreSetupStatus | null;
progress: ProxiFyreSetupProgress | null;
}
const SETUP_PLACEHOLDERS: ProxiFyreSetupStatus['items'] = [
{ id: 'vc-runtime', name: 'Среда запуска', installed: false, details: 'Проверяю' },
{ id: 'packet-filter', name: 'Сетевой драйвер', installed: false, details: 'Проверяю' },
{ id: 'proxifyre', name: 'Клиент ProxiFyre', installed: false, details: 'Проверяю' },
];
export function ProxiFyreSetupStrip({ setupStatus, progress }: ProxiFyreSetupStripProps) {
const stripItems = setupStatus?.items ?? SETUP_PLACEHOLDERS;
const visibleProgress = isVisibleProgress(progress) ? progress : null;
const progressTone = visibleProgress?.status === 'failed' ? 'failed' : 'running';
const percent = clampPercent(visibleProgress?.percent ?? 0);
return (
<div
className={`setup-strip ${setupStatus?.ready ? 'ready' : 'attention'} ${visibleProgress ? 'with-progress' : ''}`}
aria-label="Состав ProxiFyre"
>
<span className="setup-strip-title">Состав</span>
<div className="setup-strip-items">
{stripItems.map((item) => (
<div
className={`setup-strip-item ${setupItemClass(item, visibleProgress)}`}
key={item.id}
>
<span className="setup-strip-dot" aria-hidden="true" />
<strong>{setupItemUserName(item.id, item.name)}</strong>
<span>{setupItemShortStatus(item, visibleProgress)}</span>
</div>
))}
</div>
{visibleProgress ? (
<div className={`setup-progress setup-progress--${progressTone}`}>
<div
className="setup-progress-track"
role="progressbar"
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={percent}
aria-label={visibleProgress.message}
>
<span className="setup-progress-fill" style={{ width: `${percent}%` }} />
</div>
<span className="setup-progress-message">{visibleProgress.message}</span>
</div>
) : null}
</div>
);
}
function setupItemClass(
item: ProxiFyreSetupStatus['items'][number],
progress: ProxiFyreSetupProgress | null,
) {
if (progress?.activeStep === item.id) {
if (progress.status === 'failed') return 'failed';
return 'active';
}
if (item.installed) return 'installed';
return 'missing';
}
function setupItemUserName(id: string, fallbackName: string) {
if (id === 'vc-runtime') return 'Среда запуска';
if (id === 'packet-filter') return 'Сетевой драйвер';
if (id === 'proxifyre') return 'Клиент ProxiFyre';
return fallbackName;
}
function setupItemShortStatus(
item: ProxiFyreSetupStatus['items'][number],
progress: ProxiFyreSetupProgress | null,
) {
if (progress?.activeStep === item.id) {
if (progress.status === 'failed') return 'ошибка';
if (progress.status === 'succeeded') return progress.operation === 'uninstall' ? 'удалено' : 'готово';
return 'в процессе';
}
if (item.details === 'Проверяю') return 'проверяю';
if (!item.installed) return progress?.operation === 'uninstall' && progress.status === 'succeeded'
? 'удалено'
: 'нужно установить';
if (item.id === 'proxifyre') return proxifyreSetupServiceSummary(item.version);
return 'готово';
}
function proxifyreSetupServiceSummary(version: string | undefined) {
const normalized = version?.trim().toLowerCase() ?? '';
if (normalized.includes('не установлена')) return 'служба не установлена';
if (normalized.includes('остановлена') || normalized.includes('не запущена')) return 'служба остановлена';
if (normalized.includes('запущена')) return 'служба запущена';
return 'готово';
}
function isVisibleProgress(progress: ProxiFyreSetupProgress | null): progress is ProxiFyreSetupProgress {
if (!progress || progress.status === 'idle') return false;
return progress.status === 'running' || progress.status === 'failed';
}
function clampPercent(value: number) {
if (!Number.isFinite(value)) return 0;
return Math.max(0, Math.min(100, Math.round(value)));
}