feat(instances): add VM owner assignment and snapshot archive view
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Surface two previously-unused admin endpoints: assign/clear a VM's owner from the instance Settings tab, and a /instances/snapshot-archives page listing snapshots preserved from deleted guests (with config detail), linked from the Instances header for admins. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -213,6 +213,73 @@ export function useRollbackSnapshot(serverId: number, vmid: number, type: string
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Owner (admin) ====================
|
||||
|
||||
export interface VMOwnerInfo {
|
||||
owner_id: number | null;
|
||||
owner: { id: number; username: string; full_name?: string } | null;
|
||||
users: { id: number; username: string; full_name?: string }[];
|
||||
}
|
||||
|
||||
export function useVMOwner(serverId: number, vmid: number, enabled = true) {
|
||||
return useQuery<VMOwnerInfo>({
|
||||
queryKey: ['vm-owner', serverId, vmid],
|
||||
queryFn: () => apiClient.get(`/proxmox/api/${serverId}/vm/${vmid}/owner`),
|
||||
enabled: enabled && serverId > 0 && vmid > 0,
|
||||
retry: false,
|
||||
});
|
||||
}
|
||||
|
||||
export function useSetVMOwner(serverId: number, vmid: number) {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (user_id: number | null) =>
|
||||
apiClient.put(`/proxmox/api/${serverId}/vm/${vmid}/owner`, { user_id }),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ['vm-owner', serverId, vmid] }),
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Snapshot archives (admin audit) ====================
|
||||
|
||||
export interface SnapshotArchive {
|
||||
id: number;
|
||||
server_id: number;
|
||||
server_name?: string;
|
||||
vmid: number;
|
||||
vm_name?: string;
|
||||
vm_type?: string;
|
||||
node?: string;
|
||||
snapname: string;
|
||||
description?: string;
|
||||
snaptime?: number;
|
||||
parent?: string;
|
||||
vmstate?: number;
|
||||
snapshot_config?: string;
|
||||
deleted_by?: string;
|
||||
deletion_reason?: string;
|
||||
archived_at?: string;
|
||||
}
|
||||
|
||||
export function useSnapshotArchives(params?: { server_id?: number; vmid?: number; limit?: number; offset?: number }) {
|
||||
const qs = new URLSearchParams();
|
||||
if (params?.server_id) qs.set('server_id', String(params.server_id));
|
||||
if (params?.vmid) qs.set('vmid', String(params.vmid));
|
||||
if (params?.limit) qs.set('limit', String(params.limit));
|
||||
if (params?.offset) qs.set('offset', String(params.offset));
|
||||
return useQuery<{ total: number; offset: number; limit: number; archives: SnapshotArchive[] }>({
|
||||
queryKey: ['snapshot-archives', params],
|
||||
queryFn: () => apiClient.get(`/proxmox/api/snapshot-archives?${qs}`),
|
||||
});
|
||||
}
|
||||
|
||||
export function useSnapshotArchiveDetail(archiveId: number | null) {
|
||||
return useQuery<SnapshotArchive>({
|
||||
queryKey: ['snapshot-archive', archiveId],
|
||||
queryFn: () => apiClient.get(`/proxmox/api/snapshot-archives/${archiveId}`),
|
||||
enabled: !!archiveId,
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Power Actions ====================
|
||||
interface PowerActionResult {
|
||||
status: string;
|
||||
|
||||
Reference in New Issue
Block a user