Commit Graph

81 Commits

Author SHA1 Message Date
7d52297f76 fix(deploy): apply VM config reliably after clone
- wait for clone lock release before config.put (cross-node clones kept
  lock past wait_for_task, dropping ALL requested settings silently)
- configure_vm applies params in independent groups (compute/network/
  cloudinit/disk) with per-group errors and lock retry
- set sockets=1 with cores so total vCPU matches request
- keep template net0 model/MAC/options, replace only bridge
- disk resize: pick boot disk via regex over all buses, report failures
- surface config errors as deploy warnings in UI toast instead of
  silent success

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 02:31:21 +05:00
3622747371 fix(dashboard): make donut tooltip readable
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Theme tokens are oklch(); wrapping them in hsl(var(--card)) produced an
invalid, transparent tooltip background so the label blended into the
card. Use the oklch vars directly and force readable text colour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 19:48:58 +05:00
daa75e1502 feat(dashboard): show top disk stats as a donut chart
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Replace the disk I/O area chart with a donut where each slice is a node
sized by its disk usage % (disk_pct). More meaningful than I/O, which is
near-zero most of the time. Use real node names (name|node) in the legend
instead of node-0/node-1, and drop the now-unused RRD fetch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 19:41:54 +05:00
381e7ae821 i18n(instances): localize bulk operation toolbar buttons
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Translate Start/Stop/Delete/Clear and the selected-count label in the bulk
actions toolbar (add instances.selected_count key). Also includes node label
display in the node filter/table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 19:02:11 +05:00
1f9a51b0be fix(dashboard): render disk chart; show server name as node label
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
- Dashboard "ТОП статистика по диску" was stuck on "Загрузка...": the
  node name in the dashboard_metrics WS payload is `name`, not `node`, so
  the RRD query stayed disabled. Use name fallback and unwrap the
  {data:[...]} response shape.
- Instances list + detail page: show the panel-side server name (from the
  add-server form) in the "Узел" column/label instead of the Proxmox node
  hostname. Real node is still used for all API calls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 18:56:27 +05:00
fd47241394 feat(instances): bulk restart action and live bulk-operation status tracking
Add a Restart button to the bulk-selection toolbar (backend already supports
bulk_restart) and track bulk operation progress like instance creation:
per-row status overlay on affected instances plus a progress bar driven by
task_update WebSocket events.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 18:56:20 +05:00
1d1bd33e03 fix(instances): show RAM in correct units (MiB to bytes) in config
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
VM config `memory` is in MiB but formatBytes treated it as bytes,
rendering "2 KB RAM" instead of "2 GB RAM". Convert before formatting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 18:47:47 +05:00
35dcbfd18f feat(quotas): per-user resource limits for VM/LXC deployment
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 54s
Deploy to Production / Trigger production update (push) Successful in 8s
Add per-user quotas (max instances, vCPU, RAM, disk) enforced at deploy
time and surfaced to users self-service.

Backend:
- UserQuota model (one-to-one, NULL = unlimited) + migration #28
- quota_service: usage from vm_instances cache, check_quota raises 429
- enforce in VM (templates.py) and LXC (lxc.py) deploy paths
- RBAC quota:view / quota:manage, granted to admin
- admin API GET/PUT /admin/api/users/{id}/quota
- self-service GET /settings/api/quota
- tighten VM list isolation via can_view_all_instances

Frontend:
- admin quota dialog in UsersPage with usage bars
- quota card on Settings page (own limits)
- remaining-quota hint in CreateInstanceWizard config step
- useUserQuota/useSetUserQuota, useMyQuota hooks; RU/EN locales

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 18:15:02 +05:00
d59d787bed feat(dashboard): redesign in VMmanager style with multi-node disk chart
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
- Three-panel top row: cluster overview, tasks-today, node gauges
- Cluster overview: IPv4 available in stats row alongside nodes/VM count,
  RAM/disk progress bars, RAM overselling ratio
- Tasks panel: completed/running/queued/errors/total from useAllTasks
- Node panel: SVG circular CPU & RAM gauges
- Bottom: nodes table with top-10 tabs (by CPU or disk%) + Grafana-style
  disk I/O chart with parallel useQueries for top-5 nodes, CartesianGrid,
  per-node colored lines and legend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 03:26:41 +05:00
