add deadmans key, fix downloading randomly stopping halfway through, add scripts to context menu.
This commit is contained in:
@@ -537,6 +537,63 @@ function renderPluginMenu(plugins) {
|
||||
}
|
||||
}
|
||||
|
||||
function renderScriptMenu(scripts) {
|
||||
const section = document.getElementById("script-section");
|
||||
const container = document.getElementById("script-menu");
|
||||
if (!section || !container) return;
|
||||
container.innerHTML = "";
|
||||
|
||||
if (!Array.isArray(scripts) || scripts.length === 0) {
|
||||
section.classList.add("hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
section.classList.remove("hidden");
|
||||
const sorted = scripts.slice().sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
|
||||
for (const script of sorted) {
|
||||
const btn = document.createElement("button");
|
||||
btn.className = "ctx-item ctx-plugin-item";
|
||||
btn.dataset.scriptId = script.id;
|
||||
btn.title = `${script.scriptType} — click to open in Scripts with this client preselected`;
|
||||
|
||||
const labelIcon = document.createElement("i");
|
||||
labelIcon.className = "fa-solid fa-scroll ctx-icon text-cyan-400";
|
||||
btn.appendChild(labelIcon);
|
||||
|
||||
const label = document.createElement("span");
|
||||
label.className = "ctx-plugin-label";
|
||||
label.textContent = script.name || script.id;
|
||||
btn.appendChild(label);
|
||||
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "ctx-plugin-badge";
|
||||
badge.textContent = script.scriptType || "";
|
||||
btn.appendChild(badge);
|
||||
|
||||
container.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
let _scriptMenuCache = null;
|
||||
async function loadSavedScriptsForMenu() {
|
||||
const section = document.getElementById("script-section");
|
||||
const container = document.getElementById("script-menu");
|
||||
if (!section || !container) return;
|
||||
|
||||
if (_scriptMenuCache) renderScriptMenu(_scriptMenuCache);
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/saved-scripts");
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
const scripts = Array.isArray(data.items) ? data.items : [];
|
||||
_scriptMenuCache = scripts;
|
||||
renderScriptMenu(scripts);
|
||||
} catch {
|
||||
// ignore — cached render (if any) is already showing
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPluginsForClient(clientId) {
|
||||
const section = document.getElementById("plugin-section");
|
||||
const container = document.getElementById("plugin-menu");
|
||||
@@ -599,6 +656,7 @@ function initializeRenderer() {
|
||||
const notificationsMuted = card?.dataset.notificationsMuted === "true";
|
||||
openMenu(id, x, y, setContext, { isOnline: isClientOnline(id), notificationsMuted });
|
||||
loadPluginsForClient(id);
|
||||
loadSavedScriptsForMenu();
|
||||
},
|
||||
openModal,
|
||||
requestPreview,
|
||||
@@ -1362,6 +1420,16 @@ menu.addEventListener("click", async (e) => {
|
||||
closeMenu(clearContext);
|
||||
return;
|
||||
}
|
||||
const scriptId = target.dataset.scriptId;
|
||||
if (scriptId) {
|
||||
window.open(
|
||||
`/scripts?clientId=${encodeURIComponent(contextCard)}&scriptId=${encodeURIComponent(scriptId)}`,
|
||||
"_blank",
|
||||
"noopener",
|
||||
);
|
||||
closeMenu(clearContext);
|
||||
return;
|
||||
}
|
||||
const open = target.dataset.open;
|
||||
if (open === "console") {
|
||||
window.open(`/${contextCard}/console`, "_blank", "noopener");
|
||||
|
||||
@@ -746,9 +746,42 @@ function renderTemplatePalette() {
|
||||
}
|
||||
}
|
||||
|
||||
function applyContextMenuParams() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const clientId = params.get("clientId");
|
||||
const scriptId = params.get("scriptId");
|
||||
if (!clientId && !scriptId) return;
|
||||
|
||||
if (clientId) {
|
||||
const found = allClients.find((c) => c.id === clientId);
|
||||
if (found) {
|
||||
selectedClients.clear();
|
||||
selectedClients.add(clientId);
|
||||
renderClients();
|
||||
} else {
|
||||
showToast(`Client ${clientId.substring(0, 8)} is not online`, "warning", 4000);
|
||||
}
|
||||
}
|
||||
|
||||
if (scriptId) {
|
||||
const script = cachedSavedScripts.find((s) => s.id === scriptId);
|
||||
if (script) {
|
||||
setEditorValue(script.content);
|
||||
scriptType.value = script.scriptType;
|
||||
scriptSaveName.value = script.name;
|
||||
setEditorMode(script.scriptType);
|
||||
showToast(`Loaded "${script.name}" — ready to run`, "success", 3000);
|
||||
} else {
|
||||
showToast("Saved script not found", "error", 4000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkAuth();
|
||||
loadClients();
|
||||
loadSavedScripts().then(() => renderSavedScripts());
|
||||
Promise.all([
|
||||
loadClients(),
|
||||
loadSavedScripts().then(() => renderSavedScripts()),
|
||||
]).then(applyContextMenuParams);
|
||||
loadAutoTasks();
|
||||
renderTemplatePalette();
|
||||
|
||||
|
||||
@@ -241,12 +241,14 @@ const mainRowsHTML =
|
||||
`<button class="ctx-row" data-group-toggle="${g.id}"><i class="${g.icon} ctx-icon ${g.color}"></i><span style="flex:1">${g.label}</span><i class="fa-solid fa-chevron-right ctx-chevron"></i></button>`
|
||||
).join("") +
|
||||
`<div class="ctx-divider"></div>` +
|
||||
`<button class="ctx-row hidden" id="script-section" data-group-toggle="scripts"><i class="fa-solid fa-scroll ctx-icon text-cyan-400"></i><span style="flex:1">Run Script</span><i class="fa-solid fa-chevron-right ctx-chevron"></i></button>` +
|
||||
`<button class="ctx-row hidden" id="plugin-section" data-group-toggle="plugins"><i class="fa-solid fa-puzzle-piece ctx-icon text-fuchsia-400"></i><span style="flex:1">Plugins</span><i class="fa-solid fa-chevron-right ctx-chevron"></i></button>`;
|
||||
|
||||
const subPanelsHTML =
|
||||
MENU_GROUPS.map(g =>
|
||||
`<div class="ctx-sub-panel" data-for="${g.id}">${g.items.map(buildItemHTML).join("")}</div>`
|
||||
).join("") +
|
||||
`<div class="ctx-sub-panel" data-for="scripts"><div id="script-menu" style="display:flex;flex-direction:column;gap:1px"></div></div>` +
|
||||
`<div class="ctx-sub-panel" data-for="plugins"><div id="plugin-menu" style="display:flex;flex-direction:column;gap:1px"></div></div>`;
|
||||
|
||||
const menu = document.createElement("div");
|
||||
|
||||
Reference in New Issue
Block a user