diff --git a/apps/web/src/components/health-check-config-fields.tsx b/apps/web/src/components/health-check-config-fields.tsx index bd2cd78..cbe63aa 100644 --- a/apps/web/src/components/health-check-config-fields.tsx +++ b/apps/web/src/components/health-check-config-fields.tsx @@ -19,8 +19,6 @@ import { import { Switch } from '@cfdm/ui/components/switch' import { FieldGroup } from '@cfdm/ui/components/field' import { ToggleGroup, ToggleGroupItem } from '@cfdm/ui/components/toggle-group' -import { Link } from '@tanstack/react-router' -import { Alert, AlertDescription, AlertTitle } from '@/components/reui/alert' import { cn } from '@cfdm/ui/lib/utils' import { HealthAggregateTiles, @@ -123,9 +121,6 @@ export function HealthCheckConfigFields({ const aggregate = value.aggregate ?? 'majority' const isHttp = value.type === 'http' const rowClass = 'gap-3 px-0 py-3' - const hasCloudflare = providers.includes('cloudflare') - const hasGlobalping = providers.includes('globalping') - const hasLocal = providers.includes('local') return ( @@ -163,6 +158,7 @@ export function HealthCheckConfigFields({ compact stacked className={rowClass} + contentClassName="min-w-0" > - {hasCloudflare ? ( - - Cloudflare Worker - - Проба с edge Cloudflare, не продукт Health Checks API (на Free его нет). - Worker создаётся автоматически и сам опрашивает IP (KV mailbox). - Статус деплоя — в{' '} - - Настройках → Health-check - - . Если Worker не создан, этот источник не пробируется как Local. - - - ) : null} - {hasGlobalping ? ( - - Globalping - - Пробы из сети globalping.io (TCP ping / HTTP). Токен, локации и лимит — - в{' '} - - Настройках → Health-check - - . Без токена или при 429 этот источник = fail, без fallback на Local. - - - ) : null} - {hasLocal ? ( - - Local health-check - - Проба TCP/HTTP с сервера API. Cron и пороги Slow/Down — в{' '} - - Настройках → Health-check - - . Интервал в карточке не используется. - - - ) : null} - {providers.length > 1 ? ( { const picked = next[0] diff --git a/apps/web/src/components/reui-kit/health-source-tiles.tsx b/apps/web/src/components/reui-kit/health-source-tiles.tsx index 5712ccc..47e22d1 100644 --- a/apps/web/src/components/reui-kit/health-source-tiles.tsx +++ b/apps/web/src/components/reui-kit/health-source-tiles.tsx @@ -1,16 +1,45 @@ import type { KeyboardEvent, ReactNode } from 'react' -import { CheckIcon, GlobeIcon, ServerIcon, CloudIcon, LayersIcon, ShieldAlertIcon, ScaleIcon } from 'lucide-react' +import { CheckIcon, ServerIcon, LayersIcon, ShieldAlertIcon, ScaleIcon } from 'lucide-react' import { Frame, FramePanel } from '@/components/reui/frame' import { IconTile } from '@/components/reui/icon-tile' import { cn } from '@cfdm/ui/lib/utils' import type { HealthCheckAggregate, HealthCheckProvider } from '@cfdm/shared' +import { kpiCols } from './kpi-cols' export type HealthProvider = HealthCheckProvider export type HealthAggregate = HealthCheckAggregate const DEFAULT_ICON_CLASS = 'text-muted-foreground [&_svg]:text-current' +/** Official Cloudflare mark (Simple Icons). */ +function CloudflareMark() { + return ( + + ) +} + +/** Official Globalping mark (globalping.io favicon). */ +function GlobalpingMark() { + return ( + + ) +} + const PROVIDER_ITEMS: Array<{ id: HealthProvider title: string @@ -29,14 +58,14 @@ const PROVIDER_ITEMS: Array<{ id: 'cloudflare', title: 'Cloudflare', description: 'Worker на edge, KV mailbox', - icon: , + icon: , iconClassName: 'text-warning [&_svg]:text-current', }, { id: 'globalping', title: 'Globalping', description: 'Пробы из сети globalping.io', - icon: , + icon: , iconClassName: 'text-success [&_svg]:text-current', }, ] @@ -98,38 +127,48 @@ function TilePanel({ aria-pressed={selected} tabIndex={0} className={cn( - 'relative isolate flex h-full cursor-pointer flex-col p-3 transition-colors', + 'relative isolate flex min-w-0 cursor-pointer flex-col p-3 transition-colors', 'hover:bg-muted/40 focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none', selected && 'ring-ring ring-1', )} onClick={onActivate} onKeyDown={(event) => handleTileKeyDown(onActivate, event)} > -
+
-
- {title} +
+ {title} {selected ? ( ) : null}
-

{description}

+

+ {description} +

) } +function TileGrid({ children, count }: { children: ReactNode; count: number }) { + return ( + +
{children}
+ + ) +} + /** * Мультивыбор источников проб (Local / Cloudflare / Globalping). - * Preview: https://reui.io/preview/base/card-12 + * Preview: https://reui.io/preview/base/card-12 · https://reui.io/preview/base/stats-12 * Docs: https://reui.io/docs/components/base/frame · https://reui.io/docs/components/base/icon-tile */ export function HealthSourceTiles({ @@ -151,22 +190,20 @@ export function HealthSourceTiles({ } return ( - -
- {PROVIDER_ITEMS.map((item) => ( - toggle(item.id)} - /> - ))} -
- + + {PROVIDER_ITEMS.map((item) => ( + toggle(item.id)} + /> + ))} + ) } @@ -183,20 +220,18 @@ export function HealthAggregateTiles({ }) { const selected = value || 'majority' return ( - -
- {AGGREGATE_ITEMS.map((item) => ( - onChange(item.id)} - /> - ))} -
- + + {AGGREGATE_ITEMS.map((item) => ( + onChange(item.id)} + /> + ))} + ) } diff --git a/apps/web/src/components/setting-row.tsx b/apps/web/src/components/setting-row.tsx index c8db255..04c433b 100644 --- a/apps/web/src/components/setting-row.tsx +++ b/apps/web/src/components/setting-row.tsx @@ -73,7 +73,7 @@ export function SettingRow({ >