async function handleSetupAndSettingsActions(event, target, action, repository) { if (action === "setup-run-preflight") await runSystemPreflight({ setup: true }); else if (action === "setup-continue") { if (ui.systemPreflight?.summary?.ready) { ui.setupStep = 1; render(); } } else if (action === "setup-validate") { setLoading(true, "Validating Gitea connection…"); try { ui.setupValidation = await window.forgeflow.validateGitea(ui.setupDraft); ui.setupDraft.baseUrl = ui.setupValidation.baseUrl; ui.setupDraft.user = ui.setupValidation.user; ui.setupStep = 2; } catch (error) { showToast("Connection failed", error.message, "error"); } setLoading(false); } else if (action === "setup-add-root") { const root = await window.forgeflow.selectDirectory({ title: "Select a development folder", }); if (root && !ui.setupDraft.roots.includes(root)) ui.setupDraft.roots.push(root); render(); } else if (action === "setup-remove-root") { ui.setupDraft.roots.splice(Number(target.dataset.index), 1); render(); } else if (action === "setup-next") { if (ui.setupStep === 2) { ui.setupStep = 3; ui.setupDraft.discovered = []; render(); try { ui.setupDraft.discovered = await window.forgeflow.discoverRepositories( ui.setupDraft.roots, ); } catch (error) { showToast("Discovery failed", error.message, "error"); } ui.setupStep = 4; render(); } } else if (action === "setup-back") { ui.setupStep = Math.max(0, ui.setupStep - 1); render(); } else if (action === "setup-finish") { setLoading(true, "Saving configuration…"); try { const result = await window.forgeflow.completeSetup({ baseUrl: ui.setupDraft.baseUrl, token: ui.setupDraft.token, user: ui.setupDraft.user, workspaceRoots: ui.setupDraft.roots, }); ui.boot.state = result.state; await refreshRepositories(false); showToast( "Setup complete", result.tokenState.persistent ? "Your token is stored securely." : "Your token is available for this session only.", "success", ); } catch (error) { showToast("Could not complete setup", error.message, "error"); } setLoading(false); } else if (action === "check-updates") { ui.updateChecking = true; render(); try { ui.updateStatus = await window.forgeflow.checkForUpdates(); showToast( ui.updateStatus.available ? "Update available" : "ForgeFlow is current", ui.updateStatus.available ? `Version ${ui.updateStatus.remoteVersion} can be downloaded.` : `Version ${ui.updateStatus.currentVersion} is the newest release.`, ui.updateStatus.available ? "success" : "info", ); } catch (error) { showToast("Update check failed", error.message, "error"); } ui.updateChecking = false; render(); } else if (action === "save-update-settings") { const updates = { owner: document.querySelector("#update-owner").value.trim(), repo: document.querySelector("#update-repo").value.trim(), branch: document.querySelector("#update-branch").value.trim(), autoCheck: document.querySelector("#update-auto-check").value === "true", }; try { ui.boot.state = await window.forgeflow.setUpdatePreferences(updates); ui.updateStatus = null; showToast( "Update settings saved", "The next check will use this repository and branch.", "success", ); } catch (error) { showToast("Could not save update settings", error.message, "error"); } render(); } else if (action === "download-update") { setLoading(true, "Downloading and verifying the exact ForgeFlow update…"); try { ui.updateStatus = await window.forgeflow.downloadUpdate(); showToast( "Update downloaded", `Version ${ui.updateStatus.remoteVersion} passed the integrity check.`, "success", ); } catch (error) { showToast("Update download failed", error.message, "error"); } setLoading(false); } else if (action === "apply-update") { if ( !confirm( `Apply ForgeFlow ${ui.updateStatus?.remoteVersion || "update"} now? ForgeFlow closes, validates the update and restarts automatically.`, ) ) return; setLoading(true, "Launching safe updater…"); try { await window.forgeflow.applyUpdate(); showToast( "Update launched", "ForgeFlow will close and restart after validation.", "success", ); } catch (error) { showToast("Could not launch update", error.message, "error"); setLoading(false); } } else if (action === "use-server-password") { ui.modal = { type: "server-password", serverId: target.dataset.serverId, retry: { type: target.dataset.retry || "scan" }, }; render(); } else if (action === "confirm-server-password") { const server = (ui.boot?.state?.servers || []).find((item) => item.id === target.dataset.serverId); const password = document.querySelector("#quick-server-password")?.value || ""; if (!server || !password) { showToast("Password required", "Enter the Unraid SSH password.", "error"); return; } const retry = ui.modal?.retry || { type: "scan" }; setLoading(true, "Switching the server connection to password authentication…"); try { const saved = await window.forgeflow.saveServer( { ...server, authType: "password", privateKeyPath: "" }, password, "", ); ui.boot.state = saved.state; const tested = await window.forgeflow.testServer(server.id); ui.boot.state = tested.state; ui.modal = null; showToast("Server password saved", "ForgeFlow will no longer use an SSH key for this server.", "success"); if (retry.type === "deploy") { const retryRepository = ui.repositories.find((item) => item.fullName === retry.repositoryFullName); if (retryRepository) ui.selectedRepoId = retryRepository.id; await executeDeployment(retry.profileId); } else { await refreshDeploymentTruth(true); } } catch (error) { showToast("Server authentication failed", error.message, "error"); } setLoading(false); } else if (action === "open-add-server") { ui.modal = { type: "server-config", serverId: null, authType: "password", }; render(); } else if (action === "edit-server") { const server = (ui.boot.state.servers || []).find( (item) => item.id === target.dataset.serverId, ); ui.modal = { type: "server-config", serverId: target.dataset.serverId, authType: server?.authType || "password", }; render(); } else if (action === "select-private-key") { const keyPath = await window.forgeflow.selectKeyFile({ title: "Select SSH private key", defaultPath: document.querySelector("#server-private-key")?.value || undefined, }); if (keyPath) document.querySelector("#server-private-key").value = keyPath; } else if (action === "save-server") { const authType = document.querySelector("#server-auth-type").value; const server = { id: target.dataset.serverId || undefined, name: document.querySelector("#server-name").value.trim(), host: document.querySelector("#server-host").value.trim(), port: Number(document.querySelector("#server-port").value), username: document.querySelector("#server-username").value.trim(), authType, basePath: document.querySelector("#server-base-path").value.trim(), scanRoots: document.querySelector("#server-scan-roots").value.split(/\r?\n/).map((value) => value.trim()).filter(Boolean), scanExcludes: document.querySelector("#server-scan-excludes").value.split(",").map((value) => value.trim()).filter(Boolean), privateKeyPath: document.querySelector("#server-private-key")?.value.trim() || "", hostFingerprint: document .querySelector("#server-fingerprint") .value.trim(), }; const password = document.querySelector("#server-password")?.value || ""; const passphrase = document.querySelector("#server-passphrase")?.value || ""; setLoading(true, "Saving encrypted SSH configuration…"); try { const result = await window.forgeflow.saveServer( server, password, passphrase, ); ui.boot.state = result.state; ui.modal = null; showToast( "Server saved", "Run Test & trust before creating a deployment.", "success", ); } catch (error) { showToast("Could not save server", error.message, "error"); } setLoading(false); } else if (action === "test-server") { setLoading( true, "Checking SSH identity, Docker, Compose and optional Git capabilities…", ); try { let result = await window.forgeflow.testServer(target.dataset.serverId); if (result.needsTrust) { const approved = confirm( `Verify this fingerprint on the SSH server before trusting it:\n\n${result.fingerprint}\n\nServer: ${result.server.host}:${result.server.port}\n\nTrust this exact host identity and continue with authentication?`, ); if (!approved) { showToast("SSH trust cancelled", "No credentials were sent and the host identity was not saved.", "info"); setLoading(false); return true; } result = await window.forgeflow.testServer(target.dataset.serverId, result.fingerprint); } ui.boot.state = result.state; const capabilities = result.capabilities || {}; const deploymentReady = capabilities.docker && capabilities.dockerReady && capabilities.compose; showToast( deploymentReady ? "SSH server ready" : "SSH connected with missing tools", `${result.server.name} presented ${result.fingerprint}. Docker ${capabilities.dockerReady ? "ready" : "unavailable"}; Compose ${capabilities.compose ? "ready" : "missing"}.`, deploymentReady ? "success" : "info", ); } catch (error) { showToast("SSH test failed", error.message, "error"); } setLoading(false); } else if (action === "delete-server") { if ( !confirm("Delete this server and all deployment profiles linked to it?") ) return; try { ui.boot.state = await window.forgeflow.deleteServer( target.dataset.serverId, ); ui.modal = null; await refreshRepositories(false); showToast( "Server deleted", "Linked SSH deployment profiles were removed.", "success", ); } catch (error) { showToast("Could not delete server", error.message, "error"); } } else if (action === "add-root") { const root = await window.forgeflow.selectDirectory({ title: "Add development folder", }); if (root && !ui.boot.state.workspaceRoots.includes(root)) ui.boot.state.workspaceRoots.push(root); render(); } else if (action === "remove-root") { ui.boot.state.workspaceRoots.splice(Number(target.dataset.index), 1); render(); } else if (action === "save-roots") { const roots = [...document.querySelectorAll("[data-root-index]")] .map((input) => input.value.trim()) .filter(Boolean); setLoading(true, "Saving workspace folders…"); try { ui.boot.state = await window.forgeflow.setWorkspaceRoots(roots); await refreshRepositories(false); showToast( "Folders saved", "Repository discovery has been refreshed.", "success", ); } catch (error) { showToast("Could not save folders", error.message, "error"); } setLoading(false); } else if (action === "save-gitea-settings") { const baseUrl = document.querySelector("#settings-gitea-url").value.trim(); const token = document.querySelector("#settings-gitea-token").value.trim(); setLoading(true, "Validating Gitea…"); try { const result = await window.forgeflow.updateGitea({ baseUrl, token }); ui.boot.state = result.state; await refreshRepositories(false); showToast( "Gitea connected", `Signed in as ${result.validation.user.login}.`, "success", ); } catch (error) { showToast("Connection failed", error.message, "error"); } setLoading(false); } else if (action === "save-preferences") { const preferences = { autoRefresh: document.querySelector("#pref-auto-refresh").value === "true", repositoryPollSeconds: Number( document.querySelector("#pref-repo-poll").value, ), operationPollSeconds: Number( document.querySelector("#pref-operation-poll").value, ), fetchIntervalMinutes: Number( document.querySelector("#pref-fetch-interval").value, ), preferredCloneProtocol: document.querySelector("#pref-clone-protocol") .value, }; setLoading(true, "Saving background settings…"); try { ui.boot.state = await window.forgeflow.setPreferences(preferences); await refreshRepositories(false); showToast( "Settings saved", "Background awareness has been updated.", "success", ); } catch (error) { showToast("Could not save settings", error.message, "error"); } setLoading(false); } else if (action === "save-desktop-preferences") { const splitArgs = (selector) => document .querySelector(selector) .value.split("|") .map((item) => item.trim()) .filter(Boolean); const preferences = { editor: { executable: document .querySelector("#pref-editor-executable") .value.trim(), args: splitArgs("#pref-editor-args"), }, terminal: { executable: document .querySelector("#pref-terminal-executable") .value.trim(), args: splitArgs("#pref-terminal-args"), }, notificationsEnabled: document.querySelector("#pref-notifications") .checked, trayEnabled: document.querySelector("#pref-tray").checked, closeToTray: document.querySelector("#pref-close-tray").checked, startAtLogin: document.querySelector("#pref-login").checked, }; try { ui.boot.state = await window.forgeflow.setPreferences(preferences); showToast( "Desktop integration saved", "Editor, terminal, tray and notification settings are active.", "success", ); } catch (error) { showToast("Could not save desktop integration", error.message, "error"); } render(); } else if ( action === "export-config-backup" || action === "import-config-backup" ) { const passphrase = document.querySelector("#backup-passphrase").value; if (passphrase.length < 12) { showToast("Passphrase too short", "Use at least 12 characters.", "error"); return; } setLoading( true, action === "export-config-backup" ? "Encrypting configuration backup…" : "Decrypting and validating configuration…", ); try { const result = action === "export-config-backup" ? await window.forgeflow.exportConfigurationBackup(passphrase) : await window.forgeflow.importConfigurationBackup(passphrase); if (result?.state) { ui.boot.state = result.state; await refreshRepositories(false); } if (result) showToast( action === "export-config-backup" ? "Encrypted backup created" : "Configuration restored", action === "export-config-backup" ? result.filePath : `Backup from ${result.exportedAt} imported; credentials were preserved only where already present.`, "success", ); } catch (error) { showToast("Configuration backup failed", error.message, "error"); } setLoading(false); } else return false; return true; }