refactor(console): phase 2 — channel-as-semantic key; decouple executor from UI colors

Make ConsoleChannel the canonical semantic classification of every console
line. Producers (command executor, app log forwarders, result formatter) tag
each line with a channel; the UI derives both the text color and the left
accent-bar color from it at draw time, and the output filter keys off it.

This replaces the prior scheme of storing an ImU32 color per line and then
reverse-engineering the source from color-equality plus a "[daemon] "/"[xmrig] "
/"[app] "/"[rpc] " text prefix. Consequences:

- ConsoleLine now stores {text, ConsoleChannel} — no per-line color.
- addLine()/addRpcTraceLine() take a channel; the redundant text prefixes are
  gone (the accent bar carries the origin).
- The executor's ConsoleAddLineFn hands a channel, not an ImU32, so the backend
  no longer depends on ConsoleTab::COLOR_* — FullNode/Lite executors emit clean
  text + channel.
- The theme-remap loop that rewrote stored colors on light/dark flip is deleted;
  colors are resolved per-channel each frame (refreshColors on flip only).
- ConsoleOutputFilter drops its color fields; consoleLinePassesFilter() keys off
  the channel. Test updated to the channel-based API.
- Added a Warning channel (amber severity peer of Error/Success) so the
  notification + logger warning forwarders keep their color.

Full-node + lite build clean; ctest green; source hygiene clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 18:22:35 -05:00
parent 19e83eb12a
commit 33735b1d52
9 changed files with 219 additions and 175 deletions

View File

@@ -2354,26 +2354,34 @@ void testRendererHelpers()
EXPECT_FALSE(dragonx::ui::IsPoolMiningActive(true, false, true));
EXPECT_TRUE(dragonx::ui::IsPoolMiningActive(false, false, true));
dragonx::ui::ConsoleOutputFilter filter{"error", false, false, false, true, 10, 20, 30};
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("RPC Error", 20, filter));
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("daemon line", 10, filter));
// The output filter keys off the line's semantic ConsoleChannel (not a color / prefix).
using CC = dragonx::ui::ConsoleChannel;
// {text, daemonMessagesEnabled, errorsOnly, rpcTraceEnabled, appMessagesEnabled}
dragonx::ui::ConsoleOutputFilter filter{"error", false, false, false, true};
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("RPC Error", CC::Error, filter)); // substring "error"
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("Daemon line", CC::Daemon, filter)); // no "error" substring
filter.text.clear();
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("[rpc] History -> listtransactions", 30, filter));
// Daemon/Xmrig channels hidden while daemonMessagesEnabled=false.
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("node log", CC::Daemon, filter));
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("hashrate 1000", CC::Xmrig, filter));
// Rpc channel hidden while rpcTraceEnabled=false, shown once enabled.
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("History -> listtransactions", CC::Rpc, filter));
filter.rpcTraceEnabled = true;
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("[rpc] History -> listtransactions", 30, filter));
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("History -> listtransactions", CC::Rpc, filter));
filter.daemonMessagesEnabled = true;
// Errors-only keeps only the Error channel.
filter.errorsOnly = true;
filter.text.clear();
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("error line", 20, filter));
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("info line", 30, filter));
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("error line", CC::Error, filter));
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("info line", CC::Info, filter));
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("node log", CC::Daemon, filter));
// "[app] ..." lines are filtered by prefix (they share the info color), not by color.
// App channel is toggled by appMessagesEnabled; other channels are unaffected by it.
filter.errorsOnly = false;
filter.appMessagesEnabled = false;
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("[app] Price updated", 30, filter));
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("[rpc] trace", 30, filter));
EXPECT_FALSE(dragonx::ui::consoleLinePassesFilter("Price updated", CC::App, filter));
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("trace", CC::Rpc, filter));
filter.appMessagesEnabled = true;
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("[app] Price updated", 30, filter));
EXPECT_TRUE(dragonx::ui::consoleLinePassesFilter("Price updated", CC::App, filter));
std::vector<dragonx::AddressInfo> poolAddresses;
poolAddresses.push_back({"R-transparent", 0.0, "transparent", true});