From d8567205e235eca235a0aa4b8433ea245e456fdb Mon Sep 17 00:00:00 2001 From: Denozordec Date: Thu, 23 Jul 2026 11:46:51 +0700 Subject: [PATCH] feat(api, web): enhance policy rule handling with list name integration - Updated the `sourceMeta` function to accept a database parameter, allowing for dynamic retrieval of list names based on list IDs. - Modified the `ruleTarget` and `ruleSubtitle` functions to utilize the new list name mapping, improving the readability of policy rules in the UI. - Introduced memoization for list names in the `PolicySetDetailPage`, optimizing performance and ensuring accurate display of list names in the policy rules sortable component. These changes enhance the user experience by providing clearer and more informative labels for policy rules, facilitating better understanding and management of policies. --- apps/api/src/services/policy/evaluate.ts | 19 +++++++---- .../rules/policy-rules-sortable.tsx | 32 +++++++++++++++---- apps/web/src/routes/_auth/rules/$setId.tsx | 25 +++++++++++++-- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/apps/api/src/services/policy/evaluate.ts b/apps/api/src/services/policy/evaluate.ts index 0716027..0786f00 100644 --- a/apps/api/src/services/policy/evaluate.ts +++ b/apps/api/src/services/policy/evaluate.ts @@ -82,18 +82,23 @@ function resolveDefaultAction(agentDefaultAction: string | null | undefined): De return defaultActionFromLegacyMode(agentDefaultAction) } -function sourceMeta(rule: { - cidr: string | null - listId: string | null - hostname: string | null -}): { kind: 'list' | 'cidr' | 'hostname'; label: string } { +function sourceMeta( + db: Db, + rule: { + cidr: string | null + listId: string | null + hostname: string | null + }, +): { kind: 'list' | 'cidr' | 'hostname'; label: string } { if (rule.cidr?.trim()) { return { kind: 'cidr', label: rule.cidr.trim() } } if (rule.hostname?.trim()) { return { kind: 'hostname', label: rule.hostname.trim() } } - return { kind: 'list', label: rule.listId ?? 'list' } + const listId = rule.listId?.trim() || '' + const name = listId ? repos.getIpList(db, listId)?.name : null + return { kind: 'list', label: name || listId || 'list' } } /** Evaluate allow/deny sets for an agent from assigned policy sets. */ @@ -125,7 +130,7 @@ export function evaluateAgentPolicy(db: Db, agentId: string): EvaluatedPolicy { allow.push(...cidrs) rulesAllow += 1 } - const src = sourceMeta(rule) + const src = sourceMeta(db, rule) const setName = assignedSets.find((s) => s.setId === rule.setId)?.name ?? null chain.push({ diff --git a/apps/web/src/components/rules/policy-rules-sortable.tsx b/apps/web/src/components/rules/policy-rules-sortable.tsx index e04dde8..5adc3d0 100644 --- a/apps/web/src/components/rules/policy-rules-sortable.tsx +++ b/apps/web/src/components/rules/policy-rules-sortable.tsx @@ -36,17 +36,27 @@ import { apiFetch } from '@/lib/api' * Docs: https://reui.io/docs/components/base/sortable */ -function ruleTarget(r: PolicyRule): string { +function ruleTarget( + r: PolicyRule, + listNames?: Map, +): string { if (r.cidr) return r.cidr if (r.hostname) return r.hostname - if (r.list_id) return `list:${r.list_id.slice(0, 8)}…` + if (r.list_id) { + return listNames?.get(r.list_id) ?? `Список ${r.list_id.slice(0, 8)}…` + } return '—' } -function ruleSubtitle(r: PolicyRule): string | null { +function ruleSubtitle( + r: PolicyRule, + listNames?: Map, +): string | null { const parts: string[] = [] if (r.list_id && (r.cidr || r.hostname)) { - parts.push(`list:${r.list_id.slice(0, 8)}…`) + parts.push( + listNames?.get(r.list_id) ?? `Список ${r.list_id.slice(0, 8)}…`, + ) } if (r.comment) parts.push(r.comment) if (typeof r.resolved_count === 'number' && r.resolved_count > 0) { @@ -58,6 +68,8 @@ function ruleSubtitle(r: PolicyRule): string | null { type PolicyRulesSortableProps = { setId: string rules: PolicyRule[] + /** list_id → name for human-readable rule labels */ + listNames?: Map onDelete: (id: string) => void onAdd?: () => void } @@ -65,6 +77,7 @@ type PolicyRulesSortableProps = { export function PolicyRulesSortable({ setId, rules: rulesProp, + listNames, onDelete, onAdd, }: PolicyRulesSortableProps) { @@ -170,7 +183,7 @@ export function PolicyRulesSortable({ {items.map((r) => { const enabled = r.enabled !== false const isDeny = r.action === 'deny' - const subtitle = ruleSubtitle(r) + const subtitle = ruleSubtitle(r, listNames) return (
- - {ruleTarget(r)} + + {ruleTarget(r, listNames)} { + const m = new Map() + for (const l of listsQ.data?.items ?? []) { + m.set(l.id, l.name) + } + return m + }, [listsQ.data?.items]) + + const listSelectItems = useMemo( + () => + (listsQ.data?.items ?? []).map((l) => ({ + value: l.id, + label: l.name, + })), + [listsQ.data?.items], + ) + const agentColumns: ColumnDef[] = useMemo( () => [ { @@ -336,6 +353,7 @@ function PolicySetDetailPage() { setDeleteRuleId(id)} onAdd={() => setRuleOpen(true)} /> @@ -441,6 +459,7 @@ function PolicySetDetailPage() { Список