Add samy.js
This commit is contained in:
408
samy.js
Normal file
408
samy.js
Normal file
@@ -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 = `<strong> All tasks complete (${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)
|
||||
// =======================================================================
|
||||
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 });
|
||||
});
|
||||
Reference in New Issue
Block a user