From d27c216d388edb17418e4d24706850d0eb8856a5 Mon Sep 17 00:00:00 2001 From: Stephan Yelle Date: Wed, 26 Nov 2025 17:50:37 -0500 Subject: [PATCH] Add samy.js --- samy.js | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 samy.js diff --git a/samy.js b/samy.js new file mode 100644 index 0000000..461b473 --- /dev/null +++ b/samy.js @@ -0,0 +1,408 @@ +// Use globals provided by the PowerShell-generated HTML bridge +const tasks = (window.SAMY_TASKS || []); +const defaultPage = (window.SAMY_DEFAULT_PAGE || "onboard"); + +let completedTasks = 0; +let totalTasks = 0; + +// Progress / title handling +function setTotalTaskCount(count) { + totalTasks = count; + completedTasks = 0; + updateTitle(); +} + +function logProgress(label, isSuccess) { + const statusBox = document.getElementById("status-box"); + completedTasks++; + updateTitle(); + + const msg = isSuccess + ? ` ${completedTasks}/${totalTasks} done: ${label}` + : ` ${completedTasks}/${totalTasks} failed: ${label}`; + + const div = document.createElement("div"); + div.style.color = isSuccess ? "lime" : "red"; + div.textContent = msg; + statusBox?.appendChild(div); + + if (completedTasks === totalTasks) { + const finalMsg = document.createElement("div"); + finalMsg.style.marginTop = "10px"; + finalMsg.innerHTML = ` All tasks complete (${completedTasks}/${totalTasks})`; + statusBox?.appendChild(finalMsg); + + document.title = ` ScriptMonkey - Complete (${completedTasks}/${totalTasks})`; + + const sound = new Audio( + "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAESsAACJWAAACABAAZGF0YQAAAAA=" + ); + sound.play().catch(() => {}); + flashTitle(document.title); + } +} + +function updateTitle() { + document.title = `ScriptMonkey - ${completedTasks}/${totalTasks} Done`; +} + +function flashTitle(finalTitle) { + let flashes = 0; + const interval = setInterval(() => { + document.title = document.title === "" ? finalTitle : ""; + flashes++; + if (flashes >= 10) { + clearInterval(interval); + document.title = finalTitle; + } + }, 800); +} + +// ======================================================================= +// Tab Navigation +// ======================================================================= +document.addEventListener("DOMContentLoaded", () => { + const tabButtons = document.querySelectorAll(".tab-button"); + const tabContents = document.querySelectorAll(".tab-content"); + + if (!tabButtons?.length || !tabContents?.length) { + console.error("ScriptMonkey: no tab buttons or tab contents found."); + return; + } + + tabButtons.forEach((btn) => { + btn.addEventListener("click", () => { + tabButtons.forEach((b) => b.classList.remove("active")); + tabContents.forEach((c) => c.classList.remove("active")); + + btn.classList.add("active"); + const targetId = btn.dataset.tab; + const target = document.getElementById(targetId); + if (target) target.classList.add("active"); + }); + }); + + // Default tab from PS (onboard/offboard/tweaks/SVSApps) + const defaultTabId = `${defaultPage}Tab`; + const defaultBtn = document.querySelector(`.tab-button[data-tab='${defaultTabId}']`); + const defaultTab = document.getElementById(defaultTabId); + if (defaultBtn) defaultBtn.classList.add("active"); + if (defaultTab) defaultTab.classList.add("active"); +}); + +// ======================================================================= +// Onboarding: Select-all left/right columns +// ======================================================================= +function toggleColumn(col) { + const master = document.getElementById( + `selectAll${col[0].toUpperCase() + col.slice(1)}Checkbox` + ); + const children = document.querySelectorAll( + `#onboardTab input[type=checkbox][data-column=${col}]` + ); + + children.forEach((cb) => { + cb.checked = master.checked; + }); + + setTimeout(() => { + children.forEach((cb) => { + cb.dispatchEvent(new Event("change")); + }); + }, 0); +} + +function updateSelectAll(col) { + const master = document.getElementById( + `selectAll${col[0].toUpperCase() + col.slice(1)}Checkbox` + ); + const children = document.querySelectorAll( + `#onboardTab input[type=checkbox][data-column=${col}]` + ); + + master.checked = Array.from(children).every((cb) => cb.checked); +} + +document.addEventListener("DOMContentLoaded", () => { + ["left", "right"].forEach((col) => { + document + .querySelectorAll(`#onboardTab input[type=checkbox][data-column=${col}]`) + .forEach((cb) => + cb.addEventListener("change", () => updateSelectAll(col)) + ); + }); +}); + +// ======================================================================= +// Off-boarding Select All +// ======================================================================= +function toggleOffboardAll() { + const master = document.getElementById("offboardSelectAll"); + const children = document.querySelectorAll( + "#offboardTab input[type=checkbox]:not(#offboardSelectAll)" + ); + + children.forEach((cb) => { + cb.checked = master.checked; + }); +} + +function updateOffboardSelectAll() { + const master = document.getElementById("offboardSelectAll"); + if (!master) return; + + const children = document.querySelectorAll( + "#offboardTab input[type=checkbox]:not(#offboardSelectAll)" + ); + if (!children.length) { + master.checked = false; + return; + } + + master.checked = Array.from(children).every((cb) => cb.checked); +} + +document.addEventListener("DOMContentLoaded", () => { + const offChildren = document.querySelectorAll( + "#offboardTab input[type=checkbox]:not(#offboardSelectAll)" + ); + + if (!offChildren?.length) return; + + offChildren.forEach((cb) => + cb.addEventListener("change", updateOffboardSelectAll) + ); + updateOffboardSelectAll(); +}); + +// ======================================================================= +// DattoRMM options + Enter key handling +// ======================================================================= +function toggleDattoRMMOptions() { + const master = document.getElementById("installDattoRMM"); + const container = document.getElementById("installDattoRMMOptionsContainer"); + if (!container) return; + const checked = master?.checked; + container.style.display = checked ? "block" : "none"; + container + .querySelectorAll('input[type="checkbox"]') + .forEach((cb) => (cb.checked = checked)); +} + +document.addEventListener("DOMContentLoaded", () => { + const master = document.getElementById("installDattoRMM"); + if (master) { + master.addEventListener("change", toggleDattoRMMOptions); + } + + const passwordField = document.getElementById("Password"); + const goButton = document.querySelector("button[onclick='fetchSites()']"); + + if (passwordField && goButton) { + passwordField.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + goButton.click(); + } + }); + } + + const siteDropdown = document.getElementById("dattoDropdown"); + const runButton = document.querySelector(".run-button"); + + if (siteDropdown && runButton) { + siteDropdown.addEventListener("keydown", (e) => { + if (e.key === "Enter" && siteDropdown.value) { + runButton.click(); + } + }); + } +}); + +// ======================================================================= +// Fetch Sites handler (calls /getpw) +// ======================================================================= +async function fetchSites() { + const pwdInput = document.getElementById("Password"); + const pwd = pwdInput?.value; + if (!pwd) { + alert("Please enter the password."); + return; + } + + const dropdown = document.getElementById("dattoDropdown"); + dropdown.innerHTML = ''; + + try { + const resp = await fetch("/getpw", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ password: pwd }), + }); + + if (!resp.ok) throw "HTTP " + resp.status; + + const sites = await resp.json(); + dropdown.innerHTML = ""; + + sites.forEach((site) => { + const option = document.createElement("option"); + option.value = site.UID; + option.textContent = site.Name; + dropdown.appendChild(option); + }); + + document.getElementById("dattoRmmContainer").style.display = "block"; + } catch (e) { + console.error(e); + dropdown.innerHTML = + ''; + alert("Failed to fetch sites. Check password and try again."); + } +} + +// ======================================================================= +// Run Selected (main trigger) +// ======================================================================= +async function triggerInstall() { + const runBtn = document.querySelector(".run-button"); + if (!runBtn) return; + + runBtn.disabled = true; + + const statusBox = document.getElementById("status-box"); + if (statusBox) statusBox.innerHTML = ""; + + try { + const checkedTasks = tasks.filter((t) => { + const cb = document.getElementById(t.id); + return cb && cb.checked; + }); + setTotalTaskCount(checkedTasks.length); + + // 1. DattoRMM first + const dattoCB = document.getElementById("installDattoRMM"); + if (dattoCB && dattoCB.checked) { + try { + const sub = Array.from( + document.querySelectorAll(".sub-option-installDattoRMM:checked") + ).map((x) => x.value); + const dropdown = document.getElementById("dattoDropdown"); + const uid = dropdown?.value; + const name = dropdown?.selectedOptions?.[0]?.text || "Datto"; + + await fetch("/installDattoRMM", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ checkedValues: sub, UID: uid, Name: name }), + }); + logProgress("Install DattoRMM", true); + } catch (e) { + logProgress("Install DattoRMM", false); + console.error(e); + } + } + + // 2. SVSMSP module second + const svsCB = document.getElementById("installSVSMSPModule"); + if (svsCB && svsCB.checked) { + try { + await fetch("/installSVSMSPModule", { method: "GET" }); + logProgress("Install SVSMSP Module", true); + } catch (e) { + logProgress("Install SVSMSP Module", false); + console.error(e); + } + } + + // 3. Remaining tasks + for (const t of tasks) { + if (["installDattoRMM", "installSVSMSPModule"].includes(t.id)) continue; + + const cb = document.getElementById(t.id); + if (!cb || !cb.checked) continue; + + try { + await fetch(t.handler, { method: "GET" }); + logProgress(t.label || t.id, true); + } catch (e) { + logProgress(t.label || t.id, false); + console.error(`Error running ${t.id}:`, e); + } + } + } catch (e) { + console.error("triggerInstall fatal error:", e); + } finally { + runBtn.disabled = false; + } +} + +// ======================================================================= +// Shutdown handler (Exit button & window close) +// ======================================================================= +function endSession() { + fetch("/quit", { method: "GET" }).finally(() => window.close()); +} + +// Sub-options auto-toggle, tagline rotation, and beforeunload hook +document.addEventListener("DOMContentLoaded", () => { + // Sub-option containers + const tasksWithSubOptions = document.querySelectorAll( + '[id$="OptionsContainer"]' + ); + + tasksWithSubOptions.forEach((container) => { + const taskId = container.id.replace("OptionsContainer", ""); + const masterCheckbox = document.getElementById(taskId); + if (!masterCheckbox) return; + + function updateVisibility() { + const checked = masterCheckbox.checked; + container.style.display = checked ? "block" : "none"; + container + .querySelectorAll('input[type="checkbox"]') + .forEach((cb) => (cb.checked = checked)); + + if (taskId === "installDattoRMM") { + const pwdBox = document.getElementById("PasswordContainer"); + const rmmBox = document.getElementById("dattoRmmContainer"); + if (pwdBox) pwdBox.style.display = checked ? "block" : "none"; + if (rmmBox) rmmBox.style.display = checked ? "block" : "none"; + } + } + + masterCheckbox.addEventListener("change", updateVisibility); + updateVisibility(); + }); + + // Tagline rotation + const taglines = [ + "Fast deployments, no monkey business.", + "Bananas for better builds.", + "Deploy without flinging code.", + "Tame your stack. Unleash the monkey.", + "Monkey see, monkey deploy.", + "Deploy smarter -- with a monkey on your team.", + "Don't pass the monkey -- let it deploy.", + "No more monkeying around. Stack handled.", + "Own your stack. But let the monkey do the work.", + "Why throw code when the monkey's got it?", + "Deployments so easy, a monkey could do it. Ours does.", + "Monkey in the stack, not on your back.", + ]; + + const el = document.getElementById("tagline"); + if (el) { + let idx = Math.floor(Math.random() * taglines.length); + el.textContent = taglines[idx]; + + setInterval(() => { + idx = (idx + 1) % taglines.length; + el.textContent = taglines[idx]; + }, 10_000); + } +}); + +// notify server on window close +window.addEventListener("beforeunload", () => { + fetch("/quit", { method: "GET", keepalive: true }); +});