feat: add routing tab and fetch routing details for apps in frontend
fix: update compose commands to remove orphan containers in panelctl Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
93a9a0f42b
commit
45a9aec787
2 changed files with 51 additions and 9 deletions
|
|
@ -475,6 +475,7 @@ function renderAppCard(app) {
|
||||||
<button class="tab active" data-tab="compose" data-app="${app.name}">Compose</button>
|
<button class="tab active" data-tab="compose" data-app="${app.name}">Compose</button>
|
||||||
<button class="tab" data-tab="logs" data-app="${app.name}">Logs</button>
|
<button class="tab" data-tab="logs" data-app="${app.name}">Logs</button>
|
||||||
<button class="tab" data-tab="backups" data-app="${app.name}">Backups</button>
|
<button class="tab" data-tab="backups" data-app="${app.name}">Backups</button>
|
||||||
|
<button class="tab" data-tab="routing" data-app="${app.name}">Routing</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-panel active" id="tab-compose-${app.name}">
|
<div class="tab-panel active" id="tab-compose-${app.name}">
|
||||||
<textarea id="compose-${app.name}" rows="12" placeholder="Loading..."></textarea>
|
<textarea id="compose-${app.name}" rows="12" placeholder="Loading..."></textarea>
|
||||||
|
|
@ -505,6 +506,12 @@ function renderAppCard(app) {
|
||||||
<div style="color:var(--muted);font-size:.85rem;">Click "Refresh" to load backups.</div>
|
<div style="color:var(--muted);font-size:.85rem;">Click "Refresh" to load backups.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab-panel" id="tab-routing-${app.name}">
|
||||||
|
<div class="btn-group" style="margin-bottom:10px;">
|
||||||
|
<button class="btn-sm btn-primary" data-action="fetch-routing" data-app="${app.name}">Load App Variables</button>
|
||||||
|
</div>
|
||||||
|
<div class="log-output" id="routing-${app.name}">Click "Load App Variables" to view routing details & directories.</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -562,6 +569,7 @@ function attachCardListeners() {
|
||||||
document.getElementById(`tab-compose-${app}`).classList.toggle("active", tabName === "compose");
|
document.getElementById(`tab-compose-${app}`).classList.toggle("active", tabName === "compose");
|
||||||
document.getElementById(`tab-logs-${app}`).classList.toggle("active", tabName === "logs");
|
document.getElementById(`tab-logs-${app}`).classList.toggle("active", tabName === "logs");
|
||||||
document.getElementById(`tab-backups-${app}`).classList.toggle("active", tabName === "backups");
|
document.getElementById(`tab-backups-${app}`).classList.toggle("active", tabName === "backups");
|
||||||
|
document.getElementById(`tab-routing-${app}`).classList.toggle("active", tabName === "routing");
|
||||||
|
|
||||||
if (tabName === "logs") loadLogs(app);
|
if (tabName === "logs") loadLogs(app);
|
||||||
if (tabName === "backups") loadBackups(app);
|
if (tabName === "backups") loadBackups(app);
|
||||||
|
|
@ -572,13 +580,22 @@ function attachCardListeners() {
|
||||||
document.querySelectorAll("[data-action]").forEach(btn => {
|
document.querySelectorAll("[data-action]").forEach(btn => {
|
||||||
btn.onclick = (e) => {
|
btn.onclick = (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleAction(btn.dataset.action, btn.dataset.app);
|
handleAction(btn.dataset.action, btn.dataset.app, btn);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Actions ───
|
// ─── Actions ───
|
||||||
async function handleAction(action, name) {
|
async function handleAction(action, name, btnElement) {
|
||||||
|
const originalWidth = btnElement ? btnElement.offsetWidth : null;
|
||||||
|
const originalHtml = btnElement ? btnElement.innerHTML : null;
|
||||||
|
|
||||||
|
if (btnElement) {
|
||||||
|
btnElement.disabled = true;
|
||||||
|
if (originalWidth) btnElement.style.width = `${originalWidth}px`;
|
||||||
|
btnElement.innerHTML = `<span class="spinner" style="vertical-align:middle; width:12px; height:12px; margin: 2px;"></span>`;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "deploy":
|
case "deploy":
|
||||||
|
|
@ -628,9 +645,34 @@ async function handleAction(action, name) {
|
||||||
setStatus(`Backing up ${name}...`);
|
setStatus(`Backing up ${name}...`);
|
||||||
await api.backup(name);
|
await api.backup(name);
|
||||||
setStatus(`Backup created for ${name}.`);
|
setStatus(`Backup created for ${name}.`);
|
||||||
await loadBackups(name);
|
case "fetch-routing":
|
||||||
|
setStatus(`Fetching routing details for ${name}...`);
|
||||||
|
const appRes = await api.getApp(name);
|
||||||
|
if (appRes.app) {
|
||||||
|
const info = appRes.app;
|
||||||
|
document.getElementById(`routing-${name}`).innerHTML = `
|
||||||
|
<b>Primary Domain:</b> ${escHtml(info.APP_DOMAIN || "-")}
|
||||||
|
<b>All Domains:</b> ${escHtml(info.APP_DOMAINS || "-")}
|
||||||
|
<b>Upstream Target:</b> ${escHtml(info.APP_UPSTREAM || "-")}
|
||||||
|
<b>Protected:</b> ${escHtml(info.APP_AUTH_PROTECTED || "-")}
|
||||||
|
<b>Port:</b> ${escHtml(info.APP_PORT || "-")}
|
||||||
|
|
||||||
|
<b>Volumes Directory:</b> ${escHtml(info.APP_VOLUME_DIR || "-")}
|
||||||
|
<b>Stack Directory:</b> ${escHtml(info.APP_STACK_DIR || "-")}
|
||||||
|
<b>Caddy Route Block:</b> ${escHtml(info.APP_ROUTE_FILE || "-")}
|
||||||
|
`.trim();
|
||||||
|
}
|
||||||
|
setStatus(`Loaded routing for ${name}.`);
|
||||||
break;
|
break;
|
||||||
case "refresh-backups":
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setStatus(`${action} failed for ${name}: ${err.message}`, true);
|
||||||
|
} finally {
|
||||||
|
if (btnElement && originalHtml) {
|
||||||
|
btnElement.disabled = false;
|
||||||
|
btnElement.innerHTML = originalHtml;
|
||||||
|
btnElement.style.width = '';
|
||||||
|
}
|
||||||
await loadBackups(name);
|
await loadBackups(name);
|
||||||
break;
|
break;
|
||||||
case "render-route":
|
case "render-route":
|
||||||
|
|
|
||||||
10
panelctl.sh
10
panelctl.sh
|
|
@ -344,7 +344,7 @@ cmd_deploy() {
|
||||||
|
|
||||||
cmd_render_route "${name}"
|
cmd_render_route "${name}"
|
||||||
|
|
||||||
if ! run_compose -f "${APP_COMPOSE_FILE}" up -d 2>&1 | systemd-cat -t panelctl -p info 2>/dev/null; then
|
if ! run_compose -f "${APP_COMPOSE_FILE}" up -d --remove-orphans 2>&1 | systemd-cat -t panelctl -p info 2>/dev/null; then
|
||||||
log err "Deployment failed for app '${name}'"
|
log err "Deployment failed for app '${name}'"
|
||||||
fail "compose up failed"
|
fail "compose up failed"
|
||||||
fi
|
fi
|
||||||
|
|
@ -359,9 +359,9 @@ cmd_restart() {
|
||||||
|
|
||||||
log info "Restarting app '${name}'"
|
log info "Restarting app '${name}'"
|
||||||
|
|
||||||
run_compose -f "${APP_COMPOSE_FILE}" down || fail "compose down failed"
|
run_compose -f "${APP_COMPOSE_FILE}" down --remove-orphans || fail "compose down failed"
|
||||||
|
|
||||||
if ! run_compose -f "${APP_COMPOSE_FILE}" up -d 2>&1; then
|
if ! run_compose -f "${APP_COMPOSE_FILE}" up -d --remove-orphans 2>&1; then
|
||||||
fail "compose up failed during restart"
|
fail "compose up failed during restart"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -373,7 +373,7 @@ cmd_stop() {
|
||||||
validate_name "${name}"
|
validate_name "${name}"
|
||||||
load_app "${name}"
|
load_app "${name}"
|
||||||
|
|
||||||
run_compose -f "${APP_COMPOSE_FILE}" down || fail "compose down failed"
|
run_compose -f "${APP_COMPOSE_FILE}" down --remove-orphans || fail "compose down failed"
|
||||||
log info "stopped app '${name}'"
|
log info "stopped app '${name}'"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -429,7 +429,7 @@ cmd_remove() {
|
||||||
validate_name "${name}"
|
validate_name "${name}"
|
||||||
load_app "${name}"
|
load_app "${name}"
|
||||||
|
|
||||||
run_compose -f "${APP_COMPOSE_FILE}" down 2>/dev/null || true
|
run_compose -f "${APP_COMPOSE_FILE}" down --remove-orphans 2>/dev/null || true
|
||||||
|
|
||||||
# Remove this app's block from the aggregate routes file.
|
# Remove this app's block from the aggregate routes file.
|
||||||
local route_file
|
local route_file
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue