Foinse foilsithe
Íosluchtaigh foinse ZIP
CH-J Server Manager
Brabhsáil comhadlanna agus comhaid chun feidhmchlár áirithe a scaoileadh.
CH-J / Server Manager
339 Comhaid
core-20261014T184258Z-3fbed0b93fdf
Suimigh: Dáta gan taifeadadh · Tógtha:
1
"use strict";3
const api = window.chjPlugin;4
const elements = Object.fromEntries([5
"pluginVersion", "closeButton", "sessionSelect", "refreshButton", "sudoPassword", "testButton", "reloadButton", "status",6
"nginxVersion", "serviceState", "mainConfig", "configCount", "dumpButton", "configFilter", "configList", "editorMode",7
"editorTitle", "editorMeta", "revertButton", "saveButton", "configEditor", "commandOutput", "clearOutputButton"8
].map((id) => [id, document.querySelector(`#${id}`)]));10
let sessions = [];11
let inspection = null;12
let selectedPath = "";13
let selectedKind = "";14
let originalText = "";15
let busy = false;17
function selectedSession() { return sessions.find((session) => session.sessionId === elements.sessionSelect.value) || null; }18
function sudoPassword() { return elements.sudoPassword.value; }19
function setStatus(message, error = false) { elements.status.textContent = message; elements.status.classList.toggle("error", error); }20
function setOutput(text, error = false) { elements.commandOutput.textContent = String(text || "—"); elements.commandOutput.classList.toggle("error", error); }21
function isDirty() { return Boolean(selectedPath) && elements.configEditor.value !== originalText; }22
function selectedWritable() { return selectedKind === "file" && Boolean(selectedPath); }24
function syncControls() {25
const connected = Boolean(elements.sessionSelect.value);26
elements.sessionSelect.disabled = busy;27
elements.refreshButton.disabled = busy;28
elements.testButton.disabled = busy || !connected || !inspection?.installed;29
elements.reloadButton.disabled = busy || !connected || !inspection?.installed;30
elements.dumpButton.disabled = busy || !connected || !inspection?.installed;31
elements.revertButton.disabled = busy || !selectedPath;32
elements.saveButton.disabled = busy || !selectedWritable() || !isDirty();33
elements.configEditor.readOnly = busy || !selectedWritable();34
}36
function setBusy(value) { busy = value; syncControls(); }38
function renderIdentity() {39
elements.nginxVersion.textContent = inspection?.installed ? (inspection.version || "nainstalován") : "nenalezen";40
elements.serviceState.textContent = inspection?.serviceState || "—";41
elements.serviceState.className = inspection?.serviceState === "active" ? "state-active" : "state-inactive";42
elements.mainConfig.textContent = inspection?.configPath || "—";43
elements.mainConfig.title = inspection?.configPath || "";44
elements.configCount.textContent = String(inspection?.configs?.length || 0);45
}47
function renderConfigList() {48
const query = elements.configFilter.value.trim().toLowerCase();49
const files = (inspection?.configs || []).filter((item) => item.path.toLowerCase().includes(query));50
const fragment = document.createDocumentFragment();51
for (const file of files) {52
const button = document.createElement("button");53
button.type = "button";54
button.className = `config-item${file.path === selectedPath ? " active" : ""}`;55
button.dataset.path = file.path;56
button.dataset.kind = file.kind;57
const path = document.createElement("span"); path.textContent = file.path;58
const type = document.createElement("small"); type.textContent = file.kind === "symlink" ? "symlink · pouze čtení" : "soubor";59
button.append(path, type); fragment.append(button);60
}61
elements.configList.replaceChildren(fragment);62
if (!files.length) elements.configList.innerHTML = '<p class="empty">Filtru neodpovídá žádný konfigurační soubor.</p>';63
}65
async function loadSessions() {66
const previous = elements.sessionSelect.value;67
sessions = (await api.sessions.list()).filter((session) => session.state === "connected");68
elements.sessionSelect.replaceChildren(new Option(sessions.length ? "Vyberte relaci…" : "Žádná připojená relace", ""));69
for (const session of sessions) elements.sessionSelect.add(new Option(`${session.label} — ${session.username}@${session.host}`, session.sessionId));70
elements.sessionSelect.value = sessions.some((item) => item.sessionId === previous) ? previous : (sessions[0]?.sessionId || "");71
}73
async function inspect() {74
if (!elements.sessionSelect.value) { inspection = null; renderIdentity(); renderConfigList(); syncControls(); return; }75
setBusy(true); setStatus("Zjišťuji instalaci, službu a konfigurační soubory NGINX…");76
try {77
inspection = await api.nginx.inspect(elements.sessionSelect.value);78
renderIdentity(); renderConfigList();79
setStatus(inspection.installed ? `NGINX ${inspection.version || ""} je dostupný; nalezeno ${inspection.configs.length} souborů.` : "NGINX nebyl na serveru nalezen.", !inspection.installed);80
} catch (error) { inspection = null; renderIdentity(); renderConfigList(); setStatus(error?.message || String(error), true); }81
finally { setBusy(false); }82
}84
async function readConfig(path, kind) {85
if (isDirty() && !window.confirm("Zahodit neuložené změny aktuální konfigurace?")) return;86
setBusy(true); setStatus(`Načítám ${path}…`);87
try {88
const result = await api.nginx.readConfig(elements.sessionSelect.value, { path, sudoPassword: sudoPassword() });89
selectedPath = result.path; selectedKind = kind; originalText = result.text;90
elements.configEditor.value = result.text;91
elements.editorMode.textContent = kind === "symlink" ? "NÁHLED SYMLINKU" : "EDITOR";92
elements.editorTitle.textContent = result.path;93
elements.editorMeta.textContent = `${result.size.toLocaleString("cs-CZ")} B · ${kind === "symlink" ? "upravte zdroj v sites-available" : "změny se ukládají se zálohou"}`;94
renderConfigList(); setStatus("Konfigurace byla načtena.");95
} catch (error) { setStatus(error?.message || String(error), true); }96
finally { elements.sudoPassword.value = ""; setBusy(false); }97
}99
async function runTest() {100
setBusy(true); setStatus("Spouštím nginx -t…");101
try {102
const result = await api.nginx.testConfig(elements.sessionSelect.value, sudoPassword());103
setOutput(result.output, !result.ok); setStatus(result.ok ? "Konfigurace NGINX je platná." : "Test konfigurace selhal.", !result.ok);104
} catch (error) { setOutput(error?.message || String(error), true); setStatus(error?.message || String(error), true); }105
finally { elements.sudoPassword.value = ""; setBusy(false); }106
}108
async function dumpEffectiveConfig() {109
if (isDirty() && !window.confirm("Zahodit neuložené změny a zobrazit efektivní konfiguraci?")) return;110
setBusy(true); setStatus("Načítám efektivní konfiguraci pomocí nginx -T…");111
try {112
const result = await api.nginx.dumpConfig(elements.sessionSelect.value, sudoPassword());113
selectedPath = ""; selectedKind = ""; originalText = result.text; elements.configEditor.value = result.text;114
elements.editorMode.textContent = "EFEKTIVNÍ KONFIGURACE"; elements.editorTitle.textContent = "nginx -T";115
elements.editorMeta.textContent = "Kombinovaný výstup je pouze pro čtení."; renderConfigList(); setStatus("Efektivní konfigurace byla načtena.");116
} catch (error) { setOutput(error?.message || String(error), true); setStatus(error?.message || String(error), true); }117
finally { elements.sudoPassword.value = ""; setBusy(false); }118
}120
async function saveConfig() {121
if (!selectedWritable() || !isDirty()) return;122
if (!window.confirm(`Uložit ${selectedPath}, vytvořit zálohu a spustit nginx -t? Neplatná konfigurace se automaticky vrátí.`)) return;123
setBusy(true); setStatus("Ukládám zálohu a ověřuji novou konfiguraci…");124
try {125
const result = await api.nginx.saveConfig(elements.sessionSelect.value, { path: selectedPath, text: elements.configEditor.value, sudoPassword: sudoPassword() });126
originalText = elements.configEditor.value; setOutput(`${result.testOutput}\n\nZáloha: ${result.backupPath}`); setStatus("Konfigurace byla uložena a nginx -t uspěl. Reload zatím nebyl proveden.");127
} catch (error) { setOutput(error?.message || String(error), true); setStatus(error?.message || String(error), true); }128
finally { elements.sudoPassword.value = ""; setBusy(false); }129
}131
async function reloadNginx() {132
if (isDirty()) { setStatus("Nejprve uložte nebo zahoďte neuložené změny.", true); return; }133
if (!window.confirm("Provést graceful reload NGINX? Core před reloadem znovu spustí nginx -t.")) return;134
setBusy(true); setStatus("Ověřuji konfiguraci a provádím graceful reload…");135
try {136
const result = await api.nginx.reload(elements.sessionSelect.value, sudoPassword(), true);137
setOutput(result.output); setStatus("NGINX byl bezpečně reloadován."); await inspect();138
} catch (error) { setOutput(error?.message || String(error), true); setStatus(error?.message || String(error), true); }139
finally { elements.sudoPassword.value = ""; setBusy(false); }140
}142
elements.closeButton.addEventListener("click", () => api.close());143
elements.refreshButton.addEventListener("click", async () => { await loadSessions(); await inspect(); });144
elements.sessionSelect.addEventListener("change", async () => { selectedPath = ""; selectedKind = ""; originalText = ""; elements.configEditor.value = ""; await inspect(); });145
elements.configFilter.addEventListener("input", renderConfigList);146
elements.configList.addEventListener("click", (event) => { const item = event.target.closest("button[data-path]"); if (item) void readConfig(item.dataset.path, item.dataset.kind); });147
elements.configEditor.addEventListener("input", syncControls);148
elements.revertButton.addEventListener("click", () => { if (selectedPath) void readConfig(selectedPath, selectedKind); });149
elements.saveButton.addEventListener("click", saveConfig);150
elements.testButton.addEventListener("click", runTest);151
elements.dumpButton.addEventListener("click", dumpEffectiveConfig);152
elements.reloadButton.addEventListener("click", reloadNginx);153
elements.clearOutputButton.addEventListener("click", () => setOutput(""));154
window.addEventListener("beforeunload", (event) => { if (isDirty()) { event.preventDefault(); event.returnValue = ""; } });156
(async () => {157
const info = await api.getInfo(); elements.pluginVersion.textContent = `${info.name} v${info.version} · ${info.publisher}`;158
await loadSessions(); await inspect();159
})().catch((error) => setStatus(error?.message || String(error), true));SHA-256
f8862d3a2a8cedb7f512aeb0f3ce6ad915f54795ccf7c4fdd90c21958f9f67a7CH-J Proprietary Software License 1.14 · Tá Foinse ar fáil faoin CH-J Proprietary Software License 1.14. Ní chuireann a infhaighteacht a athrú ar na téarmaí ceadúnais nó cearta breise a dheonú.
Cartlann SHA-256
3df08cf5e899262a6ce92d7ec2caf5c42b683f1f2b57055662b845ff7dde67a8