diff --git a/apps/web/src/components/analytics/chart-donut-metric.tsx b/apps/web/src/components/analytics/chart-donut-metric.tsx
index f6e283a..126cd3c 100644
--- a/apps/web/src/components/analytics/chart-donut-metric.tsx
+++ b/apps/web/src/components/analytics/chart-donut-metric.tsx
@@ -2,6 +2,8 @@ import { Cell, Label, Pie, PieChart } from 'recharts'
import {
ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent,
type ChartConfig,
} from '@evobgp/ui/components/chart'
import { cn } from '@evobgp/ui/lib/utils'
@@ -43,6 +45,7 @@ export function ChartDonutMetric({
+ } />
diff --git a/apps/web/src/components/dashboard/dashboard-operations-breakdown.tsx b/apps/web/src/components/dashboard/dashboard-operations-breakdown.tsx
index 620389b..8965ca7 100644
--- a/apps/web/src/components/dashboard/dashboard-operations-breakdown.tsx
+++ b/apps/web/src/components/dashboard/dashboard-operations-breakdown.tsx
@@ -3,13 +3,16 @@ import { useMemo, useState } from 'react'
import { ChartDonutMetric } from '@/components/analytics/chart-donut-metric'
import { AnalyticsSegmentControl } from '@/components/analytics/analytics-segment-control'
import { PanelCard } from '@/components/panel-card'
-import { Separator } from '@evobgp/ui/components/separator'
import { jobStatusBreakdown, moduleTypeBreakdown } from '@/lib/metrics'
import type { JobRow, ModuleRow } from '@/types/api'
type FlowMode = 'jobs' | 'modules'
-/** chart-13 inspired donut breakdown (Card surface). */
+/**
+ * Donut distribution — chart-27 DNA: Frame + one legend (inside ChartDonutMetric).
+ * @see https://reui.io/preview/base/chart-27
+ * @see https://reui.io/docs/components/base/frame
+ */
export function DashboardOperationsBreakdown({
jobs,
modules,
@@ -32,7 +35,7 @@ export function DashboardOperationsBreakdown({
return (
}
- className="h-full"
+ className="min-w-0"
+ contentClassName="px-5 py-4"
>
-
- {loading ? (
-
- Загрузка…
-
- ) : (
- <>
-
- {slices.length > 0 ? (
-
- {slices.map((slice, index) => {
- const pct = total > 0 ? ((slice.count / total) * 100).toFixed(1) : '0'
- return (
- -
-
-
-
- {slice.label}
-
-
{slice.count}
-
- {pct}%
-
-
- {index < slices.length - 1 ? : null}
-
- )
- })}
-
- ) : null}
- >
- )}
-
+ {loading ? (
+
+ Загрузка…
+
+ ) : (
+
+ )}
)
}
diff --git a/apps/web/src/components/dashboard/dashboard-recent-jobs-grid.tsx b/apps/web/src/components/dashboard/dashboard-recent-jobs-grid.tsx
index fd25a31..71b160c 100644
--- a/apps/web/src/components/dashboard/dashboard-recent-jobs-grid.tsx
+++ b/apps/web/src/components/dashboard/dashboard-recent-jobs-grid.tsx
@@ -2,7 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
import { DataGridPrimaryCell } from '@/components/data-grid-cell'
-import { DataGridSection } from '@/components/data-grid-shell'
+import { DataGridShell } from '@/components/data-grid-shell'
import { StatusBadge } from '@/components/status-badge'
import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header'
import { DATA_GRID_DENSE_LAYOUT } from '@/lib/data-grid-defaults'
@@ -49,7 +49,7 @@ export function DashboardRecentJobsGrid({
[nameById],
)
- const { table, globalFilter, setGlobalFilter, filteredCount } = useClientDataGrid({
+ const { table, filteredCount } = useClientDataGrid({
data,
columns,
getSearchText: (row) => {
@@ -63,16 +63,13 @@ export function DashboardRecentJobsGrid({
})
return (
-
)
}
diff --git a/apps/web/src/components/dashboard/dashboard-recent-revisions-grid.tsx b/apps/web/src/components/dashboard/dashboard-recent-revisions-grid.tsx
index b63718e..3eeb9f6 100644
--- a/apps/web/src/components/dashboard/dashboard-recent-revisions-grid.tsx
+++ b/apps/web/src/components/dashboard/dashboard-recent-revisions-grid.tsx
@@ -2,7 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
import { DataGridMutedCell, DataGridPrimaryCell } from '@/components/data-grid-cell'
-import { DataGridSection } from '@/components/data-grid-shell'
+import { DataGridShell } from '@/components/data-grid-shell'
import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header'
import { DATA_GRID_DENSE_LAYOUT } from '@/lib/data-grid-defaults'
import { useClientDataGrid } from '@/hooks/use-client-data-grid'
@@ -42,7 +42,7 @@ export function DashboardRecentRevisionsGrid({
[],
)
- const { table, globalFilter, setGlobalFilter, filteredCount } = useClientDataGrid({
+ const { table, filteredCount } = useClientDataGrid({
data,
columns,
getSearchText: (row) => row.id,
@@ -51,16 +51,13 @@ export function DashboardRecentRevisionsGrid({
})
return (
-
)
}
diff --git a/apps/web/src/components/reui-kit/ops-dashboard.tsx b/apps/web/src/components/reui-kit/ops-dashboard.tsx
index 441519a..c972635 100644
--- a/apps/web/src/components/reui-kit/ops-dashboard.tsx
+++ b/apps/web/src/components/reui-kit/ops-dashboard.tsx
@@ -1,11 +1,4 @@
import type { ReactNode } from 'react'
-import {
- Frame,
- FrameDescription,
- FrameHeader,
- FramePanel,
- FrameTitle,
-} from '@/components/reui/frame'
import { Skeleton } from '@evobgp/ui/components/skeleton'
import { PageHeader } from '@/components/page-header'
import { KpiStatGrid, type KpiStatCardData } from './kpi-stat-grid'
@@ -47,9 +40,11 @@ function OpsDashboardSkeleton() {
}
/**
- * Ops dashboard: KPI → optional Quick Actions → charts → attention queue.
+ * Ops dashboard: KPI → optional Quick Actions → charts → queue.
+ * Queue is a sibling Frame grid — never wrap FrameDataGrid inside another Frame.
* @see https://reui.io/preview/base/dashboard-1
* @see https://reui.io/preview/base/stats-12
+ * @see https://reui.io/docs/components/base/frame
*/
export function OpsDashboard({
title = 'Панель управления',
@@ -77,21 +72,18 @@ export function OpsDashboard({
{afterKpi ? : null}
-
+
-
-
-
- {queueTitle}
- {queueDescription}
-
- {queue}
-
+
+
+
{queueTitle}
+ {queueDescription ? (
+
{queueDescription}
+ ) : null}
+
+ {queue}
)
diff --git a/apps/web/src/routes/_auth/dashboard.tsx b/apps/web/src/routes/_auth/dashboard.tsx
index 75b26d2..f540342 100644
--- a/apps/web/src/routes/_auth/dashboard.tsx
+++ b/apps/web/src/routes/_auth/dashboard.tsx
@@ -7,7 +7,6 @@ import { Button } from '@evobgp/ui/components/button'
import { Skeleton } from '@evobgp/ui/components/skeleton'
import { DashboardActivityTimeline } from '@/components/dashboard/dashboard-activity-timeline'
-import { DashboardFramePanel } from '@/components/dashboard/dashboard-frame-panel'
import { buildDashboardKpiCards } from '@/components/dashboard/dashboard-kpi-grid'
import { DashboardModulesGrid } from '@/components/dashboard/dashboard-modules-grid'
import { DashboardNetworkHealth } from '@/components/dashboard/dashboard-network-health'
@@ -15,7 +14,7 @@ import { DashboardOperationsBreakdown } from '@/components/dashboard/dashboard-o
import { DashboardQuickLinks } from '@/components/dashboard/dashboard-quick-links'
import { DashboardRecentJobsGrid } from '@/components/dashboard/dashboard-recent-jobs-grid'
import { DashboardRecentRevisionsGrid } from '@/components/dashboard/dashboard-recent-revisions-grid'
-import { OpsDashboard } from '@/components/reui-kit'
+import { FrameDataGrid, OpsDashboard } from '@/components/reui-kit'
import { chartPanelGridClassName, dashboardMainSidebarClassName } from '@/lib/ui-surface'
import {
moduleNameById,
@@ -111,7 +110,7 @@ function DashboardComponent() {
peers={peers}
speakers={speakers}
/>
-
+
@@ -122,28 +121,26 @@ function DashboardComponent() {
queueDescription="Последние фоновые операции и история конфигураций"
queue={
-
{activityLoading ? (
) : (
-
+
)}
-
-
+
{activityLoading ? (
) : (
)}
-
+
}
/>
diff --git a/packages/ui/src/components/tabs.tsx b/packages/ui/src/components/tabs.tsx
index 3b0ded1..137c901 100644
--- a/packages/ui/src/components/tabs.tsx
+++ b/packages/ui/src/components/tabs.tsx
@@ -24,12 +24,13 @@ function Tabs({
}
const tabsListVariants = cva(
- "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none",
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg text-muted-foreground group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none",
{
variants: {
variant: {
- default: "bg-muted",
- line: "gap-1 border-b border-border bg-transparent",
+ default:
+ "bg-muted p-[3px] group-data-[orientation=horizontal]/tabs:h-9",
+ line: "h-auto gap-1 overflow-visible border-b border-border bg-transparent p-0",
},
},
defaultVariants: {
@@ -58,10 +59,12 @@ function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {