refactor(web): общие форматтеры, единая навигация, RBAC-гейтинг и чистка мёртвого кода

- lib/format.ts: ru-RU форматтеры дат/чисел в одном месте — убраны дубли
  из 8 компонентов (agent-card, fleet-grid, blocked-ips/ports, facts,
  lifecycle, host-firewall, lists-columns, system-monitor)
- lib/nav.ts: единый конфиг маршрутов — sidebar, ⌘K-поиск и breadcrumbs
  рендерятся из одного источника (было 3 расходящихся копии)
- lib/permissions.ts + useCan: клиентский RBAC — кнопки создания/подтверждения
  скрываются без fw:*:write/admin (сервер остаётся авторитетным)
- удалён мёртвый код ~2500 строк: stepper, data-grid dnd/virtual/visibility
  варианты, settings-shell
This commit is contained in:
Denozordec
2026-09-20 19:36:37 +07:00
parent 7a3f1fad25
commit 3dc8e6d5e2
26 changed files with 275 additions and 2178 deletions
+6 -2
View File
@@ -47,6 +47,7 @@ import { ConfirmDialog } from '@/components/confirm-dialog'
import { QueryState } from '@/components/query-state'
import { agentsQueryOptions, settingsQueryOptions } from '@/queries'
import { apiFetch } from '@/lib/api'
import { useCan } from '@/lib/permissions'
import { useCopyToClipboard } from '@/hooks/use-copy-to-clipboard'
import { Button } from '@evofw/ui/components/button'
import {
@@ -97,6 +98,7 @@ function AgentsPage() {
const agentsQ = useQuery(agentsQueryOptions())
const settingsQ = useQuery(settingsQueryOptions())
const { copyToClipboard } = useCopyToClipboard()
const canWrite = useCan()('fw:agents:write')
const [createOpen, setCreateOpen] = useState(false)
const [deleteAgentId, setDeleteAgentId] = useState<string | null>(null)
const [filters, setFilters] = useState<Filter[]>([])
@@ -418,12 +420,12 @@ function AgentsPage() {
</ToggleGroup>
)
const addButton = (
const addButton = canWrite ? (
<Button size="sm" onClick={() => setCreateOpen(true)}>
<Plus data-icon="inline-start" />
Добавить агента
</Button>
)
) : null
return (
<PageShell>
@@ -454,6 +456,7 @@ function AgentsPage() {
>
Показать
</Button>
{canWrite ? (
<Button
size="sm"
disabled={
@@ -464,6 +467,7 @@ function AgentsPage() {
<Check data-icon="inline-start" />
Approve all
</Button>
) : null}
</div>
</FrameHeader>
</Frame>