feat(lite): Console tab with connection + open/create diagnostics
The lite variant had no visibility into why a wallet failed to open — just a "disconnected" spinner. Add a lite-only Console tab (full-node keeps its RPC console) that shows a live diagnostic log. - LiteDiagnostics: a small thread-safe, bounded ring buffer (header-only). The controller writes to it from its background threads: each failover server attempt and result, wallet open/create/restore outcomes, sync start, and blocked-open reasons. The App logs controller (re)builds with the preferred server. - lite_console_tab: a terminal-styled, read-only view of the log (newest at the bottom, error/success lines coloured) with Clear / Copy / Auto-scroll. Reachable even when the wallet is locked (it's diagnostics, no secrets). Registered as NavPage::LiteConsole, gated lite-only via WalletUiSurface::LiteConsole. A unit test drives an open-with-failover and asserts the log records the connection attempt and the successful open. Built clean for full-node, lite, and Windows cross-compile. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
98
src/ui/windows/lite_console_tab.cpp
Normal file
98
src/ui/windows/lite_console_tab.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "lite_console_tab.h"
|
||||
|
||||
#include "../../app.h"
|
||||
#include "../../util/i18n.h"
|
||||
#include "../../wallet/lite_diagnostics.h"
|
||||
#include "../layout.h"
|
||||
#include "../material/type.h"
|
||||
#include "../material/colors.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx {
|
||||
namespace ui {
|
||||
|
||||
using namespace material;
|
||||
|
||||
namespace {
|
||||
|
||||
// Re-snapshot the (mutex-guarded) log only when it actually changes, not every frame.
|
||||
std::vector<std::string> s_lines;
|
||||
std::uint64_t s_cachedGeneration = static_cast<std::uint64_t>(-1);
|
||||
bool s_autoScroll = true;
|
||||
|
||||
// Colour error/success lines for at-a-glance scanning (substring match on the messages the
|
||||
// controller emits). Anything else renders in the muted default colour.
|
||||
ImU32 lineColor(const std::string& line)
|
||||
{
|
||||
const auto has = [&line](const char* s) { return line.find(s) != std::string::npos; };
|
||||
if (has("failed") || has(" unreachable") || has("blocked") || has("could not") ||
|
||||
has("Error") || has("error"))
|
||||
return Error();
|
||||
if (has(": connected") || has("opened") || has("wallet ready") || has("Ready"))
|
||||
return Success();
|
||||
return OnSurfaceMedium();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RenderLiteConsoleTab(App* app)
|
||||
{
|
||||
(void)app;
|
||||
auto& diag = wallet::LiteDiagnostics::instance();
|
||||
const std::uint64_t gen = diag.generation();
|
||||
if (gen != s_cachedGeneration) {
|
||||
s_lines = diag.snapshot();
|
||||
s_cachedGeneration = gen;
|
||||
}
|
||||
|
||||
// ── Header ──────────────────────────────────────────────────────────────────
|
||||
Type().text(TypeStyle::H6, TR("lite_console_title"));
|
||||
Type().textColored(TypeStyle::Caption, OnSurfaceMedium(), TR("lite_console_intro"));
|
||||
ImGui::Spacing();
|
||||
|
||||
// ── Toolbar ─────────────────────────────────────────────────────────────────
|
||||
if (ImGui::Button(TR("lite_console_clear"))) diag.clear();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(TR("lite_console_copy"))) {
|
||||
std::string all;
|
||||
for (const auto& l : s_lines) { all += l; all.push_back('\n'); }
|
||||
ImGui::SetClipboardText(all.c_str());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox(TR("lite_console_autoscroll"), &s_autoScroll);
|
||||
ImGui::Spacing();
|
||||
|
||||
// ── Log (terminal-styled scroll region) ─────────────────────────────────────
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(0, 0, 0, 90));
|
||||
ImGui::BeginChild("##LiteConsoleLog", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_HorizontalScrollbar);
|
||||
ImGui::PushFont(Type().caption());
|
||||
if (s_lines.empty()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, OnSurfaceDisabled());
|
||||
ImGui::TextUnformatted(TR("lite_console_empty"));
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
for (const auto& line : s_lines) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, lineColor(line));
|
||||
ImGui::TextUnformatted(line.c_str()); // not format-interpreted — safe for any content
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
// Keep pinned to the newest line only while the user is already at the bottom.
|
||||
if (s_autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
ImGui::PopFont();
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
18
src/ui/windows/lite_console_tab.h
Normal file
18
src/ui/windows/lite_console_tab.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
//
|
||||
// Lite-wallet "Console" tab: a read-only, terminal-styled view of the lite diagnostics log
|
||||
// (server connection attempts, wallet open/create/restore, sync milestones, errors). Lite
|
||||
// builds only. See src/ui/windows/lite_console_tab.cpp.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace dragonx {
|
||||
class App;
|
||||
namespace ui {
|
||||
|
||||
void RenderLiteConsoleTab(App* app);
|
||||
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user