aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/zenserver/frontend/html/pages/hub.js21
-rw-r--r--src/zenserver/frontend/html/zen.css5
-rw-r--r--src/zenserver/hub/httphubservice.cpp1
-rw-r--r--src/zenserver/hub/hub.cpp2
-rw-r--r--src/zenserver/hub/hub.h1
6 files changed, 29 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 32b9e7255..54c7ba0de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -51,7 +51,9 @@
- Improvement: `zen up` refactored to use shared `StartupZenServer`/`ShutdownZenServer` helpers (also used by `zen hub up`/`zen hub down`)
- Improvement: Hub dashboard module list improved
- Animated state dots, with flashing transitions for hibernating, waking, provisioning, and deprovisioning
+ - Per-row port used by the provisioned instance
- Per-row hibernate, wake, and deprovision actions with confirmation for destructive operations
+ - Per-row button to open the instance dashboard in a new window
- Multi-select with bulk hibernate/wake/deprovision and select-all
- Pagination at 50 lines per page
- Inline fold-out panel per row with human-readable process metrics
diff --git a/src/zenserver/frontend/html/pages/hub.js b/src/zenserver/frontend/html/pages/hub.js
index a226f0924..3a5b67483 100644
--- a/src/zenserver/frontend/html/pages/hub.js
+++ b/src/zenserver/frontend/html/pages/hub.js
@@ -114,6 +114,7 @@ export class Page extends ZenPage
// Module table
const table = document.createElement("table");
+ table.className = "module-table";
const thead = document.createElement("thead");
const hrow = document.createElement("tr");
@@ -125,7 +126,7 @@ export class Page extends ZenPage
th_check.appendChild(this._select_all_cb);
hrow.appendChild(th_check);
- for (const label of ["#", "MODULE ID", "STATUS", "ACTIONS"])
+ for (const label of ["#", "MODULE ID", "STATUS", "PORT", "ACTIONS"])
{
const th = document.createElement("th");
th.textContent = label;
@@ -279,6 +280,8 @@ export class Page extends ZenPage
row.dot.removeAttribute("data-prev-state");
}
row.state_text.nodeValue = state;
+ row.port_text.nodeValue = m.port ? String(m.port) : "";
+ row.btn_open.disabled = state !== "provisioned";
row.btn_hibernate.disabled = !_btn_enabled(state, "hibernate");
row.btn_wake.disabled = !_btn_enabled(state, "wake");
row.btn_deprov.disabled = !_btn_enabled(state, "deprovision");
@@ -357,8 +360,19 @@ export class Page extends ZenPage
td_status.appendChild(state_node);
tr.appendChild(td_status);
+ const port = m.port || 0;
+ const td_port = document.createElement("td");
+ td_port.style.cssText = "font-variant-numeric:tabular-nums;";
+ const port_node = document.createTextNode(port ? String(port) : "");
+ td_port.appendChild(port_node);
+ tr.appendChild(td_port);
+
const td_action = document.createElement("td");
td_action.className = "module-action-cell";
+ const [wrap_o, btn_o] = _make_action_btn("\u2197", "Open dashboard", () => {
+ window.open(`${window.location.protocol}//${window.location.hostname}:${port}`, "_blank");
+ });
+ btn_o.disabled = state !== "provisioned";
const [wrap_h, btn_h] = _make_action_btn("\u23F8", "Hibernate", () => this._post_module_action(id, "hibernate").then(() => this._update()));
const [wrap_w, btn_w] = _make_action_btn("\u25B6", "Wake", () => this._post_module_action(id, "wake").then(() => this._update()));
const [wrap_d, btn_d] = _make_action_btn("\u2715", "Deprovision", () => this._confirm_deprovision([id]));
@@ -368,6 +382,7 @@ export class Page extends ZenPage
td_action.appendChild(wrap_h);
td_action.appendChild(wrap_w);
td_action.appendChild(wrap_d);
+ td_action.appendChild(wrap_o);
tr.appendChild(td_action);
// Build metrics grid from process_metrics keys.
@@ -375,7 +390,7 @@ export class Page extends ZenPage
// top-to-bottom in the left column before continuing in the right column.
const metric_nodes = new Map();
const metrics_td = document.createElement("td");
- metrics_td.colSpan = 5;
+ metrics_td.colSpan = 6;
const metrics_grid = document.createElement("div");
metrics_grid.className = "module-metrics-grid";
const keys = Object.keys(m.process_metrics || {});
@@ -405,7 +420,7 @@ export class Page extends ZenPage
metrics_td.appendChild(metrics_grid);
metrics_tr.appendChild(metrics_td);
- row = { tr, metrics_tr, idx: td_idx, cb, dot, state_text: state_node, btn_expand, btn_hibernate: btn_h, btn_wake: btn_w, btn_deprov: btn_d, metric_nodes };
+ row = { tr, metrics_tr, idx: td_idx, cb, dot, state_text: state_node, port_text: port_node, btn_expand, btn_open: btn_o, btn_hibernate: btn_h, btn_wake: btn_w, btn_deprov: btn_d, metric_nodes };
this._row_cache.set(id, row);
}
diff --git a/src/zenserver/frontend/html/zen.css b/src/zenserver/frontend/html/zen.css
index c47b35904..5ce60d2d2 100644
--- a/src/zenserver/frontend/html/zen.css
+++ b/src/zenserver/frontend/html/zen.css
@@ -1253,6 +1253,11 @@ tr:last-child td {
text-align: center;
}
+.module-table td, .module-table th {
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+
.module-expand-btn {
background: transparent;
border: none;
diff --git a/src/zenserver/hub/httphubservice.cpp b/src/zenserver/hub/httphubservice.cpp
index 03be6e85d..a91e36128 100644
--- a/src/zenserver/hub/httphubservice.cpp
+++ b/src/zenserver/hub/httphubservice.cpp
@@ -42,6 +42,7 @@ HttpHubService::HttpHubService(Hub& Hub) : m_Hub(Hub)
{
Obj << "moduleId" << ModuleId;
Obj << "state" << ToString(Info.State);
+ Obj << "port" << Info.Port;
Obj.BeginObject("process_metrics");
{
Obj << "MemoryBytes" << Info.Metrics.MemoryBytes;
diff --git a/src/zenserver/hub/hub.cpp b/src/zenserver/hub/hub.cpp
index 54f45e511..ebbb9432a 100644
--- a/src/zenserver/hub/hub.cpp
+++ b/src/zenserver/hub/hub.cpp
@@ -605,6 +605,7 @@ Hub::Find(std::string_view ModuleId, InstanceInfo* OutInstanceInfo)
std::chrono::system_clock::now() // TODO
};
Instance->GetProcessMetrics(Info.Metrics);
+ Info.Port = Instance->GetBasePort();
*OutInstanceInfo = Info;
}
@@ -628,6 +629,7 @@ Hub::EnumerateModules(std::function<void(std::string_view ModuleId, const Instan
std::chrono::system_clock::now() // TODO
};
Instance->GetProcessMetrics(Info.Metrics);
+ Info.Port = Instance->GetBasePort();
Infos.push_back(std::make_pair(std::string(Instance->GetModuleId()), Info));
}
diff --git a/src/zenserver/hub/hub.h b/src/zenserver/hub/hub.h
index 9a84f7744..8c4039c38 100644
--- a/src/zenserver/hub/hub.h
+++ b/src/zenserver/hub/hub.h
@@ -69,6 +69,7 @@ public:
HubInstanceState State = HubInstanceState::Unprovisioned;
std::chrono::system_clock::time_point ProvisionTime;
ProcessMetrics Metrics;
+ uint16_t Port = 0;
};
/**