28fa6eb5b4 fix(instances): reset stale server/node filter on workspace switch
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 10s
Persisted instances-server-filter/instances-node-filter kept an old id
after switching workspace, emptying the list and showing the raw id in
the Select. Drop the filter to 'all' when the server/node is no longer
present in the active workspace.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 03:25:44 +05:00
7117c8adc3 feat(images): collapsible sections with persisted state
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Make 'Cloud-образы ВМ' and 'LXC-шаблоны' section headers clickable to
collapse/expand. State is saved to localStorage per section so it
survives reloads and navigation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 03:24:55 +05:00
845c8024c4 feat(auth): forgot/reset password pages and wiring
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m16s
Deploy to Production / Trigger production update (push) Successful in 8s
- ForgotPasswordPage and ResetPasswordPage in the split-screen auth layout.
- "Forgot password" link on the login page now routes to /forgot-password.
- Public routes /forgot-password and /reset-password; reset page validates
  the token on mount and gates the form, with show/hide password and
  confirmation matching.
- i18n keys (reset.*) for ru/en.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 03:24:19 +05:00
65e14585c5 chore(frontend): make vite dev runnable outside Docker
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Allow overriding the dep-optimizer cache dir via VITE_CACHE_DIR (the
default node_modules/.vite is root-owned when built in Docker) and honor
a PORT injected by the harness. Both default to prior behavior when the
env vars are unset, so Docker builds are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 03:05:18 +05:00
89962a7f20 feat(auth): split-screen login with geometric pattern
Redesign the login page into a two-column layout: a decorative
geometric line pattern on the left (hidden on mobile) and the form on
the right with the PVEmanager logo on top and a footer with a language
switcher + copyright. Add a password show/hide toggle and a "forgot
password" link. Login logic (username/password) is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 03:05:18 +05:00
03b574777c fix(images): default arch to node platform; fix node selector placeholder
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Successful in 55s
Deploy to Production / Trigger production update (push) Failing after 10s
- arch filter defaults to amd64 and auto-syncs to the selected node's arch
  (useNodeArch), so amd64 nodes no longer show arm64 images by default
- node Select no longer renders raw '__none__'; shows 'Нода' placeholder
  and a disabled hint when no nodes are reachable

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:28:04 +05:00
d2f57e13db feat(images): Phase 3 UI — custom mirror manager (admin)
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Successful in 51s
Deploy to Production / Trigger production update (push) Failing after 10s
Admin-only MirrorsManager on ImagesPage: list/add/edit/delete custom
mirrors with kind/arch/url/template/checksum fields; mirror CRUD hooks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:17:00 +05:00
ec8f4904a1 feat(images): Phase 2 UI — make-template toggle in download dialog
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Successful in 51s
Deploy to Production / Trigger production update (push) Failing after 11s
qcow2: 'make VM template' toggle (default on) with disk-storage picker,
cores/memory/bridge and cloud-init user/password fields; routes to
image_template task kind.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:11:20 +05:00
32e06fe922 feat(images): frontend Images page, catalog hooks, download dialog
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Successful in 55s
Deploy to Production / Trigger production update (push) Failing after 11s
Phase 1 UI for VM image mirror feature:
- use-image-catalog hook (catalog, lxc repo templates, target storages, download)
- ImagesPage: server/node context, arch/search filters, cloud + LXC sections
- DownloadImageDialog: storage picker, background download via DeployTask
- CatalogImage/ImageMirror types, image_download/image_template task kinds
- sidebar nav 'Images' + /images route

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 22:57:16 +05:00
f67ee24155 Merge branch 'feature/metrics-history'
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 50s
Deploy to Production / Trigger production update (push) Successful in 7s
2026-06-22 02:47:45 +05:00
9e9cac15e1 fix(disk-resize): pass node, real disk picker, shrink guard, grow output
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 49s
Deploy to Production / Trigger production update (push) Successful in 8s
Settings tab disk-resize UX:
- useResizeDisk/useUpdateConfig now send the required node query param,
  fixing the 422 "Field required" error.
- disk device is chosen from the VM's actual disks (defaults to the boot
  disk) instead of a hardcoded scsi0.
- show the current disk size, prefill it, and block shrinking before
  hitting Proxmox (which rejects it).
