Skip to content

Commit d1bb314

Browse files
chopperbrianoclaude
andcommitted
Dashboard: align header into a clean two-column grid (win.23)
The header had grown organically with ad-hoc spacing — labels and values were never aligned across rows, making the eye jump around. Replace with a consistent grid: col 0-1 left margin col 2-17 col1 label (16-wide: label + colon + spaces) col 18-31 col1 value (14-wide, padded for alignment) col 32-45 col2 label (14-wide) col 46+ col2 value (free) Long-value rows (Web UI, Payout, Balance, PSP Pool) use the full width with col1 only. Add a `cell()` lambda that pads correctly even when ANSI color codes are present in the value, so columns line up regardless of color escape sequences. Result on a 120-col terminal: DigiByte Core: Online Database: Ready IPFS: Connected RPC Server: Port 14024 Web Server: Port 8090 External IP: 64.182.71.30 Web UI: http://localhost:8090/ Payout: dgb1qh9n2zzuhdd37gyrktjam5uju8gy3f5ems4yna3 Balance: 21.2103 DGB (updates every 4h) PSP Pool: Pool reachable - this node is listed Network: 6 nodes online Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 582243e commit d1bb314

2 files changed

Lines changed: 87 additions & 27 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ SET(PATCH_VERSION 0)
4040
SET(SO_VERSION 0)
4141

4242
# Windows port build number (increment for each Windows-specific release)
43-
SET(WIN_BUILD 22)
43+
SET(WIN_BUILD 23)
4444

4545
# Add source directory
4646
include_directories(src)

src/ConsoleDashboard.cpp

