feat(policy): именованные наборы правил с DNS и M:N привязкой к агентам
Правила живут в policy_sets; evaluate мержит назначенные наборы; источник list|CIDR|hostname с кэшем DNS. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -28,7 +28,7 @@ const overviewNav = [
|
||||
const opsNav = [
|
||||
{ to: '/agents', label: 'Агенты', icon: ServerIcon, exact: false },
|
||||
{ to: '/lists', label: 'Списки IP', icon: ListIcon, exact: false },
|
||||
{ to: '/rules', label: 'Правила', icon: ShieldIcon, exact: false },
|
||||
{ to: '/rules', label: 'Наборы правил', icon: ShieldIcon, exact: false },
|
||||
{ to: '/stats', label: 'Статистика', icon: BarChart3Icon, exact: false },
|
||||
] as const
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ const NAV_ITEMS = [
|
||||
},
|
||||
{
|
||||
to: '/rules',
|
||||
label: 'Правила',
|
||||
keywords: ['rules', 'правила', 'policy'],
|
||||
label: 'Наборы правил',
|
||||
keywords: ['rules', 'правила', 'policy', 'наборы', 'sets'],
|
||||
icon: ShieldIcon,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ const routeTitles: Record<string, string> = {
|
||||
'/': 'Панель управления',
|
||||
'/agents': 'Агенты',
|
||||
'/lists': 'Списки IP',
|
||||
'/rules': 'Правила',
|
||||
'/rules': 'Наборы правил',
|
||||
'/stats': 'Статистика',
|
||||
'/settings': 'Настройки',
|
||||
}
|
||||
@@ -42,6 +42,13 @@ function getBreadcrumbs(
|
||||
]
|
||||
}
|
||||
|
||||
if (pathname.match(/^\/rules\/[^/]+$/)) {
|
||||
return [
|
||||
{ label: 'Наборы правил', href: '/rules' },
|
||||
{ label: dynamicLabels[pathname] ?? 'Набор', href: pathname },
|
||||
]
|
||||
}
|
||||
|
||||
const title = routeTitles[pathname]
|
||||
if (title) {
|
||||
return [{ label: title, href: pathname }]
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
agentsQueryOptions,
|
||||
dashboardQueryOptions,
|
||||
listsQueryOptions,
|
||||
rulesQueryOptions,
|
||||
policySetsQueryOptions,
|
||||
} from '@/queries'
|
||||
|
||||
type MonitorMetric = {
|
||||
@@ -80,7 +80,10 @@ export function SystemMonitorPopover() {
|
||||
const dashQ = useQuery({ ...dashboardQueryOptions(), refetchInterval: 30_000 })
|
||||
const agentsQ = useQuery({ ...agentsQueryOptions(), refetchInterval: 30_000 })
|
||||
const listsQ = useQuery({ ...listsQueryOptions(), refetchInterval: 60_000 })
|
||||
const rulesQ = useQuery({ ...rulesQueryOptions(), refetchInterval: 60_000 })
|
||||
const setsQ = useQuery({
|
||||
...policySetsQueryOptions(),
|
||||
refetchInterval: 60_000,
|
||||
})
|
||||
|
||||
const d = dashQ.data
|
||||
const agents = agentsQ.data?.items ?? []
|
||||
@@ -90,7 +93,8 @@ export function SystemMonitorPopover() {
|
||||
d?.agents_pending ?? agents.filter((a) => a.status === 'pending').length
|
||||
const onlinePct = approved > 0 ? Math.round((online / approved) * 100) : 0
|
||||
const listsCount = listsQ.data?.items?.length ?? d?.lists_total ?? 0
|
||||
const rulesCount = rulesQ.data?.items?.length ?? 0
|
||||
const rulesCount =
|
||||
setsQ.data?.items.reduce((n, s) => n + (s.rules_count ?? 0), 0) ?? 0
|
||||
const apiOk = !dashQ.isError
|
||||
|
||||
const metrics = useMemo<MonitorMetric[]>(
|
||||
|
||||
Reference in New Issue
Block a user