From 3b79d834cdae3c49caf62612aa323efeb04931b5 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 23 Oct 2026 22:36:49 +0700 Subject: [PATCH] feat(web): dashboard as on the shared mockup board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Панель переписана по доске BgpDashboard: действия в шапке, KPI-полоса, вкладка «Обзор», быстрые действия карточками, график префиксов по последним ревизиям, таблица модулей и лента активности. Графики загрузки BGP и потока операций убраны с панели — они живут в «Сети» и «Мониторинге». Co-Authored-By: Claude Sonnet 5.5 --- .../dashboard/dashboard-prefix-trend.tsx | 55 ++++++++ apps/web/src/routes/_auth/dashboard.tsx | 120 +++++++++++------- apps/web/tsconfig.tsbuildinfo | 2 +- 3 files changed, 130 insertions(+), 47 deletions(-) create mode 100644 apps/web/src/components/dashboard/dashboard-prefix-trend.tsx diff --git a/apps/web/src/components/dashboard/dashboard-prefix-trend.tsx b/apps/web/src/components/dashboard/dashboard-prefix-trend.tsx new file mode 100644 index 0000000..c8a3f19 --- /dev/null +++ b/apps/web/src/components/dashboard/dashboard-prefix-trend.tsx @@ -0,0 +1,55 @@ +import { useMemo } from 'react' +import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts' + +import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from '@evobgp/ui/components/chart' +import { Frame, FrameDescription, FrameHeader, FramePanel, FrameTitle } from '@/components/reui/frame' +import { fmtWhen } from '@/components/portal/format' +import type { RevisionRow } from '@/types/api' + +const chartConfig = { + prefixes: { label: 'Префиксов', color: 'var(--chart-1)' }, +} satisfies ChartConfig + +/** Префиксов в опубликованной конфигурации по последним ревизиям (доска «Панель»). */ +export function DashboardPrefixTrend({ revisions, loading }: { revisions: RevisionRow[]; loading?: boolean }) { + const data = useMemo( + () => + [...revisions] + .sort((a, b) => a.created_at.localeCompare(b.created_at)) + .slice(-12) + .map((r) => ({ id: r.id, when: fmtWhen(r.created_at), prefixes: r.materialized_prefix_count })), + [revisions], + ) + + return ( + + + Префиксов в опубликованной конфигурации + Последние {data.length || 12} ревизий + + + {data.length < 2 ? ( +
+ {loading ? 'Загрузка…' : 'Недостаточно ревизий для графика'} +
+ ) : ( + + + + + + + + + + + [Math.floor(min * 0.98), Math.ceil(max * 1.01)]} tickLine={false} axisLine={false} width={48} tickFormatter={(v: number) => v.toLocaleString('ru-RU')} /> + p?.[0]?.payload?.when ?? ''} />} /> + + + + )} +
+ + ) +} diff --git a/apps/web/src/routes/_auth/dashboard.tsx b/apps/web/src/routes/_auth/dashboard.tsx index 2920043..e61b43e 100644 --- a/apps/web/src/routes/_auth/dashboard.tsx +++ b/apps/web/src/routes/_auth/dashboard.tsx @@ -1,24 +1,28 @@ import { createFileRoute } from '@tanstack/react-router' import { useQueries, useQuery } from '@tanstack/react-query' -import { RefreshCw } from 'lucide-react' +import { Boxes, Play, RefreshCw, Search, Share2 } from 'lucide-react' +import { useNavigate } from '@tanstack/react-router' import { useState } from 'react' import { Button } from '@evobgp/ui/components/button' import { buildDashboardKpiCards } from '@/components/dashboard/dashboard-kpi-grid' -import { DashboardNetworkHealth } from '@/components/dashboard/dashboard-network-health' -import { DashboardOperationsBreakdown } from '@/components/dashboard/dashboard-operations-breakdown' -import { DashboardQuickLinks } from '@/components/dashboard/dashboard-quick-links' +import { DashboardPrefixTrend } from '@/components/dashboard/dashboard-prefix-trend' import { ModulesListGrid } from '@/components/modules/modules-list-grid' import { ActivityFeed } from '@/components/portal/canvas-blocks' import { fmtWhen } from '@/components/portal/format' import type { Tone } from '@/components/portal/tone' -import { OpsDashboard } from '@/components/reui-kit' -import { chartPanelGridClassName } from '@/lib/ui-surface' +import { KpiStatGrid } from '@/components/reui-kit' +import { PageHeader } from '@/components/page-header' +import { PageTab, PageTabsList } from '@/components/portal/bits' +import { AppCards, type AppCardItem } from '@/components/portal/canvas-blocks' +import { Skeleton } from '@evobgp/ui/components/skeleton' +import { Tabs, TabsContent } from '@evobgp/ui/components/tabs' import { overviewJobsQueryOptions, overviewModulesQueryOptions, overviewPeersQueryOptions, + overviewRevisionsQueryOptions, overviewSpeakersQueryOptions, } from '@/queries/overview' import { settingsQueryOptions } from '@/queries/settings' @@ -41,6 +45,7 @@ function parseShowQuickActions(value: unknown): boolean { * @see https://reui.io/preview/base/chart-27 */ function DashboardComponent() { + const navigate = useNavigate() const [lastUpdated, setLastUpdated] = useState(null) const settingsQ = useQuery(settingsQueryOptions()) const showQuickActions = parseShowQuickActions(settingsQ.data?.ui_show_quick_actions) @@ -54,6 +59,7 @@ function DashboardComponent() { ], }) + const revisionsQ = useQuery(overviewRevisionsQueryOptions()) const [modulesQ, peersQ, speakersQ, jobsQ] = results const initialLoading = modulesQ.isLoading || peersQ.isLoading || speakersQ.isLoading || jobsQ.isLoading @@ -78,7 +84,7 @@ function DashboardComponent() { const running = j.status === 'running' || j.status === 'queued' const tone: Tone = failed ? 'er' : running ? 'in' : 'ok' return { - t: fmtWhen(j.finished_at ?? j.started_at ?? j.created_at), + t: fmtWhen(j.finished_at ?? j.started_at ?? j.created_at).replace(/^сегодня /, ''), title: j.kind, text: j.error ?? `Статус: ${j.status}`, label: failed ? 'Error' : running ? 'Running' : 'Info', @@ -86,48 +92,70 @@ function DashboardComponent() { } }) + const quickActions: AppCardItem[] = [ + { id: 'new-module', title: 'Создать модуль', desc: 'AS, CDN, домены или IP-диапазоны', badge: 'Модули', meta: '', icon: , onSelect: () => void navigate({ to: '/modules', search: { create: true } }) }, + { id: 'lookup', title: 'Проверить IP или домен', desc: 'Есть ли адрес в списках и community', badge: 'Проверка', meta: '', icon: , onSelect: () => void navigate({ to: '/lookup', search: { q: '' } }) }, + { id: 'add-peer', title: 'Добавить пира', desc: 'Новый BGP-сосед на спикере', badge: 'Сеть', meta: '', icon: , onSelect: () => void navigate({ to: '/network', search: { tab: 'peers' } }) }, + { id: 'deploy', title: 'Деплой', desc: 'Публикация ревизии на спикеры', badge: 'Операции', badgeVariant: 'warning-light', meta: '', icon: , onSelect: () => void navigate({ to: '/operations', search: { tab: 'revisions' } }) }, + ] + + if (initialLoading) { + return ( +
+ + + + +
+ ) + } + return ( - - - Обновить - - } - kpiCards={kpiCards} - isLoading={initialLoading} - afterKpi={showQuickActions ? : null} - queue={ -
+
+ + + + + } + /> + + + + + + + + + {showQuickActions ? ( + + ) : null} + {activity.length > 0 ? ( - + void navigate({ to: '/operations', search: { tab: 'jobs' } })}> + Весь журнал + + } + /> ) : null} -
- } - queueTitle="" - queueDescription="" - charts={ -
- - -
- } - /> + + +
) } diff --git a/apps/web/tsconfig.tsbuildinfo b/apps/web/tsconfig.tsbuildinfo index ee8deb5..e2e807c 100644 --- a/apps/web/tsconfig.tsbuildinfo +++ b/apps/web/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/main.tsx","./src/routetree.gen.ts","./src/vite-env.d.ts","./src/components/app-switcher.tsx","./src/components/category-badge.tsx","./src/components/confirm-dialog.tsx","./src/components/data-grid-cell.tsx","./src/components/empty-state.tsx","./src/components/form-drawer.tsx","./src/components/loading-button.tsx","./src/components/page-header.tsx","./src/components/page-shell.tsx","./src/components/panel-card.tsx","./src/components/query-state.tsx","./src/components/segmented-tabs.tsx","./src/components/select-field.tsx","./src/components/skeletons.tsx","./src/components/status-badge.tsx","./src/components/status-toggle-group.tsx","./src/components/theme-provider.tsx","./src/components/truncated-text.tsx","./src/components/access/access-api-keys-card.tsx","./src/components/access/access-api-keys-grid.tsx","./src/components/access/api-key-create-dialog.tsx","./src/components/access/api-key-token-dialog.tsx","./src/components/analytics/analytics-activity-list.tsx","./src/components/analytics/analytics-card-shell.tsx","./src/components/analytics/analytics-kpi-row.tsx","./src/components/analytics/analytics-progress.tsx","./src/components/analytics/analytics-segment-control.tsx","./src/components/analytics/chart-bar-strip.tsx","./src/components/analytics/chart-donut-metric.tsx","./src/components/analytics/dashboard-network-capacity-card.tsx","./src/components/analytics/dashboard-operations-flow-card.tsx","./src/components/analytics/dashboard-platform-card.tsx","./src/components/analytics/index.ts","./src/components/analytics/monitoring-health-card.tsx","./src/components/analytics/network-overview-analytics-card.tsx","./src/components/dashboard/card-dot-field.tsx","./src/components/dashboard/dashboard-kpi-grid.tsx","./src/components/dashboard/dashboard-network-health.tsx","./src/components/dashboard/dashboard-network-panel.tsx","./src/components/dashboard/dashboard-operations-breakdown.tsx","./src/components/dashboard/dashboard-quick-links.tsx","./src/components/directories/community-create-dialog.tsx","./src/components/directories/directories-communities-grid.tsx","./src/components/directories/directories-doh-grid.tsx","./src/components/directories/directories-row-actions.tsx","./src/components/directories/doh-profile-create-dialog.tsx","./src/components/layout/portal-shell.tsx","./src/components/lookup/lookup-add-step.tsx","./src/components/lookup/lookup-matches-grid.tsx","./src/components/lookup/lookup-search-form.tsx","./src/components/lookup/lookup-status-banner.tsx","./src/components/lookup/lookup-wizard.tsx","./src/components/modules/community-select.tsx","./src/components/modules/module-as-entry-dialog.tsx","./src/components/modules/module-cdn-source-dialog.tsx","./src/components/modules/module-create-dialog.tsx","./src/components/modules/module-domain-entry-dialog.tsx","./src/components/modules/module-edit-dialog.tsx","./src/components/modules/module-entries-grid.tsx","./src/components/modules/module-entries-section.tsx","./src/components/modules/module-ip-range-entry-dialog.tsx","./src/components/modules/module-kpi-cards.tsx","./src/components/modules/modules-list-grid.tsx","./src/components/monitoring/monitoring-ready-grid.tsx","./src/components/network/network-discovered-peers-card.tsx","./src/components/network/network-kpi.tsx","./src/components/network/network-peers-card.tsx","./src/components/network/network-peers-grid.tsx","./src/components/network/network-speakers-card.tsx","./src/components/network/network-speakers-grid.tsx","./src/components/network/peer-form-dialog.tsx","./src/components/network/speaker-form-dialog.tsx","./src/components/operations/job-timeline.tsx","./src/components/operations/operations-jobs-card.tsx","./src/components/operations/operations-jobs-grid.tsx","./src/components/operations/operations-jobs-kanban.tsx","./src/components/operations/operations-revisions-grid.tsx","./src/components/patterns/donut-breakdown-card.tsx","./src/components/patterns/illustrated-empty-state.tsx","./src/components/patterns/index.ts","./src/components/patterns/kpi-sparkline-card.tsx","./src/components/patterns/metric-tone-styles.ts","./src/components/patterns/panel-corners.tsx","./src/components/patterns/projects-empty-state.tsx","./src/components/patterns/segmented-progress-card.tsx","./src/components/portal/bits.tsx","./src/components/portal/canvas-blocks.tsx","./src/components/portal/chrome-context.tsx","./src/components/portal/chrome-store.ts","./src/components/portal/chrome.tsx","./src/components/portal/data-page-layout.ts","./src/components/portal/data-page.tsx","./src/components/portal/format.ts","./src/components/portal/kpi-strip.tsx","./src/components/portal/kpi.tsx","./src/components/portal/section-grid.tsx","./src/components/portal/tone.ts","./src/components/reui/alert.tsx","./src/components/reui/autocomplete.tsx","./src/components/reui/badge.tsx","./src/components/reui/date-selector.tsx","./src/components/reui/frame.tsx","./src/components/reui/icon-stack.tsx","./src/components/reui/icon-tile.tsx","./src/components/reui/kanban.tsx","./src/components/reui/number-field.tsx","./src/components/reui/rating.tsx","./src/components/reui/sortable.tsx","./src/components/reui/stepper.tsx","./src/components/reui/timeline.tsx","./src/components/reui/cascader/cascader-async.tsx","./src/components/reui/cascader/cascader-columns.tsx","./src/components/reui/cascader/cascader-context.tsx","./src/components/reui/cascader/cascader-footer.tsx","./src/components/reui/cascader/cascader-i18n.tsx","./src/components/reui/cascader/cascader-item.tsx","./src/components/reui/cascader/cascader-lib.tsx","./src/components/reui/cascader/cascader-nav.tsx","./src/components/reui/cascader/cascader-types.tsx","./src/components/reui/cascader/cascader-virtual.tsx","./src/components/reui/cascader/cascader.tsx","./src/components/reui/code-block/code-block-highlight.tsx","./src/components/reui/code-block/code-block.tsx","./src/components/reui/data-grid/data-grid-cell-selection.tsx","./src/components/reui/data-grid/data-grid-column-filter.tsx","./src/components/reui/data-grid/data-grid-column-header.tsx","./src/components/reui/data-grid/data-grid-column-visibility.tsx","./src/components/reui/data-grid/data-grid-i18n.tsx","./src/components/reui/data-grid/data-grid-pagination.tsx","./src/components/reui/data-grid/data-grid-scroll-area.tsx","./src/components/reui/data-grid/data-grid-table-dnd-rows.tsx","./src/components/reui/data-grid/data-grid-table-dnd.tsx","./src/components/reui/data-grid/data-grid-table-virtual.tsx","./src/components/reui/data-grid/data-grid-table.tsx","./src/components/reui/data-grid/data-grid.tsx","./src/components/reui/filters/filters-advanced.tsx","./src/components/reui/filters/filters-builder.tsx","./src/components/reui/filters/filters-chip.tsx","./src/components/reui/filters/filters-context.tsx","./src/components/reui/filters/filters-date.tsx","./src/components/reui/filters/filters-dnd.tsx","./src/components/reui/filters/filters-draft.tsx","./src/components/reui/filters/filters-editors.tsx","./src/components/reui/filters/filters-i18n.tsx","./src/components/reui/filters/filters-lib.tsx","./src/components/reui/filters/filters-operators.tsx","./src/components/reui/filters/filters-query.tsx","./src/components/reui/filters/filters-types.tsx","./src/components/reui/filters/filters.tsx","./src/components/reui-kit/data-grid-kit-defaults.test.ts","./src/components/reui-kit/detail-panel.tsx","./src/components/reui-kit/expandable-resource-grid.tsx","./src/components/reui-kit/filter-utils.ts","./src/components/reui-kit/frame-data-grid.tsx","./src/components/reui-kit/frame-section.tsx","./src/components/reui-kit/index.ts","./src/components/reui-kit/kpi-cols.ts","./src/components/reui-kit/kpi-stat-grid.tsx","./src/components/reui-kit/ops-dashboard.tsx","./src/components/reui-kit/quick-action-grid.tsx","./src/components/reui-kit/resource-page.tsx","./src/components/reui-kit/settings-shell.tsx","./src/components/schedule/schedule-jobs-card.tsx","./src/components/schedule/schedule-jobs-grid.tsx","./src/components/schedule/schedule-modules-grid.tsx","./src/components/settings/appearance-settings-tab.tsx","./src/components/settings/bird-settings-tab.tsx","./src/components/settings/connection-settings-tab.tsx","./src/components/settings/sections-settings-tab.tsx","./src/components/settings/session-settings-tab.tsx","./src/components/settings/setting-row.tsx","./src/components/settings/settings-card.tsx","./src/components/settings/settings-field-group.tsx","./src/components/settings/settings-kv-grid.tsx","./src/components/settings/settings-page-shell.tsx","./src/components/settings/settings-setting-field.tsx","./src/components/settings/settings-tabs-data.tsx","./src/hooks/use-app-switcher.ts","./src/hooks/use-copy-to-clipboard.ts","./src/hooks/use-file-upload.ts","./src/hooks/use-mobile.ts","./src/lib/api-client.test.ts","./src/lib/api-client.ts","./src/lib/app-switcher-config.ts","./src/lib/auth.ts","./src/lib/filters-i18n.ts","./src/lib/queryclient.ts","./src/lib/reui-i18n-ru.ts","./src/lib/router.ts","./src/lib/ui-labels.ts","./src/lib/ui-surface.ts","./src/lib/access/api-key-labels.ts","./src/lib/metrics/deployment-progress.ts","./src/lib/metrics/index.ts","./src/lib/metrics/job-status-breakdown.ts","./src/lib/metrics/module-type-breakdown.ts","./src/lib/metrics/peer-capacity-bars.ts","./src/lib/metrics/peer-session-breakdown.ts","./src/lib/metrics/readiness-breakdown.test.ts","./src/lib/metrics/readiness-breakdown.ts","./src/lib/metrics/recent-platform-activity.ts","./src/lib/metrics/types.ts","./src/lib/modules/display.ts","./src/lib/modules/helpers.ts","./src/queries/api-keys.ts","./src/queries/app-switcher.ts","./src/queries/auth.ts","./src/queries/directories.ts","./src/queries/lookup.ts","./src/queries/modules.ts","./src/queries/monitoring.ts","./src/queries/network.ts","./src/queries/operations.ts","./src/queries/overview.ts","./src/queries/settings.ts","./src/routes/__root.tsx","./src/routes/_auth.tsx","./src/routes/auth.callback.tsx","./src/routes/index.tsx","./src/routes/_auth/_settings.tsx","./src/routes/_auth/access.tsx","./src/routes/_auth/dashboard.tsx","./src/routes/_auth/directories.tsx","./src/routes/_auth/lookup.tsx","./src/routes/_auth/monitoring.tsx","./src/routes/_auth/network.tsx","./src/routes/_auth/operations.tsx","./src/routes/_auth/schedule.tsx","./src/routes/_auth/_settings/settings.tsx","./src/routes/_auth/_settings/tenant-settings.tsx","./src/routes/_auth/modules/$moduleid.tsx","./src/routes/_auth/modules/index.tsx","./src/routes/_auth/modules/new.tsx","./src/types/api.gen.ts","./src/types/api.ts","./vite.config.ts"],"version":"5.9.3"} \ No newline at end of file +{"root":["./src/main.tsx","./src/routetree.gen.ts","./src/vite-env.d.ts","./src/components/app-switcher.tsx","./src/components/category-badge.tsx","./src/components/confirm-dialog.tsx","./src/components/data-grid-cell.tsx","./src/components/empty-state.tsx","./src/components/form-drawer.tsx","./src/components/loading-button.tsx","./src/components/page-header.tsx","./src/components/page-shell.tsx","./src/components/panel-card.tsx","./src/components/query-state.tsx","./src/components/segmented-tabs.tsx","./src/components/select-field.tsx","./src/components/skeletons.tsx","./src/components/status-badge.tsx","./src/components/status-toggle-group.tsx","./src/components/theme-provider.tsx","./src/components/truncated-text.tsx","./src/components/access/access-api-keys-card.tsx","./src/components/access/access-api-keys-grid.tsx","./src/components/access/api-key-create-dialog.tsx","./src/components/access/api-key-token-dialog.tsx","./src/components/analytics/analytics-activity-list.tsx","./src/components/analytics/analytics-card-shell.tsx","./src/components/analytics/analytics-kpi-row.tsx","./src/components/analytics/analytics-progress.tsx","./src/components/analytics/analytics-segment-control.tsx","./src/components/analytics/chart-bar-strip.tsx","./src/components/analytics/chart-donut-metric.tsx","./src/components/analytics/dashboard-network-capacity-card.tsx","./src/components/analytics/dashboard-operations-flow-card.tsx","./src/components/analytics/dashboard-platform-card.tsx","./src/components/analytics/index.ts","./src/components/analytics/monitoring-health-card.tsx","./src/components/analytics/network-overview-analytics-card.tsx","./src/components/dashboard/card-dot-field.tsx","./src/components/dashboard/dashboard-kpi-grid.tsx","./src/components/dashboard/dashboard-network-health.tsx","./src/components/dashboard/dashboard-network-panel.tsx","./src/components/dashboard/dashboard-operations-breakdown.tsx","./src/components/dashboard/dashboard-prefix-trend.tsx","./src/components/dashboard/dashboard-quick-links.tsx","./src/components/directories/community-create-dialog.tsx","./src/components/directories/directories-communities-grid.tsx","./src/components/directories/directories-doh-grid.tsx","./src/components/directories/directories-row-actions.tsx","./src/components/directories/doh-profile-create-dialog.tsx","./src/components/layout/portal-shell.tsx","./src/components/lookup/lookup-add-step.tsx","./src/components/lookup/lookup-matches-grid.tsx","./src/components/lookup/lookup-search-form.tsx","./src/components/lookup/lookup-status-banner.tsx","./src/components/lookup/lookup-wizard.tsx","./src/components/modules/community-select.tsx","./src/components/modules/module-as-entry-dialog.tsx","./src/components/modules/module-cdn-source-dialog.tsx","./src/components/modules/module-create-dialog.tsx","./src/components/modules/module-domain-entry-dialog.tsx","./src/components/modules/module-edit-dialog.tsx","./src/components/modules/module-entries-grid.tsx","./src/components/modules/module-entries-section.tsx","./src/components/modules/module-ip-range-entry-dialog.tsx","./src/components/modules/module-kpi-cards.tsx","./src/components/modules/modules-list-grid.tsx","./src/components/monitoring/monitoring-ready-grid.tsx","./src/components/network/network-discovered-peers-card.tsx","./src/components/network/network-kpi.tsx","./src/components/network/network-peers-card.tsx","./src/components/network/network-peers-grid.tsx","./src/components/network/network-speakers-card.tsx","./src/components/network/network-speakers-grid.tsx","./src/components/network/peer-form-dialog.tsx","./src/components/network/speaker-form-dialog.tsx","./src/components/operations/job-timeline.tsx","./src/components/operations/operations-jobs-card.tsx","./src/components/operations/operations-jobs-grid.tsx","./src/components/operations/operations-jobs-kanban.tsx","./src/components/operations/operations-revisions-grid.tsx","./src/components/patterns/donut-breakdown-card.tsx","./src/components/patterns/illustrated-empty-state.tsx","./src/components/patterns/index.ts","./src/components/patterns/kpi-sparkline-card.tsx","./src/components/patterns/metric-tone-styles.ts","./src/components/patterns/panel-corners.tsx","./src/components/patterns/projects-empty-state.tsx","./src/components/patterns/segmented-progress-card.tsx","./src/components/portal/bits.tsx","./src/components/portal/canvas-blocks.tsx","./src/components/portal/chrome-context.tsx","./src/components/portal/chrome-store.ts","./src/components/portal/chrome.tsx","./src/components/portal/data-page-layout.ts","./src/components/portal/data-page.tsx","./src/components/portal/format.ts","./src/components/portal/kpi-strip.tsx","./src/components/portal/kpi.tsx","./src/components/portal/section-grid.tsx","./src/components/portal/tone.ts","./src/components/reui/alert.tsx","./src/components/reui/autocomplete.tsx","./src/components/reui/badge.tsx","./src/components/reui/date-selector.tsx","./src/components/reui/frame.tsx","./src/components/reui/icon-stack.tsx","./src/components/reui/icon-tile.tsx","./src/components/reui/kanban.tsx","./src/components/reui/number-field.tsx","./src/components/reui/rating.tsx","./src/components/reui/sortable.tsx","./src/components/reui/stepper.tsx","./src/components/reui/timeline.tsx","./src/components/reui/cascader/cascader-async.tsx","./src/components/reui/cascader/cascader-columns.tsx","./src/components/reui/cascader/cascader-context.tsx","./src/components/reui/cascader/cascader-footer.tsx","./src/components/reui/cascader/cascader-i18n.tsx","./src/components/reui/cascader/cascader-item.tsx","./src/components/reui/cascader/cascader-lib.tsx","./src/components/reui/cascader/cascader-nav.tsx","./src/components/reui/cascader/cascader-types.tsx","./src/components/reui/cascader/cascader-virtual.tsx","./src/components/reui/cascader/cascader.tsx","./src/components/reui/code-block/code-block-highlight.tsx","./src/components/reui/code-block/code-block.tsx","./src/components/reui/data-grid/data-grid-cell-selection.tsx","./src/components/reui/data-grid/data-grid-column-filter.tsx","./src/components/reui/data-grid/data-grid-column-header.tsx","./src/components/reui/data-grid/data-grid-column-visibility.tsx","./src/components/reui/data-grid/data-grid-i18n.tsx","./src/components/reui/data-grid/data-grid-pagination.tsx","./src/components/reui/data-grid/data-grid-scroll-area.tsx","./src/components/reui/data-grid/data-grid-table-dnd-rows.tsx","./src/components/reui/data-grid/data-grid-table-dnd.tsx","./src/components/reui/data-grid/data-grid-table-virtual.tsx","./src/components/reui/data-grid/data-grid-table.tsx","./src/components/reui/data-grid/data-grid.tsx","./src/components/reui/filters/filters-advanced.tsx","./src/components/reui/filters/filters-builder.tsx","./src/components/reui/filters/filters-chip.tsx","./src/components/reui/filters/filters-context.tsx","./src/components/reui/filters/filters-date.tsx","./src/components/reui/filters/filters-dnd.tsx","./src/components/reui/filters/filters-draft.tsx","./src/components/reui/filters/filters-editors.tsx","./src/components/reui/filters/filters-i18n.tsx","./src/components/reui/filters/filters-lib.tsx","./src/components/reui/filters/filters-operators.tsx","./src/components/reui/filters/filters-query.tsx","./src/components/reui/filters/filters-types.tsx","./src/components/reui/filters/filters.tsx","./src/components/reui-kit/data-grid-kit-defaults.test.ts","./src/components/reui-kit/detail-panel.tsx","./src/components/reui-kit/expandable-resource-grid.tsx","./src/components/reui-kit/filter-utils.ts","./src/components/reui-kit/frame-data-grid.tsx","./src/components/reui-kit/frame-section.tsx","./src/components/reui-kit/index.ts","./src/components/reui-kit/kpi-cols.ts","./src/components/reui-kit/kpi-stat-grid.tsx","./src/components/reui-kit/ops-dashboard.tsx","./src/components/reui-kit/quick-action-grid.tsx","./src/components/reui-kit/resource-page.tsx","./src/components/reui-kit/settings-shell.tsx","./src/components/schedule/schedule-jobs-card.tsx","./src/components/schedule/schedule-jobs-grid.tsx","./src/components/schedule/schedule-modules-grid.tsx","./src/components/settings/appearance-settings-tab.tsx","./src/components/settings/bird-settings-tab.tsx","./src/components/settings/connection-settings-tab.tsx","./src/components/settings/sections-settings-tab.tsx","./src/components/settings/session-settings-tab.tsx","./src/components/settings/setting-row.tsx","./src/components/settings/settings-card.tsx","./src/components/settings/settings-field-group.tsx","./src/components/settings/settings-kv-grid.tsx","./src/components/settings/settings-page-shell.tsx","./src/components/settings/settings-setting-field.tsx","./src/components/settings/settings-tabs-data.tsx","./src/hooks/use-app-switcher.ts","./src/hooks/use-copy-to-clipboard.ts","./src/hooks/use-file-upload.ts","./src/hooks/use-mobile.ts","./src/lib/api-client.test.ts","./src/lib/api-client.ts","./src/lib/app-switcher-config.ts","./src/lib/auth.ts","./src/lib/filters-i18n.ts","./src/lib/queryclient.ts","./src/lib/reui-i18n-ru.ts","./src/lib/router.ts","./src/lib/ui-labels.ts","./src/lib/ui-surface.ts","./src/lib/access/api-key-labels.ts","./src/lib/metrics/deployment-progress.ts","./src/lib/metrics/index.ts","./src/lib/metrics/job-status-breakdown.ts","./src/lib/metrics/module-type-breakdown.ts","./src/lib/metrics/peer-capacity-bars.ts","./src/lib/metrics/peer-session-breakdown.ts","./src/lib/metrics/readiness-breakdown.test.ts","./src/lib/metrics/readiness-breakdown.ts","./src/lib/metrics/recent-platform-activity.ts","./src/lib/metrics/types.ts","./src/lib/modules/display.ts","./src/lib/modules/helpers.ts","./src/queries/api-keys.ts","./src/queries/app-switcher.ts","./src/queries/auth.ts","./src/queries/directories.ts","./src/queries/lookup.ts","./src/queries/modules.ts","./src/queries/monitoring.ts","./src/queries/network.ts","./src/queries/operations.ts","./src/queries/overview.ts","./src/queries/settings.ts","./src/routes/__root.tsx","./src/routes/_auth.tsx","./src/routes/auth.callback.tsx","./src/routes/index.tsx","./src/routes/_auth/_settings.tsx","./src/routes/_auth/access.tsx","./src/routes/_auth/dashboard.tsx","./src/routes/_auth/directories.tsx","./src/routes/_auth/lookup.tsx","./src/routes/_auth/monitoring.tsx","./src/routes/_auth/network.tsx","./src/routes/_auth/operations.tsx","./src/routes/_auth/schedule.tsx","./src/routes/_auth/_settings/settings.tsx","./src/routes/_auth/_settings/tenant-settings.tsx","./src/routes/_auth/modules/$moduleid.tsx","./src/routes/_auth/modules/index.tsx","./src/routes/_auth/modules/new.tsx","./src/types/api.gen.ts","./src/types/api.ts","./vite.config.ts"],"errors":true,"version":"5.9.3"} \ No newline at end of file