Files
SAMY/samy.js
2025-12-01 02:59:04 -05:00

482 lines
15 KiB
JavaScript

// 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 = `<strong> All tasks completed (${completedTasks}/${totalTasks})</strong>`;
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 = '<option disabled selected>Loading sites...</option>';
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 =
'<option disabled selected>Error loading sites</option>';
alert("Failed to fetch sites. Check password and try again.");
}
}
// =======================================================================
// Run Selected (main trigger)
// =======================================================================
// =======================================================================
// 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 {
// Figure out which standard tasks are checked
const checkedTasks = tasks.filter((t) => {
const cb = document.getElementById(t.id);
return cb && cb.checked;
});
// Rename checkbox / textbox
const renameCB = document.getElementById("chkRenameComputer");
const newNameInput = document.getElementById("txtNewComputerName");
// Count how many "extra" tasks (rename) we're doing
let extraTasks = 0;
if (renameCB && renameCB.checked) {
extraTasks = 1; // treat rename as one task in the progress counter
}
setTotalTaskCount(checkedTasks.length + extraTasks);
// 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);
}
}
// 4. Rename computer (LAST)
if (renameCB && renameCB.checked && newNameInput) {
const newName = newNameInput.value.trim();
// Same basic rules you'll enforce server-side
const nameIsValid =
newName.length > 0 &&
newName.length <= 15 &&
/^[A-Za-z0-9-]+$/.test(newName);
if (!nameIsValid) {
alert(
"Invalid computer name. Must be 1-15 characters and only letters, numbers, and hyphens."
);
// still mark it as a failed task so progress reaches 100%
logProgress("Rename computer", false);
} else {
try {
await fetch("/renameComputer", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ newName }),
});
logProgress("Rename computer", true);
} catch (e) {
console.error("Error calling /renameComputer:", e);
logProgress("Rename computer", false);
}
}
}
} catch (e) {
console.error("triggerInstall fatal error:", e);
} finally {
runBtn.disabled = false;
if (totalTasks > 0) {
console.info(
`[Info] All tasks completed (${completedTasks}/${totalTasks})`
);
}
// Best-effort notification to the server
try {
await fetch("/tasksCompleted", { method: "POST" });
} catch (err) {
console.warn("Could not notify server about completion:", err);
}
}
}
// =======================================================================
// 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();
});
// NEW: Rename computer checkbox -> show/hide text box
const renameCheckbox = document.getElementById("chkRenameComputer");
const renameBlock = document.getElementById("renameComputerBlock");
if (renameCheckbox && renameBlock) {
function updateRenameVisibility() {
renameBlock.style.display = renameCheckbox.checked ? "block" : "none";
}
renameCheckbox.addEventListener("change", updateRenameVisibility);
// Ensure correct initial state on load
updateRenameVisibility();
}
// 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 });
});