From 7b8c1ebdf1f0958be1507d2b26b814064e158f80 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner Date: Fri, 5 Dec 2025 15:53:50 +0100 Subject: [PATCH] feat: Add default and advanced install method selection - Add ConfigurationModal component for selecting default or advanced installation mode - Default mode: Uses predefined defaults with minimal user input (hostname from slug, vmbr0, dhcp, etc.) - Advanced mode: Full configuration modal with all environment variables customizable - Add support for IPv4 CIDR input when network mode is 'static' - Add support for IPv6 static address input when IPv6 method is 'static' - Implement password formatting as '-password ' for build.func compatibility - Auto-enable SSH when password or SSH keys are provided - Add storage selection dropdowns filtered by server node assignment - Pass environment variables through entire execution stack (frontend -> WebSocket -> SSH/local execution) - Add mode environment variable (always set to 'default' for script execution) - Update ExecutionModeModal to show 'Advanced (Beta)' option --- server.js | 5 +- src/app/_components/ConfigurationModal.tsx | 74 +++++++++++----------- src/app/_components/ExecutionModeModal.tsx | 2 +- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/server.js b/server.js index e304fb8..864acf7 100644 --- a/server.js +++ b/server.js @@ -82,6 +82,7 @@ const handle = app.getRequestHandler(); * @property {number} [cloneCount] * @property {string[]} [hostnames] * @property {'lxc'|'vm'} [containerType] + * @property {Record} [envVars] */ class ScriptExecutionHandler { @@ -421,7 +422,9 @@ class ScriptExecutionHandler { // Add envVars to environment if (envVars && typeof envVars === 'object') { for (const [key, value] of Object.entries(envVars)) { - envWithVars[key] = String(value); + /** @type {Record} */ + const envRecord = envWithVars; + envRecord[key] = String(value); } } diff --git a/src/app/_components/ConfigurationModal.tsx b/src/app/_components/ConfigurationModal.tsx index c8197a4..34cf120 100644 --- a/src/app/_components/ConfigurationModal.tsx +++ b/src/app/_components/ConfigurationModal.tsx @@ -75,7 +75,7 @@ export function ConfigurationModal({ var_cpu: resources?.cpu ?? 1, var_ram: resources?.ram ?? 1024, var_disk: resources?.hdd ?? 4, - var_unprivileged: resources?.privileged === false ? 1 : (resources?.privileged === true ? 0 : 1), + var_unprivileged: script?.privileged === false ? 1 : (script?.privileged === true ? 0 : 1), // Network defaults var_net: 'dhcp', @@ -196,19 +196,19 @@ export function ConfigurationModal({ newErrors.var_ipv6_static = 'Invalid IPv6 address'; } } - if (!validatePositiveInt(advancedVars.var_cpu)) { + if (!validatePositiveInt(advancedVars.var_cpu as string | number | undefined)) { newErrors.var_cpu = 'Must be a positive integer'; } - if (!validatePositiveInt(advancedVars.var_ram)) { + if (!validatePositiveInt(advancedVars.var_ram as string | number | undefined)) { newErrors.var_ram = 'Must be a positive integer'; } - if (!validatePositiveInt(advancedVars.var_disk)) { + if (!validatePositiveInt(advancedVars.var_disk as string | number | undefined)) { newErrors.var_disk = 'Must be a positive integer'; } - if (advancedVars.var_mtu && !validatePositiveInt(advancedVars.var_mtu)) { + if (advancedVars.var_mtu && !validatePositiveInt(advancedVars.var_mtu as string | number | undefined)) { newErrors.var_mtu = 'Must be a positive integer'; } - if (advancedVars.var_vlan && !validatePositiveInt(advancedVars.var_vlan)) { + if (advancedVars.var_vlan && !validatePositiveInt(advancedVars.var_vlan as string | number | undefined)) { newErrors.var_vlan = 'Must be a positive integer'; } } @@ -237,7 +237,7 @@ export function ConfigurationModal({ var_cpu: resources?.cpu ?? 1, var_ram: resources?.ram ?? 1024, var_disk: resources?.hdd ?? 4, - var_unprivileged: resources?.privileged === false ? 1 : (resources?.privileged === true ? 0 : 1), + var_unprivileged: script?.privileged === false ? 1 : (script?.privileged === true ? 0 : 1), }; if (containerStorage) { @@ -385,7 +385,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_cpu', parseInt(e.target.value) || 1)} className={errors.var_cpu ? 'border-destructive' : ''} /> @@ -400,7 +400,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_ram', parseInt(e.target.value) || 1024)} className={errors.var_ram ? 'border-destructive' : ''} /> @@ -415,7 +415,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_disk', parseInt(e.target.value) || 4)} className={errors.var_disk ? 'border-destructive' : ''} /> @@ -428,7 +428,7 @@ export function ConfigurationModal({ Unprivileged { if (e.target.value === 'static') { updateAdvancedVar('var_net', 'static'); @@ -492,7 +492,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_brg', e.target.value)} placeholder="vmbr0" /> @@ -503,7 +503,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_gateway', e.target.value)} placeholder="Auto" className={errors.var_gateway ? 'border-destructive' : ''} @@ -517,7 +517,7 @@ export function ConfigurationModal({ IPv6 Method updateAdvancedVar('var_ipv6_static', e.target.value)} placeholder="2001:db8::1/64" className={errors.var_ipv6_static ? 'border-destructive' : ''} @@ -558,7 +558,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_vlan', e.target.value ? parseInt(e.target.value) : '')} placeholder="None" className={errors.var_vlan ? 'border-destructive' : ''} @@ -574,7 +574,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_mtu', e.target.value ? parseInt(e.target.value) : 1500)} placeholder="1500" className={errors.var_mtu ? 'border-destructive' : ''} @@ -589,7 +589,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_mac', e.target.value)} placeholder="Auto" className={errors.var_mac ? 'border-destructive' : ''} @@ -604,7 +604,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_ns', e.target.value)} placeholder="Auto" className={errors.var_ns ? 'border-destructive' : ''} @@ -626,7 +626,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_hostname', e.target.value)} placeholder={slug} /> @@ -637,7 +637,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_pw', e.target.value)} placeholder="Random (empty = auto-login)" /> @@ -648,7 +648,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_tags', e.target.value)} placeholder="community-script" /> @@ -665,7 +665,7 @@ export function ConfigurationModal({ Enable SSH updateAdvancedVar('var_ssh_authorized_key', e.target.value)} placeholder="ssh-rsa AAAA..." /> @@ -696,7 +696,7 @@ export function ConfigurationModal({ Nesting (Docker) updateAdvancedVar('var_fuse', parseInt(e.target.value))} className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground focus:ring-2 focus:ring-ring focus:outline-none" > @@ -722,7 +722,7 @@ export function ConfigurationModal({ Keyctl updateAdvancedVar('var_mknod', parseInt(e.target.value))} className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground focus:ring-2 focus:ring-ring focus:outline-none" > @@ -749,7 +749,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_mount_fs', e.target.value)} placeholder="nfs,cifs" /> @@ -759,7 +759,7 @@ export function ConfigurationModal({ Protection updateAdvancedVar('var_timezone', e.target.value)} placeholder="System" /> @@ -790,7 +790,7 @@ export function ConfigurationModal({ Verbose updateAdvancedVar('var_apt_cacher', e.target.value)} className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground focus:ring-2 focus:ring-ring focus:outline-none" > @@ -817,7 +817,7 @@ export function ConfigurationModal({ updateAdvancedVar('var_apt_cacher_ip', e.target.value)} placeholder="192.168.1.10" className={errors.var_apt_cacher_ip ? 'border-destructive' : ''} @@ -838,7 +838,7 @@ export function ConfigurationModal({ Container Storage updateAdvancedVar('var_template_storage', e.target.value)} className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground focus:ring-2 focus:ring-ring focus:outline-none" > diff --git a/src/app/_components/ExecutionModeModal.tsx b/src/app/_components/ExecutionModeModal.tsx index 5cca184..fce78ca 100644 --- a/src/app/_components/ExecutionModeModal.tsx +++ b/src/app/_components/ExecutionModeModal.tsx @@ -195,7 +195,7 @@ export function ExecutionModeModal({ isOpen, onClose, onExecute, scriptName, scr size="default" className="flex-1" > - Advanced + Advanced (Beta)