diff --git a/site/dashboard.html b/site/dashboard.html
index a7734c9..04ed80d 100644
--- a/site/dashboard.html
+++ b/site/dashboard.html
@@ -1086,7 +1086,10 @@ async function removeAllowlistDomain(domain) {
} catch (err) {}
}
+let editingRoute = false;
+
function renderServices(entries) {
+ if (editingRoute) return;
const el = document.getElementById('servicesList');
if (!entries.length) {
el.innerHTML = '
` +
+ `
` +
`${r.path} ` +
`→ :${r.port}` +
(r.strip ? ` (strip)` : '') +
+ (e.name === 'numa' ? '' : ` `) +
`
`
).join('');
+ const deletable = e.source !== 'config' && e.name !== 'numa';
return `
@@ -1112,12 +1118,52 @@ function renderServices(entries) {
localhost:${e.target_port} → proxied
${routeLines}
+ ${e.name === 'numa' ? '' : `
`}
- ${e.name === 'numa' ? '' : `
`}
+ ${deletable ? `
` : ''}
`}).join('');
}
+function toggleRouteForm(name) {
+ const el = document.getElementById('routeForm-' + name);
+ const opening = el.style.display === 'none';
+ el.style.display = opening ? 'block' : 'none';
+ editingRoute = opening;
+}
+
+async function addRoute(name) {
+ const errEl = document.getElementById('routeError-' + name);
+ errEl.style.display = 'none';
+ try {
+ const path = document.getElementById('routePath-' + name).value.trim();
+ const port = parseInt(document.getElementById('routePort-' + name).value) || 0;
+ const strip = document.getElementById('routeStrip-' + name).checked;
+ const res = await fetch(API + '/services/' + encodeURIComponent(name) + '/routes', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ path, port, strip }),
+ });
+ if (!res.ok) throw new Error(await res.text());
+ editingRoute = false;
+ refresh();
+ } catch (err) {
+ errEl.textContent = err.message;
+ errEl.style.display = 'block';
+ }
+}
+
+async function deleteRoute(name, path) {
+ try {
+ await fetch(API + '/services/' + encodeURIComponent(name) + '/routes', {
+ method: 'DELETE',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ path }),
+ });
+ refresh();
+ } catch (err) { /* next refresh will update */ }
+}
+
async function addService(event) {
event.preventDefault();
const errEl = document.getElementById('serviceError');
diff --git a/src/api.rs b/src/api.rs
index 069c156..5696d70 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -601,6 +601,7 @@ struct ServiceResponse {
lan_accessible: bool,
#[serde(skip_serializing_if = "Vec::is_empty")]
routes: Vec