Repository navigation
feat(ui): show workspace health in the status bar - #1548
fluck-boss merged 3 commits into
Conversation
A plugin the sandbox stops after repeated failures is announced by one toast that disappears, and is otherwise visible only through Help > Plugin Health & Recovery or `boss doctor` in a terminal (risa-labs-inc#394). Show the report `boss doctor` already builds in the status bar while it has findings, and open a dialog listing each finding with its remedy and, where a screen fixes it, a button to that screen: Plugin Health & Recovery for plugin findings, Browser Engine settings for a missing engine. Nothing is shown while the workspace is healthy. The fix button sets its own border and colours rather than taking OutlinedButton's defaults, which come from MaterialTheme: its surface is light, so a BossTheme label on it rendered white on white and the button read as blank. Found by rendering the dialog to a PNG offscreen, which is the only way this class of defect shows up without running the app. Refs risa-labs-inc#394
The health report used to be read by `boss status` and `boss doctor`, one
query at a time. The status item reads it every 5 s in every window, so
anything the read logs repeats for as long as the condition lasts:
- The read-only engine check logged startup's decisions ("version
mismatch", "will re-download"), and on macOS a WARN on every call for an
engine kept after its one repair - while reporting it healthy. A
read-only inspection now logs nothing; the signature is unchanged.
- A health source that kept throwing logged a WARN per read. It is now
logged once, and again only after it has read cleanly.
Also pin that the dialog outlives the badge once a problem is fixed from
inside it, and drop the literal backticks from the dialog's subtitle.
|
@claude please review this exact head for merge into dev. Check that the workspace-health status bar item does no blocking IO or heavy work on the UI thread, polls or subscribes at a sane rate and stops when hidden or the window closes, handles missing or unhealthy workspaces without crashing, and has tests for the state mapping. |
|
Claude finished @fluck-boss's task in 5m 9s —— View job Review: workspace health in the status bar
Verdict on the four things you asked about
The code reads well and the docs-in-comments are up to this repo's standard. Below are the things I would want addressed or consciously accepted before merge; none of them is a "do not merge". 1. An uncaught throw in the producer takes more than the badge with it
while (true) {
value = withContext(Dispatchers.IO) { readReport() }
delay(refreshIntervalMs)
}
The odds are low (the collector's contract is "never throws", and 2. The poll is per window, and the browser source is the one that costs something
It is small and it is off the UI thread, so this is not a defect. But the natural shape for app-wide state read by N windows is one app-level poller behind a Related, and cheaper: in focus mode the bar auto-hides, so each hover-reveal restarts the loop with an immediate read. A shared feed with 3.
|
|
Thanks @Vidhaankhare16 - this is a nice feature. The 5s read stays off the UI thread, it stops with composition, and the state-mapping tests are good. Holding for one fix before merge:
Non-blocking, worth a look while you're in there:
|
The status item read the report in a produceState loop with nothing around it. The collector contains each source, but the report is assembled outside those guards, so anything escaping there left the effect and cancelled the window's recomposer effect job instead of just the badge. Each read now goes through readReportContained: Exception and LinkageError are caught (the collector's pair), cancellation is rethrown, the loop keeps the last report it showed, and the failure is logged once through HealthSourceWarnings until a read succeeds again.
|
Thanks @fluck-boss. The blocker is fixed in What changed.
Tests (
I haven't changed the non-blocking points in this push. The shared poller, the null- |
#1688) The health dialog is composed inside its status-bar item, so it exists only while the bottom bar does. In focus mode the bar is shown only while the pointer is over it, and opening the modal moves the pointer onto the dialog: the bar hid and took the dialog with it. Each window now has a BottomBarHolds, provided to the bar. The health item holds the bar while its dialog is open, and shouldShowBottomBar counts a hold the way it already counts Terminal setup's reopened dialog. The Fix button also closed the dialog and opened nothing when the window had no id to send the fix to. With no window id the dialog now leaves the button out; each finding's "What to do" text still says what to do. Follows up the #1548 review.
Refs #394
Problem
When the plugin sandbox stops a plugin after repeated failures, the only thing a person sees is one toast, and it disappears. After that the plugin is just missing. #394 describes this ("no way to find out"), and @surfthewave-commits asked there for the reason to be surfaced "without a click".
The data already exists.
WorkspaceHealthReport(from #579/#710) reports a stopped plugin asplugin_stopped_after_failures. It also reports a browser engine that is missing, failed to start or is unresponsive, and MCP tools being withheld. But onlyboss statusandboss doctorshow it, so someone who doesn't open a terminal never sees it. Plugin Health & Recovery (#454) can fix plugin problems, but only if you already know to open it from the Help menu.Change
boss doctoralready prints. It also names any area that could not be checked or was only partly checked, so an empty list is never mistaken for a clean bill of health.plugin_stopped_after_failures,plugin_needs_attention→ Open Plugin Health & Recovery (feat(plugins): add health and recovery center #454)browser_engine_not_installed→ Open Browser Engine settings (download / reinstall)No new detection logic: the item reads the same
WorkspaceHealthCollectorthe CLI uses, every 5 s, off the main thread. The collector never throws. In the bar itself, the only edit is one call inBossRightBottomBar, which adds no branches to a function already at detekt's complexity ceiling.Keeping a 5 s read out of the log. Until now the report was read once per
boss status/boss doctorquery. Reading it every 5 s in every window means anything the read logs is repeated for as long as the condition lasts. So:ChromiumAutoDownloader.isChromiumInstalledReadOnly, whose only caller is the health collector) now logs nothing. It used to log startup's decisions, such as "Chromium version mismatch" and "will re-download", which a status query never acts on. On macOS, an engine kept after its one repair attempt also logged a WARN on every call while being reported healthy. The check's signature is unchanged, so its detekt baseline entry still matches: the read-only path is recognised by therecordRepairit passes, a named no-op.HealthSourceWarnings). Before, it logged a WARN on every read.Design choices
HealthFinding.code, never on summary text, because codes are the stable identifiers.triggerShowPluginHealthCenter,triggerOpenSettings). The dialog closes first so two modals never stack.Tests
WorkspaceHealthIndicatorTest:HealthCodesconstant, with a reflection check so a code added later must be given a fix decision hereSettingsSection.valueOf(BROWSER_ENGINE_SETTINGS_SECTION), becausetriggerOpenSettingstakes a string and a renamed section would otherwise fail silentlyWorkspaceHealthStatusItemTest(Compose UI):ChromiumAutoDownloaderTest: a read-only inspection of an engine kept after its repair writes no log line. Startup's own inspection still writes one, which shows the count is measuring something.WorkspaceHealthSourcesTest: a window source failing on 3 reads is logged once, and failing again after a clean read is logged again.WorkspaceHealthCollectorTest: an area failing on 3 reads is logged once.Results (JDK 17, Windows 11): 59/59 across
WorkspaceHealthStatusItemTest8,WorkspaceHealthIndicatorTest8,WorkspaceHealthCollectorTest6,WorkspaceHealthSourcesTest5,WorkspaceHealthReportTest19 andChromiumAutoDownloaderTest13, 0 skipped, counted from the fresh test XML. detekt and ktlint clean on the same run.The fix button's colours came out of that check rather than a review: rendering the dialog
offscreen to a PNG showed the button blank, because
OutlinedButton's defaults come fromMaterialTheme, whose surface is light, so aBossThemelabel on it was white on white.It sets its own border and content colour now.
Known limitations
boss doctoruses.boss doctorstill show it.