feat(ui): say "Node busy" instead of "Launching dragonxd"; honest quit copy

A node rebuilding note witnesses for an hour was shown as "Starting
DragonX node... Launching dragonxd", which invited closing it.

- Overlay, a new NodeBusy banner and the status bar now say what the node
  is doing (rebuilding witnesses / catching up on blocks / up but not
  answering), with the elapsed time and Phase-1 block progress. A rebuild
  during startup warm-up replaces the stale "-28 Activating best chain"
  text, and the overlay re-applies its text once a second instead of only
  on a connect attempt (30s apart while the node is busy).
- Quit prompt: elapsed time, "Keep node running & quit" is the default,
  "Stop anyway & quit" becomes "Stop node & wait" (it no longer kills).
- A reinstall skipped because the node is still running now notifies.
- Status bar: don't repeat the warm-up status on the right, and don't
  print "Connected" there in non-English locales.
- i18n: 31 new keys in all 8 languages; 10 dead force-quit/old-modal keys
  removed; CJK subset rebuilt for the new glyphs.
- Tests: chooseDaemonStatus, NodeBusy banner priority, and every new key
  present in all 8 JSONs with matching printf conversions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 10:26:32 -05:00
co-authored by Claude Opus 5.5
parent 0f25c67600
commit 1215ded1a0
17 changed files with 822 additions and 133 deletions
+19
View File
@@ -141,5 +141,24 @@ inline bool shouldConfirmStop(bool stopsDaemon, const DaemonBusyTracker& tracker
return stopsDaemon && (tracker.rebuilding() || rpcBusyWhileAlive);
}
// What the "node is starting / not answering" overlay should say, most specific first.
enum class DaemonStatusKind {
Rebuilding, // its own log says it's rebuilding note witnesses
Replaying, // its own log says it's catching up on blocks it saved before (startup replay)
InitPhase, // a recognisable init phase line (loading the block index, verifying, ...)
Busy, // it answers the connection but not the request (reply timeout / queue full)
Launching, // nothing bound to the RPC port yet
};
inline DaemonStatusKind chooseDaemonStatus(bool hasInitPhaseLine, bool reachableButBusy,
const DaemonBusyTracker& tracker)
{
if (tracker.rebuilding()) return DaemonStatusKind::Rebuilding;
if (tracker.replaying()) return DaemonStatusKind::Replaying;
if (hasInitPhaseLine) return DaemonStatusKind::InitPhase;
if (reachableButBusy) return DaemonStatusKind::Busy;
return DaemonStatusKind::Launching;
}
} // namespace daemon
} // namespace dragonx