ну и ну

This commit is contained in:
dv 2026-04-09 11:05:56 +03:00
parent 941258fbb6
commit 140d43f8fe
2 changed files with 64 additions and 16 deletions

View file

@ -36,7 +36,7 @@ utp_service/
├── pages/ # Page-level components ├── pages/ # Page-level components
├── api/ # React Query hooks + API calls ├── api/ # React Query hooks + API calls
├── hooks/ # useSSE, useMonitorSSE ├── hooks/ # useSSE, useMonitorSSE
├── components/ # AppLayout, StatusBadge ├── components/ # AppLayout, StatusBadge, DeviceEditModal
└── store/auth.ts # Zustand auth store └── store/auth.ts # Zustand auth store
``` ```
@ -106,10 +106,10 @@ Content-addressed: `SnapshotContent(sha256 PK, content)`, `ConfigSnapshot(device
| global_devices.py | /devices | GET all devices across objects (filters: category, city, client, object_id, status) | | global_devices.py | /devices | GET all devices across objects (filters: category, city, client, object_id, status) |
| racks.py | /objects/{id}/racks | CRUD | | racks.py | /objects/{id}/racks | CRUD |
| zones.py | /objects/{id}/zones | CRUD | | zones.py | /objects/{id}/zones | CRUD |
| tasks.py | /tasks | POST create + GET list/detail + GET /{id}/events (SSE) | | tasks.py | /tasks | POST create + GET list/detail + GET /{id}/events (SSE); GET list accepts `?device_id=X` (JOIN task_results) |
| events.py | /events | GET SSE stream (task_id param) | | events.py | /events | GET SSE stream (task_id param) |
| alerts.py | /alerts | GET list + POST /{id}/acknowledge + POST /{id}/resolve | | alerts.py | /alerts | GET list (filters: status, object_id, device_id) + POST /{id}/acknowledge + POST /{id}/resolve |
| snapshots.py | /snapshots | GET list + GET /{id}/diff | | snapshots.py | /objects/{id}/snapshots | GET list (filter: device_id) + GET /diff?a=&b= + GET /{id} |
| tags.py | /tags | CRUD | | tags.py | /tags | CRUD |
| admin.py | /admin | User mgmt + plugin control + health | | admin.py | /admin | User mgmt + plugin control + health |
@ -160,6 +160,7 @@ SSE fix: `onerror` must `throw err` to prevent fetchEventSource auto-retry loop
/ → redirect to /inventory/objects / → redirect to /inventory/objects
/inventory/objects → ObjectsPage (mode=inventory) — city-grouped list /inventory/objects → ObjectsPage (mode=inventory) — city-grouped list
/inventory/objects/:id → InventoryObjectDetailPage — device CRUD, SSH discovery /inventory/objects/:id → InventoryObjectDetailPage — device CRUD, SSH discovery
/inventory/objects/:id/devices/:deviceId → DeviceDetailPage — device card (4 tabs)
/inventory/objects/:id/snapshots → SnapshotsPage /inventory/objects/:id/snapshots → SnapshotsPage
/work/objects → ObjectsPage (mode=work) — city-grouped list /work/objects → ObjectsPage (mode=work) — city-grouped list
/work/objects/:id → WorkObjectDetailPage — task execution, device status /work/objects/:id → WorkObjectDetailPage — task execution, device status
@ -168,13 +169,59 @@ SSE fix: `onerror` must `throw err` to prevent fetchEventSource auto-retry loop
Layout nav: ИНВЕНТАРЬ (DatabaseOutlined) | РАБОТА (ControlOutlined, AppstoreOutlined) Layout nav: ИНВЕНТАРЬ (DatabaseOutlined) | РАБОТА (ControlOutlined, AppstoreOutlined)
### DeviceDetailPage (`pages/DeviceDetail.tsx`)
URL: `/inventory/objects/:id/devices/:deviceId`
Шапка: IP + live-статус (SSE via `useMonitorSSE`), hostname, теги категории/стойки/вендора, кнопки Редактировать / Удалить.
Вкладки:
- **Основное** — все поля `DeviceItem` через `Descriptions`, `device_meta`/`connection_params` в JSON-блоках, capabilities тегами
- **Алерты** — список алертов устройства (`useAlerts({ device_id })`), фильтр по статусу, кнопки acknowledge/resolve
- **Снапшоты** — список (`useSnapshots(objId, { device_id })`), выбор двух → цветной diff-viewer через `useSnapshotDiff`
- **История задач** — задачи через `useDeviceTasks(deviceId)`, раскрытие строки показывает stdout/stderr из `TaskResult`
### DeviceEditModal (`components/DeviceEditModal.tsx`)
Самодостаточный компонент формы редактирования/добавления устройства. Используется в:
- `InventoryObjectDetailPage` (кнопки Edit и «Добавить устройство»)
- `DeviceDetailPage` (кнопка «Редактировать» в шапке)
Props: `open`, `device: DeviceItem | null` (null = режим добавления), `objId`, `onClose`, `onSaved?`
Внутри: `useCreateDevice` / `useUpdateDevice`, `useRacks` для списка стоек.
## Frontend API Hooks (`src/api/`) ## Frontend API Hooks (`src/api/`)
- `objects.ts`: useObjects, useObject, useCreateObject, useUpdateObject, useDeleteObject, useObjectsMeta (cities/clients autocomplete), useDiscoverObject, useSyncFromDB, useSyncFromSheets - `objects.ts`: useObjects, useObject, useCreateObject, useUpdateObject, useDeleteObject, useObjectsMeta,
- `devices.ts`: useDevices, useDevice, useCreateDevice, useUpdateDevice, useDeleteDevice, useImportDevicesPreview, useImportDevices, useAllDevices (global) useDiscoverObject, useSyncObject, useSyncSheets, usePreviewCSV, useImportCSV,
- `tasks.ts`: useTasks, useTaskDetail, useCreateTask, useTaskSSE **useDevices(objId)** — список устройств объекта,
- `alerts.ts`: useAlerts, useAcknowledgeAlert, useResolveAlert **useDevice(objId, deviceId)** — одно устройство (queryKey: `['device', objId, deviceId]`),
- `snapshots.ts`: useSnapshots, useSnapshotDetail, useSnapshotDiff, useCaptureSnapshot useCreateDevice, useUpdateDevice (инвалидирует `['devices', objId]` + `['device', objId, id]`), useDeleteDevice,
useDeleteAllDevices, useAllDevices (global, фильтры: category/city/client/object_id/status)
- `tasks.ts`: useTasks, useTask, useActions, useCreateTask,
**useDeviceTasks(deviceId)** — задачи по устройству (queryKey: `['tasks', 'device', deviceId]`)
- `alerts.ts`: useAlerts (params: status, object_id, **device_id**, limit, skip), useAcknowledgeAlert, useResolveAlert
- `snapshots.ts`: useSnapshots(objId, params?: {**device_id**?, label?, limit?, skip?}), useSnapshotDetail, useSnapshotDiff(objId, a, b)
- `racks.ts`: useRacks, useCreateRack, useUpdateRack, useDeleteRack
- `zones.ts`: useZones, useCreateZone, useDeleteZone
### DeviceItem interface (полный, `api/objects.ts`)
```typescript
interface DeviceItem {
id, object_id, ip, hostname, mac
vendor, model, firmware_version, external_id
category, role, source
rack_id, rack_name, rack_type, location
ssh_user_override, ssh_port_override
device_meta: Record<string, unknown> // JSONB
connection_params: Record<string, unknown> // JSONB
capabilities: string[]
status, last_seen, last_ping_ms, monitor_enabled
is_active, notes, created_at, updated_at
}
```
## Plugins (builtin) ## Plugins (builtin)

View file

@ -16,6 +16,7 @@ import {
Button, Button,
Col, Col,
Descriptions, Descriptions,
Divider,
Form, Form,
Input, Input,
Modal, Modal,