- render the growpart output and a grown/not-grown status after resize.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 02:43:12 +05:00
ddd37060fe fix(metrics): move disk-fill chart to the very end after IOPS
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 01:23:32 +05:00
7a5485c63c fix(metrics): reorder graph cards, per-chart hover cursor, readable dark tooltip
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 01:21:04 +05:00
0f7c5a44df fix(metrics): move disk-fill chart up next to CPU and memory
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 21:57:52 +05:00
e90ad2e0d2 fix(metrics): keep previous series on NIC/range switch to avoid full-grid reload
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 21:57:52 +05:00
074983a1f6 fix(metrics): correct cpu/disk% chart scaling, evict stale collector state, lighten nic query, drop polling & dead RRD code
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 21:35:02 +05:00
4f224d90cf feat(metrics): graphs tab reads stored history with date range, NIC selector, IOPS & disk% 2026-06-21 21:35:02 +05:00
0aed32f998 feat(metrics): add useVMMetrics hook 2026-06-21 21:35:02 +05:00
df2c59eb3f chore: pre-existing WIP (overview/realtime/format/types/use-instances)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 21:35:02 +05:00
a4b99c2383 fix(instances): type multiSelectFilter as FilterFn<any> for column reuse
Some checks failed
Deploy to Production / Trigger production update (push) Failing after 10s
Allows the shared column filter to be attached to typed VMInstance columns
without a FilterFn<unknown> assignability error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:28:01 +05:00
5c6bb013c9 feat(instances): surface PVE lock state in the instances list
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 50s
Deploy to Production / Trigger production update (push) Successful in 8s
Backend returns the live `lock` field (clone/create/migrate/...) and the
list shows an amber badge next to the status, so an instance that is
still being cloned no longer looks like a ready stopped VM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 00:38:41 +05:00
6b3700f496 feat(clone): richer clone dialog with node, storage and owner pickers
Expose target node, target storage, owner (admin-only) and description
in the clone dialog, wired to the existing backend params. Reset the
form on open and fix the cramped label/field spacing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 00:38:41 +05:00
8ebef3d10e feat(instances): add column filters and VM config formatter
Add ColumnFilter component (Popover-based faceted filter) and a
formatVmConfig helper rendering "N vCPU / X GB RAM / Y GB".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 00:38:14 +05:00
0d4406024f i18n(instances): translate settings tab labels and tidy field spacing
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Move hardcoded English labels (compute resources, disk resize, raw
config, etc.) to i18n keys and replace ad-hoc mt-1 with consistent
space-y-1.5 between labels and inputs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 23:40:12 +05:00
a1aaa97b24 feat(backups): add search field to backup files and amber VM-picker checkboxes
Filter backup files by VMID, volume, notes or node in real time, with a
distinct empty state for no-match. Tint the job dialog VM-picker
checkboxes with the brand amber accent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 23:40:12 +05:00
315aaed58b fix(instances): widen VM management dropdown so menu items fit on one line
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 23:40:12 +05:00
aa0ea459cd fix(snapshots): send required node param and add storage-support hint
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 49s
Deploy to Production / Trigger production update (push) Successful in 9s
useCreateSnapshot omitted the required ?node= query param, so creation
failed with a 422. Pass node through, and add a UI hint plus a clear
error message when the VM storage does not support snapshots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 23:35:42 +05:00
3cac5f6c2a fix(api-client): format FastAPI error detail instead of [object Object]
new Error(error.detail) produced "[object Object]" when detail was an
array (422 validation errors) or object. Add formatApiError() to extract
a readable message and widen ApiError.detail to match real responses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 23:35:34 +05:00
14cac12191 feat(ui): replace all native confirm() dialogs with styled ConfirmDialog
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Add ConfirmDialogProvider + useConfirm hook (Promise-based API) so every
window.confirm() in the app is replaced with a consistent themed modal.

Replaced in 11 files (16 call-sites):
- Settings: update panel action
- Templates: delete template
- Storages: delete storage
- SSH Keys: delete key
- Nodes: delete server
- NodeNetworks: delete interface, apply pending, revert pending
- HAResources: remove HA resource
- SDNManager: apply SDN, delete zone/vnet, delete subnet
- IPAM: release allocation, delete pool, cleanup orphans

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 09:09:26 +05:00
00cbe9716b fix(settings): remove unimplemented Webhook URL field from notifications
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
The webhook_url field was stored in DB but never used to send
notifications — removing it from UI avoids misleading users.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 08:53:40 +05:00
cc2bb349e5 fix(settings): notifications/profile form UX fixes
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 48s
Deploy to Production / Trigger production update (push) Successful in 8s
- Profile tab: add language selector (per-user), add toast on save/error
  for profile info and password change (clears fields only on success)
