Update StackMonkey.ps1
This commit is contained in:
806
StackMonkey.ps1
806
StackMonkey.ps1
@@ -856,419 +856,419 @@ function Invoke-ScriptMonkey {
|
|||||||
#
|
#
|
||||||
# 1) Inline your full original CSS here
|
# 1) Inline your full original CSS here
|
||||||
#
|
#
|
||||||
$style = @'
|
$style = @'
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
/* Cool Palette */
|
/* Cool Palette */
|
||||||
--background-color: rgba(18, 18, 18, 1);
|
--background-color: rgba(18, 18, 18, 1);
|
||||||
--border-color: rgba(255,127,0,0.25);
|
--border-color: rgba(255,127,0,0.25);
|
||||||
/* Neutral Colors */
|
/* Neutral Colors */
|
||||||
--white-color: rgba(255,255,255);
|
--white-color: rgba(255,255,255);
|
||||||
--gray-color: rgba(102,102,102);
|
--gray-color: rgba(102,102,102);
|
||||||
--dark-gray-color: rgba(51,51,51);
|
--dark-gray-color: rgba(51,51,51);
|
||||||
--light-gray-color: rgba(187,187,187);
|
--light-gray-color: rgba(187,187,187);
|
||||||
/* Sidebar Button Colors */
|
/* Sidebar Button Colors */
|
||||||
--btn-sidebar-light-gray: rgba(68,68,68);
|
--btn-sidebar-light-gray: rgba(68,68,68);
|
||||||
--btn-sidebar-blue: rgba(30,144,255,1);
|
--btn-sidebar-blue: rgba(30,144,255,1);
|
||||||
--btn-hover: rgba(0,86,179,1);
|
--btn-hover: rgba(0,86,179,1);
|
||||||
--btn-hover-scale: 1.05;
|
--btn-hover-scale: 1.05;
|
||||||
/* Button Colors */
|
/* Button Colors */
|
||||||
--btn-success: rgba(40,167,69);
|
--btn-success: rgba(40,167,69);
|
||||||
--btn-success-disabled: rgba(108,117,125);
|
--btn-success-disabled: rgba(108,117,125);
|
||||||
--btn-danger: rgba(220,53,69);
|
--btn-danger: rgba(220,53,69);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
margin: 0; padding: 0;
|
margin: 0; padding: 0;
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
color: var(--white-color);
|
color: var(--white-color);
|
||||||
height: 100%; overflow: hidden;
|
height: 100%; overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.logo-container { display: grid; grid-template-columns: auto 1fr; align-items: center; padding: 20px; }
|
|
||||||
.logo-container img { max-width:300px; height:auto; }
|
|
||||||
.subtitle { font-size: 1.2rem; color: var(--gray-color); margin-top: 0.5em; }
|
|
||||||
|
|
||||||
.container { display:flex; height:100vh; overflow:hidden; }
|
|
||||||
.sidebar { width:200px; background:var(--background-color); padding:10px; }
|
|
||||||
.sidebar button {
|
|
||||||
display:block; width:100%; margin-bottom:10px; padding:10px;
|
|
||||||
color:var(--white-color); background:var(--btn-sidebar-light-gray);
|
|
||||||
border:none; border-radius:5px; cursor:pointer; text-align:left;
|
|
||||||
transition:background-color 0.3s, transform 0.2s;
|
|
||||||
}
|
|
||||||
.sidebar button.active { background:var(--btn-sidebar-blue); }
|
|
||||||
.sidebar button:hover {
|
|
||||||
background:var(--btn-hover); transform:scale(var(--btn-hover-scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
position: relative;
|
|
||||||
flex:1;
|
|
||||||
padding:20px;
|
|
||||||
overflow-y:auto;
|
|
||||||
max-height:calc(100vh - 50px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-buttons {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
right: 20px;
|
|
||||||
display: flex;
|
|
||||||
gap: 10px; /* space between Exit and Run */
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.exit-button,
|
|
||||||
.run-button {
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--white-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Specific overrides */
|
|
||||||
.exit-button {
|
|
||||||
background-color: var(--btn-danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Specific overrides */
|
|
||||||
.run-button {
|
|
||||||
background-color: var(--btn-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tab-content { display:none; }
|
|
||||||
.tab-content.active { display:block; }
|
|
||||||
|
|
||||||
.columns-container {
|
|
||||||
display:flex; gap:20px; flex-wrap:wrap; align-items:flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* column styling, same as old script */
|
.logo-container { display: grid; grid-template-columns: auto 1fr; align-items: center; padding: 20px; }
|
||||||
.column {
|
.logo-container img { max-width:300px; height:auto; }
|
||||||
flex: 1; /* fill available space */
|
.subtitle { font-size: 1.2rem; color: var(--gray-color); margin-top: 0.5em; }
|
||||||
max-width: 45%; /* or whatever width you like */
|
|
||||||
border: 2px solid var(--border-color);
|
.container { display:flex; height:100vh; overflow:hidden; }
|
||||||
border-radius: 8px;
|
.sidebar { width:200px; background:var(--background-color); padding:10px; }
|
||||||
padding: 10px;
|
.sidebar button {
|
||||||
background-color: var(--dark-gray-color);
|
display:block; width:100%; margin-bottom:10px; padding:10px;
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
|
color:var(--white-color); background:var(--btn-sidebar-light-gray);
|
||||||
}
|
border:none; border-radius:5px; cursor:pointer; text-align:left;
|
||||||
.checkbox-group label {
|
transition:background-color 0.3s, transform 0.2s;
|
||||||
display:flex; align-items:center; margin-bottom:8px;
|
}
|
||||||
|
.sidebar button.active { background:var(--btn-sidebar-blue); }
|
||||||
|
.sidebar button:hover {
|
||||||
|
background:var(--btn-hover); transform:scale(var(--btn-hover-scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
flex:1;
|
||||||
|
padding:20px;
|
||||||
|
overflow-y:auto;
|
||||||
|
max-height:calc(100vh - 50px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed-buttons {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px; /* space between Exit and Run */
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exit-button,
|
||||||
|
.run-button {
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--white-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specific overrides */
|
||||||
|
.exit-button {
|
||||||
|
background-color: var(--btn-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specific overrides */
|
||||||
|
.run-button {
|
||||||
|
background-color: var(--btn-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.tab-content { display:none; }
|
||||||
|
.tab-content.active { display:block; }
|
||||||
|
|
||||||
|
.columns-container {
|
||||||
|
display:flex; gap:20px; flex-wrap:wrap; align-items:flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* column styling, same as old script */
|
||||||
|
.column {
|
||||||
|
flex: 1; /* fill available space */
|
||||||
|
max-width: 45%; /* or whatever width you like */
|
||||||
|
border: 2px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: var(--dark-gray-color);
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
.checkbox-group label {
|
||||||
|
display:flex; align-items:center; margin-bottom:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group { text-align:right; margin-top:20px; }
|
||||||
|
.exit-button {
|
||||||
|
background:var(--btn-danger); color:var(--white-color);
|
||||||
|
padding:10px 20px; border:none; border-radius:5px; cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#PasswordContainer, #dattoRmmContainer {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common styles for inputs, buttons, and selects */
|
||||||
|
#PasswordContainer input,
|
||||||
|
#PasswordContainer button,
|
||||||
|
#dattoRmmContainer select {
|
||||||
|
background-color: var(--dark-gray-color);
|
||||||
|
color: var(--white-color);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
width: 40%;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style specifically for the fetch button */
|
||||||
|
#PasswordContainer button {
|
||||||
|
background-color: var(--btn-sidebar-blue);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effect for the fetch button */
|
||||||
|
#PasswordContainer button:hover {
|
||||||
|
background-color: var(--btn-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag line */
|
||||||
|
#tagline {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: var(--light-gray-color);
|
||||||
|
font-weight: bold;
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:768px) {
|
||||||
|
.container { flex-direction:column; }
|
||||||
|
.sidebar { width:100%; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
'@
|
||||||
|
|
||||||
|
$script = @'
|
||||||
|
<script>
|
||||||
|
// =======================================================================
|
||||||
|
// Tab Navigation
|
||||||
|
// =======================================================================
|
||||||
|
const tabButtons = document.querySelectorAll(".tab-button");
|
||||||
|
const tabContents = document.querySelectorAll(".tab-content");
|
||||||
|
tabButtons.forEach(btn => {
|
||||||
|
btn.addEventListener("click", () => {
|
||||||
|
// clear active state
|
||||||
|
tabButtons.forEach(b => b.classList.remove("active"));
|
||||||
|
tabContents.forEach(c => c.classList.remove("active"));
|
||||||
|
// set new active
|
||||||
|
btn.classList.add("active");
|
||||||
|
document.getElementById(btn.dataset.tab).classList.add("active");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// initialize default tab on load
|
||||||
|
document.querySelector(".tab-button[data-tab='{{defaultPage}}Tab']").classList.add("active");
|
||||||
|
document.getElementById("{{defaultPage}}Tab").classList.add("active");
|
||||||
|
|
||||||
|
// =======================================================================
|
||||||
|
// Task Trigger
|
||||||
|
// =======================================================================
|
||||||
|
const tasks = [
|
||||||
|
{{tasksJsAll}}
|
||||||
|
];
|
||||||
|
|
||||||
|
// =======================================================================
|
||||||
|
// Column “Select All” toggling for On-Boarding
|
||||||
|
// =======================================================================
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now simulate change events after setting all checkboxes
|
||||||
|
setTimeout(() => {
|
||||||
|
children.forEach(cb => {
|
||||||
|
cb.dispatchEvent(new Event('change'));
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================================
|
||||||
|
// Un-check “Select All” if any child is unchecked (& re-check if all are checked)
|
||||||
|
// =======================================================================
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach listeners on load
|
||||||
|
['left','right'].forEach(col => {
|
||||||
|
document
|
||||||
|
.querySelectorAll(`#onboardTab input[type=checkbox][data-column=${col}]`)
|
||||||
|
.forEach(cb => cb.addEventListener('change', () => updateSelectAll(col)));
|
||||||
|
});
|
||||||
|
|
||||||
|
// =======================================================================
|
||||||
|
// DattoRMM Options
|
||||||
|
// =======================================================================
|
||||||
|
function toggleDattoRMMOptions() {
|
||||||
|
const master = document.getElementById('installDattoRMM');
|
||||||
|
const container = document.getElementById('installDattoRMMOptionsContainer');
|
||||||
|
if (!container) return;
|
||||||
|
container.style.display = master.checked ? 'block' : 'none';
|
||||||
|
container.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = master.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group { text-align:right; margin-top:20px; }
|
|
||||||
.exit-button {
|
|
||||||
background:var(--btn-danger); color:var(--white-color);
|
|
||||||
padding:10px 20px; border:none; border-radius:5px; cursor:pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#PasswordContainer, #dattoRmmContainer {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Common styles for inputs, buttons, and selects */
|
|
||||||
#PasswordContainer input,
|
|
||||||
#PasswordContainer button,
|
|
||||||
#dattoRmmContainer select {
|
|
||||||
background-color: var(--dark-gray-color);
|
|
||||||
color: var(--white-color);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
display: block;
|
|
||||||
width: 40%;
|
|
||||||
max-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style specifically for the fetch button */
|
|
||||||
#PasswordContainer button {
|
|
||||||
background-color: var(--btn-sidebar-blue);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hover effect for the fetch button */
|
|
||||||
#PasswordContainer button:hover {
|
|
||||||
background-color: var(--btn-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tag line */
|
|
||||||
#tagline {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: var(--light-gray-color);
|
|
||||||
font-weight: bold;
|
|
||||||
justify-self: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width:768px) {
|
|
||||||
.container { flex-direction:column; }
|
|
||||||
.sidebar { width:100%; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
'@
|
|
||||||
|
|
||||||
$script = @'
|
|
||||||
<script>
|
|
||||||
// =======================================================================
|
|
||||||
// Tab Navigation
|
|
||||||
// =======================================================================
|
|
||||||
const tabButtons = document.querySelectorAll(".tab-button");
|
|
||||||
const tabContents = document.querySelectorAll(".tab-content");
|
|
||||||
tabButtons.forEach(btn => {
|
|
||||||
btn.addEventListener("click", () => {
|
|
||||||
// clear active state
|
|
||||||
tabButtons.forEach(b => b.classList.remove("active"));
|
|
||||||
tabContents.forEach(c => c.classList.remove("active"));
|
|
||||||
// set new active
|
|
||||||
btn.classList.add("active");
|
|
||||||
document.getElementById(btn.dataset.tab).classList.add("active");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// initialize default tab on load
|
|
||||||
document.querySelector(".tab-button[data-tab='{{defaultPage}}Tab']").classList.add("active");
|
|
||||||
document.getElementById("{{defaultPage}}Tab").classList.add("active");
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Task Trigger
|
|
||||||
// =======================================================================
|
|
||||||
const tasks = [
|
|
||||||
{{tasksJsAll}}
|
|
||||||
];
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Column “Select All” toggling for On-Boarding
|
|
||||||
// =======================================================================
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Now simulate change events after setting all checkboxes
|
|
||||||
setTimeout(() => {
|
|
||||||
children.forEach(cb => {
|
|
||||||
cb.dispatchEvent(new Event('change'));
|
|
||||||
});
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Un-check “Select All” if any child is unchecked (& re-check if all are checked)
|
|
||||||
// =======================================================================
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach listeners on load
|
|
||||||
['left','right'].forEach(col => {
|
|
||||||
document
|
|
||||||
.querySelectorAll(`#onboardTab input[type=checkbox][data-column=${col}]`)
|
|
||||||
.forEach(cb => cb.addEventListener('change', () => updateSelectAll(col)));
|
|
||||||
});
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// DattoRMM Options
|
|
||||||
// =======================================================================
|
|
||||||
function toggleDattoRMMOptions() {
|
|
||||||
const master = document.getElementById('installDattoRMM');
|
|
||||||
const container = document.getElementById('installDattoRMMOptionsContainer');
|
|
||||||
if (!container) return;
|
|
||||||
container.style.display = master.checked ? 'block' : 'none';
|
|
||||||
container.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = master.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const master = document.getElementById('installDattoRMM');
|
|
||||||
if (master) master.addEventListener('change', toggleDattoRMMOptions);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Fetch Sites Handler
|
|
||||||
// =======================================================================
|
|
||||||
async function fetchSites() {
|
|
||||||
const pwd = document.getElementById("Password").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 = ''; // clear the loading message
|
|
||||||
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function triggerInstall() {
|
|
||||||
// disable the button so you can't double-click while work is in flight
|
|
||||||
const runBtn = document.querySelector('.run-button');
|
|
||||||
runBtn.disabled = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (const t of tasks) {
|
|
||||||
const cb = document.getElementById(t.id);
|
|
||||||
if (!cb || !cb.checked) continue;
|
|
||||||
|
|
||||||
if (t.id === 'installDattoRMM') {
|
|
||||||
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;
|
|
||||||
|
|
||||||
await fetch('/installDattoRMM', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({
|
|
||||||
checkedValues: sub,
|
|
||||||
UID: uid,
|
|
||||||
Name: name
|
|
||||||
})
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await fetch(t.handler, { method: 'GET' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error during triggerInstall:', e);
|
|
||||||
} finally {
|
|
||||||
// always re-enable, even if an error occurred
|
|
||||||
runBtn.disabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Shutdown Handler
|
|
||||||
// =======================================================================
|
|
||||||
function endSession() {
|
|
||||||
fetch("/quit", { method: "GET" })
|
|
||||||
.finally(() => window.close());
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Sub-Options Auto-Toggle for Tasks
|
|
||||||
// =======================================================================
|
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
// Auto-handle visibility and checking for tasks with sub-options
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Show/hide Password and RMM only if it's installDattoRMM
|
|
||||||
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(); // call once on load
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// ===========================================
|
|
||||||
// ─ rotating tagline ───────────────────────────────
|
|
||||||
// ===========================================
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const taglines = [
|
const master = document.getElementById('installDattoRMM');
|
||||||
"Fast deployments, no monkey business.",
|
if (master) master.addEventListener('change', toggleDattoRMMOptions);
|
||||||
"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");
|
|
||||||
let idx = Math.floor(Math.random() * taglines.length);
|
|
||||||
el.textContent = taglines[idx];
|
|
||||||
|
|
||||||
setInterval(() => {
|
|
||||||
idx = (idx + 1) % taglines.length;
|
|
||||||
el.textContent = taglines[idx];
|
|
||||||
}, 10_000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// when the browser window is closed (X), notify the server to quit
|
|
||||||
window.addEventListener('beforeunload', () => {
|
|
||||||
// keepalive: true ensures the request is sent even as the page unloads
|
|
||||||
fetch('/quit', { method: 'GET', keepalive: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
// =======================================================================
|
||||||
|
// Fetch Sites Handler
|
||||||
|
// =======================================================================
|
||||||
|
async function fetchSites() {
|
||||||
|
const pwd = document.getElementById("Password").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 = ''; // clear the loading message
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function triggerInstall() {
|
||||||
|
// disable the button so you can't double-click while work is in flight
|
||||||
|
const runBtn = document.querySelector('.run-button');
|
||||||
|
runBtn.disabled = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (const t of tasks) {
|
||||||
|
const cb = document.getElementById(t.id);
|
||||||
|
if (!cb || !cb.checked) continue;
|
||||||
|
|
||||||
|
if (t.id === 'installDattoRMM') {
|
||||||
|
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;
|
||||||
|
|
||||||
|
await fetch('/installDattoRMM', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
checkedValues: sub,
|
||||||
|
UID: uid,
|
||||||
|
Name: name
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await fetch(t.handler, { method: 'GET' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error during triggerInstall:', e);
|
||||||
|
} finally {
|
||||||
|
// always re-enable, even if an error occurred
|
||||||
|
runBtn.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================================================
|
||||||
|
// Shutdown Handler
|
||||||
|
// =======================================================================
|
||||||
|
function endSession() {
|
||||||
|
fetch("/quit", { method: "GET" })
|
||||||
|
.finally(() => window.close());
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================================================
|
||||||
|
// Sub-Options Auto-Toggle for Tasks
|
||||||
|
// =======================================================================
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
// Auto-handle visibility and checking for tasks with sub-options
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Show/hide Password and RMM only if it's installDattoRMM
|
||||||
|
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(); // call once on load
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ===========================================
|
||||||
|
// ─ rotating tagline ───────────────────────────────
|
||||||
|
// ===========================================
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
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");
|
||||||
|
let idx = Math.floor(Math.random() * taglines.length);
|
||||||
|
el.textContent = taglines[idx];
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
idx = (idx + 1) % taglines.length;
|
||||||
|
el.textContent = taglines[idx];
|
||||||
|
}, 10_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// when the browser window is closed (X), notify the server to quit
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
// keepalive: true ensures the request is sent even as the page unloads
|
||||||
|
fetch('/quit', { method: 'GET', keepalive: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
'@
|
||||||
|
|
||||||
#
|
#
|
||||||
# 3) The HTML skeleton with placeholders
|
# 3) The HTML skeleton with placeholders
|
||||||
|
|||||||
Reference in New Issue
Block a user