wire disk budget step + VM provisioning into installer wizard

This commit is contained in:
Krystie
2026-08-13 01:27:43 -07:00
parent 2a5b1736b8
commit 4894e07469
2 changed files with 62 additions and 11 deletions
@@ -18,6 +18,7 @@
</div>
</div>
<script src="./disk-budget-step.js"></script>
<script src="./wizard.js"></script>
</body>
</html>
+61 -11
View File
@@ -44,6 +44,12 @@ const state = {
email: '',
caName: 'DashCaddy Local CA'
},
// Disk budget / VM sandbox configuration
diskBudget: {
preset: 'balanced',
diskSizeGB: 30,
customSizeGB: 30
},
// Detected network IPs
network: {
lanIP: '',
@@ -91,6 +97,7 @@ const steps = [
{ id: 'welcome', title: 'Welcome' },
{ id: 'dependencies', title: 'Dependencies' },
{ id: 'folder', title: 'Install Path' },
{ id: 'disk', title: 'Storage' },
{ id: 'tier', title: 'Tier' },
{ id: 'access', title: 'Access' },
{ id: 'dns', title: 'DNS' },
@@ -179,7 +186,7 @@ function setupEventListeners() {
state.result.dashboardUrl = data.dashboardUrl;
state.result.installPath = data.installPath;
state.result.health = data.health || null;
state.currentStep = 8; // Move to complete step
state.currentStep = 9; // Move to complete step
render();
});
@@ -207,6 +214,21 @@ function setupEventListeners() {
state.uninstall.error = data.error;
render();
});
// VM provisioning progress / error listeners
window.electronAPI.onVMProgress((data) => {
if (state.installation.status === 'running') {
state.installation.progress = Math.min(data.progress || 0, 5);
state.installation.currentTask = data.task || 'Provisioning sandboxed virtual disk...';
render();
}
});
window.electronAPI.onVMError((data) => {
state.installation.status = 'error';
state.installation.error = data.error || 'VM provisioning failed';
render();
});
}
// Navigation
@@ -219,7 +241,7 @@ function nextStep() {
case 1: // Dependencies
checkDependencies();
break;
case 7: // Installation
case 8: // Installation
startInstallation();
break;
}
@@ -420,6 +442,33 @@ async function startInstallation() {
render();
try {
// ── Provision sandboxed VM disk before installation ─────────
if (state.diskBudget && state.diskBudget.diskSizeGB) {
state.installation.currentTask = 'Provisioning sandboxed virtual disk...';
state.installation.progress = 1;
render();
const domain = state.domainMode === 'public'
? state.domain.publicDomain
: state.domainMode === 'custom-tld'
? state.domain.tld
: null;
const vmResult = await window.electronAPI.vmProvision({
diskSizeGB: state.diskBudget.diskSizeGB,
installPath: state.paths.install,
apiPort: state.branding.apiPort,
domain
});
if (!vmResult || !vmResult.success) {
throw new Error((vmResult && vmResult.error) || 'VM provisioning failed');
}
state.installation.completedTasks.push('Virtual disk provisioned');
state.installation.progress = 5;
render();
}
await window.electronAPI.runInstallation({
installPath: state.paths.install,
dockerDataPath: state.paths.dockerData,
@@ -511,12 +560,13 @@ function renderCurrentStep() {
case 0: return renderWelcome();
case 1: return renderDependencies();
case 2: return renderFolderSelection();
case 3: return renderTierSelection();
case 4: return renderAccessMode();
case 5: return renderDNSConfiguration();
case 6: return renderDashboardSetup();
case 7: return renderInstallation();
case 8: return renderComplete();
case 3: return renderDiskBudgetStep();
case 4: return renderTierSelection();
case 5: return renderAccessMode();
case 6: return renderDNSConfiguration();
case 7: return renderDashboardSetup();
case 8: return renderInstallation();
case 9: return renderComplete();
default: return '';
}
}
@@ -1125,7 +1175,7 @@ function renderComplete() {
function renderFooter() {
const isFirst = state.currentStep === 0;
const isLast = state.currentStep === steps.length - 1;
const isInstalling = state.currentStep === 7 && state.installation.status === 'running';
const isInstalling = state.currentStep === 8 && state.installation.status === 'running';
// Determine if user can proceed
let canProceed = true;
@@ -1136,7 +1186,7 @@ function renderFooter() {
case 2: // Folder
canProceed = !!state.paths.install;
break;
case 4: // Access mode
case 5: // Access mode
if (state.domainMode === 'public') {
canProceed = !!state.domain.publicDomain && !!state.domain.email;
} else if (state.domainMode === 'custom-tld') {
@@ -1165,7 +1215,7 @@ function renderFooter() {
// Button text
let nextLabel = 'Next';
if (state.currentStep === 6) nextLabel = 'Install';
if (state.currentStep === 7) nextLabel = 'Install';
return `
<div class="step-footer">