- Notifications: remove Chat ID field from admin Telegram section —
  it was never saved to DB and only served as a test-only input;
  testing is now done via "Мои уведомления" → Send test
- Add missing onSuccess/onError toasts to SMTP and Telegram save buttons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 08:47:37 +05:00
9ced08b88c feat(settings): per-user language preference and panel improvements
Store UI language per user (users.language column, migration 26).
Language selector moves from Panel tab to Profile tab — each account
picks its own language, saved to DB and applied via i18n.changeLanguage()
on save so the interface switches immediately.

Panel tab: panel_name read-only (falls back to env PANEL_NAME),
log_retention_days field exposed in UI, language selector removed.
Panel API accepts panel_name in PUT so it can be overridden in DB
without touching the env var.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 08:47:18 +05:00
4451b3e45a fix(settings): align SMTP/security settings fields with API
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 46s
Deploy to Production / Trigger production update (push) Successful in 8s
Rename SMTP request/response fields (host/port/username/password/from_email/tls)
and point security settings hooks at /admin/api/security/settings with a typed
SecuritySettings shape. Add minutes / security_saved i18n keys.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 08:26:39 +05:00
a507e3c4bc feat(metrics): real-time VM disk fill, IOPS and network I/O
Add live per-disk usage, disk read/write and network in/out rates to the
instance Overview tab, the instances list and the dashboard top-loaded list.

Backend:
- get_vm_fsinfo() pulls per-filesystem usage via QEMU guest agent
- metrics_broadcaster computes I/O rates (bytes/sec) from cumulative counters
- instances-list loop now refreshes each running VM via status/current
  (1s-granular) instead of cluster/resources (10s pvestatd), with bounded
  concurrency, and paces both realtime loops to a 1s cadence

Frontend:
- OverviewTab: per-disk cards, Network I/O and I/O-rate cards via WS
- InstancesPage: Net and Disk I/O columns; Disk% shown for LXC only
- DashboardPage: top-loaded list overlaid with realtime metrics

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 08:26:29 +05:00
965fb858da fix(ipam): require resource name before allocating IP and fill missing fields on VM link
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 46s
Deploy to Production / Trigger production update (push) Successful in 8s
- Validate resource name in auto-allocate form before sending request
- Fill resource_name, proxmox_node, resource_type, mac_address when syncing
  a VM that already has matching vmid/server_id but missing metadata

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 03:23:57 +05:00
7546883393 feat(dashboard): show top 10 loaded running instances by CPU
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 02:59:43 +05:00
64924e50ed fix(instances): persist server filter selection across navigation and page reload
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 02:53:45 +05:00
5b781f9e16 fix(ipam): show VM id/name/IP in IP map tooltip
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
The IP map tooltip read e.ip, but the backend ip-map endpoint returns
the address as ip_address, so the IP rendered as 'undefined'. Align the
IPAMIPMapEntry type with the backend response and build the tooltip from
proxmox_vmid, resource_name/hostname and ip_address.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 02:27:04 +05:00
14a6f5ace7 feat(ipam): expose network/pool/allocation management in UI
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Wire up backend IPAM endpoints that had no frontend:
- edit/delete network (with force) on network detail page
- full pool CRUD (create/edit/delete) on network detail page
- manual allocation create + edit on allocations page
- IP address map visualization per network

Add missing hooks (useCreatePool/useUpdatePool/useDeletePool,
useUpdateAllocation), force support in useDeleteNetwork, typed
ip-map entries, writable allocation fields, and RU/EN locale keys.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 02:12:40 +05:00
f18ba4d597 revert(nodes): remove server auto-setup feature
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m35s
Deploy to Production / Trigger production update (push) Successful in 8s
Drop the /api/servers/auto-setup endpoint, the AutoSetupDialog UI and the
useAutoSetupServer hook. Rename the auto_setup locale strings to
auto_create_token. Also normalize the storages response to an array.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:18:38 +05:00
493814f44f fix(dashboard): populate recent-activity feed from audit logs
Align the frontend with the /logs API contract: the endpoint returns
{ logs: [...] } with a created_at field, not { items: [...] } / timestamp.
Add a Vite dev-proxy rule for /logs so the request reaches the backend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:18:30 +05:00