feat(web): дашборд инстанса в настройках с живыми метриками

Вкладка «Инстанс» сверху показывает нагрузку сервера, ниже — диск и базу, внизу
healthcheck с пингом (AGENT.md 7.19).

- `Gauge` — полукруглый индикатор: заполняется по значению, меняет цвет на
  порогах 70 % и 90 %, доступен как `role="meter"`;
- процессор и память обновляются раз в секунду (`useInstanceMetrics`), для
  простоя вкладки опрос останавливается;
- два блока диска: «занято / всего» и вес базы (файл + WAL); видимых подписей
  нет — они раскрываются в тултипе при наведении на значение;
- healthcheck: состояние каждой проверки, общий статус, техническая деталь и
  живой пинг — время ответа инстанса на запрос дашборда в миллисекундах;
- переводы ru/en, тесты на индикаторы, формат «занято / всего», тултипы,
  healthcheck и отсутствие раздела у обычного пользователя.
This commit is contained in:
2026-09-20 21:26:25 +03:00
parent 4c3736b5fb
commit e1107600ec
9 changed files with 715 additions and 2 deletions
@@ -11,10 +11,13 @@ import {
instanceSettingsQueryKey,
instanceUsersQueryKey,
} from '@/api/instance';
import { InstanceDashboard } from '@/components/instance/InstanceDashboard';
import { InstanceHealth } from '@/components/instance/InstanceHealth';
import { ErrorNotice, LoadingNotice } from '@/components/ui/ErrorNotice';
import { Card } from '@/components/ui/primitives';
import { formatDateTime } from '@/lib/identity';
import { useCurrentUser } from '@/lib/hooks';
import { useInstanceMetrics } from '@/lib/useInstanceMetrics';
const AUDIT_LIMIT = 50;
@@ -49,6 +52,8 @@ export default function InstanceSettingsPage() {
enabled: isAdmin,
retry: 0,
});
// Живые метрики: опрос раз в секунду, пока раздел открыт (AGENT.md 7.19).
const metrics = useInstanceMetrics(isAdmin);
if (!isAdmin) {
return (
@@ -69,6 +74,8 @@ export default function InstanceSettingsPage() {
<p className="mt-1 text-sm text-fg-muted">{t('settings.instance.description')}</p>
</header>
<InstanceDashboard state={metrics} />
<Card>
<h3 className="text-base font-semibold">{t('settings.instance.settings')}</h3>
{settings.isPending ? <LoadingNotice /> : null}
@@ -204,6 +211,8 @@ export default function InstanceSettingsPage() {
</ul>
)}
</Card>
<InstanceHealth state={metrics} />
</div>
);
}