Lines changed: 86 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -376,38 +376,96 @@ void ConsoleDashboard::render() {
376376
out << BOLD << FG_BRIGHT_WHITE << ERASE_LINE << centerText(title, w) << RESET << "\n"; totalRows++;
377377
out << ERASE_LINE << std::string(w, '-') << "\n"; totalRows++;
378378

379-
// Row 3-5: Services
380-
out << ERASE_LINE
381-
<< " DigiByte Core: " << (dgbOnline ? (std::string(FG_GREEN) + "Online") : (std::string(FG_RED) + "Offline")) << RESET
382-
<< " Database: " << (dbOnline ? (std::string(FG_GREEN) + "Ready") : (std::string(FG_RED) + "N/A")) << RESET
383-
<< " IPFS: " << (ipfsOnline ? (std::string(FG_GREEN) + "Connected") : (std::string(FG_YELLOW) + "N/A")) << RESET
384-
<< "\n"; totalRows++;
385-
out << ERASE_LINE
386-
<< " RPC Server: " << (rpcOnline ? (std::string(FG_GREEN) + "Port " + std::to_string(rpcPort)) : (std::string(FG_RED) + "Off")) << RESET
387-
<< " Web Server: " << (webOnline ? (std::string(FG_GREEN) + "Port " + std::to_string(webPort)) : (std::string(FG_RED) + "Off")) << RESET
379+
// ---- Aligned two-column header ----------------------------------------
380+
// Layout (visible columns, ignoring ANSI escape codes):
381+
//
382+
// col 0-1 left margin (2 spaces)
383+
// col 2-17 col1 label (16 chars: label + colon + spaces)
384+
// col 18-31 col1 value (14 chars, padded to fixed width)
385+
// col 32-45 col2 label (14 chars: label + colon + spaces)
386+
// col 46-? col2 value (free width, end of line)
387+
//
388+
// For long-value rows (Web UI, Payout, Balance, PSP Pool), col1 takes the
389+
// full row and the col2 cell is omitted.
390+
//
391+
// The cell helper pads invisible-length-correct, so ANSI color codes don't
392+
// throw off column alignment.
393+
const int COL1_LABEL_W = 16;
394+
const int COL1_VALUE_W = 14;
395+
const int COL2_LABEL_W = 14;
396+
397+
auto cell = [](const std::string& label, const std::string& value, const char* color,
398+
int labelW, int valueW) -> std::string {
399+
std::string lp = label + ":";
400+
if ((int)lp.size() < labelW) lp += std::string(labelW - lp.size(), ' ');
401+
std::string result = lp;
402+
if (color) result += color;
403+
result += value;
404+
result += RESET;
405+
int pad = valueW - (int)value.size();
406+
if (pad > 0) result += std::string(pad, ' ');
407+
return result;
408+
};
409+
410+
// Row: DigiByte Core | Database
411+
out << ERASE_LINE << " "
412+
<< cell("DigiByte Core", dgbOnline ? "Online" : "Offline",
413+
dgbOnline ? FG_GREEN : FG_RED, COL1_LABEL_W, COL1_VALUE_W)
414+
<< cell("Database", dbOnline ? "Ready" : "N/A",
415+
dbOnline ? FG_GREEN : FG_RED, COL2_LABEL_W, 0)
388416
<< "\n"; totalRows++;
389-
// Web UI link + External IP
390-
if (webOnline) {
391-
out << ERASE_LINE
392-
<< " Web UI: " << FG_CYAN << "http://localhost:" << std::to_string(webPort) << "/" << RESET;
417+
418+
// Row: IPFS | RPC Server
419+
{
420+
std::string rpcVal = rpcOnline ? ("Port " + std::to_string(rpcPort)) : std::string("Off");
421+
out << ERASE_LINE << " "
422+
<< cell("IPFS", ipfsOnline ? "Connected" : "N/A",
423+
ipfsOnline ? FG_GREEN : FG_YELLOW, COL1_LABEL_W, COL1_VALUE_W)
424+
<< cell("RPC Server", rpcVal,
425+
rpcOnline ? FG_GREEN : FG_RED, COL2_LABEL_W, 0)
426+
<< "\n"; totalRows++;
427+
}
428+
429+
// Row: Web Server | External IP
430+
{
431+
std::string webVal = webOnline ? ("Port " + std::to_string(webPort)) : std::string("Off");
432+
out << ERASE_LINE << " "
433+
<< cell("Web Server", webVal,
434+
webOnline ? FG_GREEN : FG_RED, COL1_LABEL_W, COL1_VALUE_W);
393435
if (!externalIP.empty() && externalIP != "unknown") {
394-
out << " External IP: " << FG_BRIGHT_WHITE << externalIP << RESET;
436+
out << cell("External IP", externalIP, FG_BRIGHT_WHITE, COL2_LABEL_W, 0);
395437
}
396438
out << "\n"; totalRows++;
397439
}
398-
// Payout address + balance
440+
441+
// Row: Web UI (single column, full row)
442+
if (webOnline) {
443+
out << ERASE_LINE << " "
444+
<< cell("Web UI", "http://localhost:" + std::to_string(webPort) + "/",
445+
FG_CYAN, COL1_LABEL_W, 0)
446+
<< "\n"; totalRows++;
447+
}
448+
449+
// Row: Payout address (single column, full row)
399450
if (!_payoutAddress.empty()) {
400-
out << ERASE_LINE
401-
<< " Payout: " << FG_BRIGHT_WHITE << _payoutAddress << RESET;
402-
if (!_payoutBalance.empty()) {
403-
out << " Balance: " << FG_GREEN << _payoutBalance << RESET
404-
<< DIM << " (updates every 4h)" << RESET;
405-
}
406-
out << "\n"; totalRows++;
451+
out << ERASE_LINE << " "
452+
<< cell("Payout", _payoutAddress, FG_BRIGHT_WHITE, COL1_LABEL_W, 0)
453+
<< "\n"; totalRows++;
454+
}
455+
456+
// Row: Balance (single column with DIM "(updates every 4h)" suffix)
457+
if (!_payoutBalance.empty()) {
458+
std::string lp = std::string("Balance:") + std::string(COL1_LABEL_W - 8, ' ');
459+
out << ERASE_LINE << " " << lp
460+
<< FG_GREEN << _payoutBalance << RESET
461+
<< DIM << " (updates every 4h)" << RESET
462+
<< "\n"; totalRows++;
407463
}
408-
// PSP pool status + node count
464+
465+
// Row: PSP Pool status (with optional Network: N nodes appended)
409466
if (!_pspStatus.empty()) {
410-
out << ERASE_LINE << " PSP Pool: ";
467+
std::string lp = std::string("PSP Pool:") + std::string(COL1_LABEL_W - 9, ' ');
468+
out << ERASE_LINE << " " << lp;
411469
if (_pspStatus.find("reachable") != std::string::npos &&
412470
_pspStatus.find("unreachable") == std::string::npos) {
413471
out << FG_GREEN << _pspStatus << RESET;
@@ -421,11 +479,13 @@ void ConsoleDashboard::render() {
421479
out << "\n"; totalRows++;
422480
}
423481

424-
// IPFS announce hint — shown only when there's actionable advice
482+
// Row: IPFS announce hint (conditional, only when there's actionable info)
425483
{
426484
std::lock_guard<std::mutex> lock(_ipfsAnnounceMutex);
427485
if (!_ipfsAnnounceHint.empty()) {
428-
out << ERASE_LINE << " IPFS: " << FG_YELLOW << _ipfsAnnounceHint << RESET << "\n";
486+
std::string lp = std::string("IPFS:") + std::string(COL1_LABEL_W - 5, ' ');
487+
out << ERASE_LINE << " " << lp
488+
<< FG_YELLOW << _ipfsAnnounceHint << RESET << "\n";
429489
totalRows++;
430490
}
431491
}

0 commit comments

Comments
 (0)