feat(instances): show saved VM configuration on the Settings tab
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 10s
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 10s
Read-only card on the instance Settings tab surfacing the panel-stored config (cores/memory/disk/network/cloud-init) via the saved-config endpoint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useVMConfig, useUpdateConfig, useResizeDisk, useVMOwner, useSetVMOwner, useExecuteScript } from '@/hooks/use-instances';
|
||||
import { useVMConfig, useUpdateConfig, useResizeDisk, useVMOwner, useSetVMOwner, useExecuteScript, useSavedConfig } from '@/hooks/use-instances';
|
||||
import { useProfile } from '@/hooks/use-settings';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { toast } from 'sonner';
|
||||
@@ -137,6 +137,45 @@ function ExecuteScriptCard({ serverId, vmid, node }: { serverId: number; vmid: n
|
||||
);
|
||||
}
|
||||
|
||||
function SavedConfigCard({ serverId, vmid }: { serverId: number; vmid: number }) {
|
||||
const { t } = useTranslation();
|
||||
const { data } = useSavedConfig(serverId, vmid);
|
||||
if (!data?.found || !data.config) return null;
|
||||
const c = data.config;
|
||||
|
||||
const rows: [string, string | number | undefined][] = [
|
||||
[t('instances.saved_name'), c.name],
|
||||
['vCPU', c.cores],
|
||||
[`${t('nodes.memory')} (MB)`, c.memory],
|
||||
[`${t('nodes.disk')} (GB)`, c.disk_size],
|
||||
['IP', c.ip_address ? `${c.ip_address}${c.ip_prefix ? `/${c.ip_prefix}` : ''}` : undefined],
|
||||
[t('netif.gateway'), c.gateway],
|
||||
['DNS', c.nameserver],
|
||||
[t('instances.cloud_user'), c.cloud_init_user],
|
||||
];
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-semibold flex items-center gap-2">
|
||||
<Settings className="h-4 w-4" />{t('instances.saved_config')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-3 text-xs text-muted-foreground">{t('instances.saved_config_hint')}</p>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-1 text-sm">
|
||||
{rows.filter(([, v]) => v != null && v !== '').map(([label, v]) => (
|
||||
<div key={label} className="flex justify-between gap-2 border-b py-1">
|
||||
<span className="text-muted-foreground">{label}</span>
|
||||
<span className="font-mono">{String(v)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SettingsTab({ serverId, vmid, type, node }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { data: config } = useVMConfig(serverId, vmid, type, node);
|
||||
@@ -282,6 +321,8 @@ export default function SettingsTab({ serverId, vmid, type, node }: Props) {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<SavedConfigCard serverId={serverId} vmid={vmid} />
|
||||
|
||||
{/* Raw Config */}
|
||||
{config && (
|
||||
<Card>
|
||||
|
||||
@@ -280,6 +280,26 @@ export function useSnapshotArchiveDetail(archiveId: number | null) {
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Saved config (DB) ====================
|
||||
|
||||
export interface SavedVMConfig {
|
||||
found: boolean;
|
||||
config?: {
|
||||
cores?: number; memory?: number; disk_size?: number;
|
||||
ip_address?: string; ip_prefix?: number; gateway?: string; nameserver?: string;
|
||||
cloud_init_user?: string; cloud_init_password?: string; ssh_keys?: string;
|
||||
name?: string; template_id?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export function useSavedConfig(serverId: number, vmid: number, enabled = true) {
|
||||
return useQuery<SavedVMConfig>({
|
||||
queryKey: ['vm-saved-config', serverId, vmid],
|
||||
queryFn: () => apiClient.get(`/proxmox/api/${serverId}/vm/${vmid}/saved-config`),
|
||||
enabled: enabled && serverId > 0 && vmid > 0,
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== Execute script (guest agent) ====================
|
||||
|
||||
export interface ExecuteScriptResult {
|
||||
|
||||
@@ -177,6 +177,10 @@
|
||||
"no_owner": "No owner",
|
||||
"owner_saved": "Owner updated",
|
||||
"owner_hint": "Assign this instance to a user (admin only).",
|
||||
"saved_config": "Saved configuration",
|
||||
"saved_config_hint": "Values stored by the panel at creation/reinstall time.",
|
||||
"saved_name": "Name",
|
||||
"cloud_user": "Cloud-init user",
|
||||
"execute_script": "Execute script",
|
||||
"execute_script_hint": "Runs via the QEMU guest agent (must be installed and running in the VM).",
|
||||
"interpreter": "Interpreter",
|
||||
|
||||
@@ -177,6 +177,10 @@
|
||||
"no_owner": "Без владельца",
|
||||
"owner_saved": "Владелец обновлён",
|
||||
"owner_hint": "Назначить инстанс пользователю (только админ).",
|
||||
"saved_config": "Сохранённая конфигурация",
|
||||
"saved_config_hint": "Значения, сохранённые панелью при создании/переустановке.",
|
||||
"saved_name": "Имя",
|
||||
"cloud_user": "Cloud-init пользователь",
|
||||
"execute_script": "Выполнить скрипт",
|
||||
"execute_script_hint": "Выполняется через QEMU guest agent (должен быть установлен и запущен в VM).",
|
||||
"interpreter": "Интерпретатор",
|
||||
|
||||
Reference in New Issue
Block a user