From ba033f90bca836d571bc93ccdec8461c8904751c Mon Sep 17 00:00:00 2001 From: James Maes Date: Fri, 16 Oct 2026 09:13:24 -0500 Subject: [PATCH] fix(email): worded health tile instead of the raw UNKNOWN enum The Email health tile showed the HealthStatus name (UP/DEGRADED/DOWN/UNKNOWN). It now shows Healthy / Degraded / Down, and "Not checked yet" when no check has reported, with the check cadence in the context line. The drill to health_check is unchanged. Co-Authored-By: Claude Opus 5.5 --- .../qbits/email/health/EmailHealthChecks.java | 2 +- .../qbits/email/health/EmailHealthWidget.java | 29 +++++++++++++++++-- .../email/health/EmailHealthWidgetTest.java | 13 +++++---- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/kingsrook/qbits/email/health/EmailHealthChecks.java b/src/main/java/com/kingsrook/qbits/email/health/EmailHealthChecks.java index fb07f46..b72be21 100644 --- a/src/main/java/com/kingsrook/qbits/email/health/EmailHealthChecks.java +++ b/src/main/java/com/kingsrook/qbits/email/health/EmailHealthChecks.java @@ -102,7 +102,7 @@ public class EmailHealthChecks implements HealthCheckSupplier { return (new HealthCheckMetaData().withName(name).withLabel(name).withComponent("email") .withCategory(HealthCategory.EMAIL).withKind(HealthCheckKind.DEPENDENCY) - .withIntervalSeconds(300).withTimeoutMs(5000).withCheckInstance(input -> + .withIntervalSeconds(EmailHealthWidget.CHECK_INTERVAL_MINUTES * 60).withTimeoutMs(5000).withCheckInstance(input -> { try { diff --git a/src/main/java/com/kingsrook/qbits/email/health/EmailHealthWidget.java b/src/main/java/com/kingsrook/qbits/email/health/EmailHealthWidget.java index 57a7473..b67f3d5 100644 --- a/src/main/java/com/kingsrook/qbits/email/health/EmailHealthWidget.java +++ b/src/main/java/com/kingsrook/qbits/email/health/EmailHealthWidget.java @@ -47,6 +47,31 @@ import com.kingsrook.qqq.backend.core.utils.JsonUtils; *******************************************************************************/ public class EmailHealthWidget extends AbstractWidgetRenderer { + public static final String NOT_CHECKED = "Not checked yet"; + + ////////////////////////////////////////////////////////////////////////////// + // the interval of the email health checks (EmailHealthChecks), in minutes // + ////////////////////////////////////////////////////////////////////////////// + static final int CHECK_INTERVAL_MINUTES = 5; + + + + /******************************************************************************* + ** Human words for a health status; unknown means no check has reported yet. + *******************************************************************************/ + static String wording(String status) + { + return (switch(status) + { + case "UP" -> "Healthy"; + case "DEGRADED" -> "Degraded"; + case "DOWN" -> "Down"; + default -> NOT_CHECKED; + }); + } + + + /******************************************************************************* ** Read the persisted rollup as the viewer, preserving health permissions. *******************************************************************************/ @@ -72,8 +97,8 @@ public class EmailHealthWidget extends AbstractWidgetRenderer } } } - StatisticsData data = new StatisticsData().withCount(status).withCountFontSize("1rem") - .withCountContext(!installed ? "Email - health monitoring not configured" : readable ? "Email - System Health" : "Email - health access required"); + String context = !installed ? "Email - health monitoring not configured" : readable ? "Email - System Health. Checks run every " + CHECK_INTERVAL_MINUTES + " minutes" : "Email - health access required"; + StatisticsData data = new StatisticsData().withCount(wording(status)).withCountFontSize("1rem").withCountContext(context); if(readable) { data.withCountURL("/app/health_check?filter=" + URLEncoder.encode(JsonUtils.toJson(EmailStore.equal("component", "email")), StandardCharsets.UTF_8)); diff --git a/src/test/java/com/kingsrook/qbits/email/health/EmailHealthWidgetTest.java b/src/test/java/com/kingsrook/qbits/email/health/EmailHealthWidgetTest.java index 15a81bb..b1256fb 100644 --- a/src/test/java/com/kingsrook/qbits/email/health/EmailHealthWidgetTest.java +++ b/src/test/java/com/kingsrook/qbits/email/health/EmailHealthWidgetTest.java @@ -62,7 +62,7 @@ class EmailHealthWidgetTest var instance = H2Support.setup(config -> config.withSecretResolver(name -> null)); assertThat(instance.getWidget("emailHealth").getType()).isEqualTo(WidgetType.STATISTICS.getType()); var data = render(); - assertThat(data.getCount()).isEqualTo("UNKNOWN"); + assertThat(data.getCount()).isEqualTo("Not checked yet"); assertThat(data.getCountContext()).contains("not configured"); assertThat(data.getCountURL()).isNull(); } @@ -88,15 +88,18 @@ class EmailHealthWidgetTest assertThat(render().getCountURL()).isNull(); QContext.getQSession().setPermissions(Set.of("email.view", "health.read")); instance.setEnforcePermissionsInCoreActions(true); - assertThat(render().getCount()).isEqualTo("UNKNOWN"); + assertThat(render().getCount()).isEqualTo("Not checked yet"); + assertThat(render().getCountContext()).contains("Checks run every 5 minutes"); connection.createStatement().execute("INSERT INTO health_component VALUES (1, 'email', 'DOWN'), (2, 'other', 'UP')"); - assertThat(render().getCount()).isEqualTo("DOWN"); + assertThat(render().getCount()).isEqualTo("Down"); String link = URLDecoder.decode(render().getCountURL(), StandardCharsets.UTF_8); assertThat(link).startsWith("/app/health_check?filter=").contains("component", "email"); connection.createStatement().execute("UPDATE health_component SET status = 'UP' WHERE id = 1"); - assertThat(render().getCount()).isEqualTo("UP"); + assertThat(render().getCount()).isEqualTo("Healthy"); + connection.createStatement().execute("UPDATE health_component SET status = 'DEGRADED' WHERE id = 1"); + assertThat(render().getCount()).isEqualTo("Degraded"); connection.createStatement().execute("UPDATE health_component SET status = 'S3NT1NEL-secret' WHERE id = 1"); - assertThat(render().getCount()).isEqualTo("UNKNOWN"); + assertThat(render().getCount()).isEqualTo("Not checked yet"); assertThat(render().getCountContext()).doesNotContain("S3NT1NEL-secret"); } } -- 2.54.0