Skip to content

Add Dashboard page as first per-agency sidebar entry - #44

Merged
aaronbrethorst merged 2 commits into
developfrom
ui-redesign-3
Apr 29, 2026
Merged

aaronbrethorst merged 2 commits into
developfrom
ui-redesign-3

Conversation

@aaronbrethorst

@aaronbrethorst aaronbrethorst commented Apr 29, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds a new Dashboard page (/dashboard/index.jsp) that combines the Active Blocks summary, Server Status monitor grid, and the five largest DB tables (horizontal-bar chart + table) onto one overview page. Wired as the first link under each agency in the sidebar.
  • Extracts the active-blocks summary stat-strip and the server-status monitor grid into shared <t:> tags (activeBlocksSummary.tag, serverStatusGrid.tag) so the original /status/activeBlocks.jsp and /status/serverStatus.jsp pages render the same markup as the dashboard.
  • Adds DbDiskSpaceQuery.getTopTables(agencyId, limit) returning a typed List<TableSize>. The dashboard renders bars/table directly from these rows; no new charting dependency.
  • Makes the active-blocks Stimulus controller short-circuit route fetching when the accordion/route-template targets are absent so the dashboard can mount the controller for the summary strip alone.

Test plan

  • mvn -pl transitclockWebapp -am package -DskipTests builds clean.
  • Existing webapp tests pass (mvn -pl transitclockWebapp test) — the DbDiskSpaceQueryTest and JSP audit tests are green. (One pre-existing DbDiskSpaceResourceTest failure on NoClassDefFound com/fasterxml/jackson/databind/ObjectMapper is unrelated to this PR; it was introduced in b972cee3 against the webapp's deliberately-Jackson-excluded runtime — flagged below.)
  • /dashboard/index.jsp?a=1 renders the three sections with live data (verified in browser via Playwright; zero console errors).
  • /status/activeBlocks.jsp?a=1 regression check — full page including the route accordion still renders and the Stimulus controller fetches both summary and per-route data with no console errors.
  • /status/serverStatus.jsp?a=1 regression check — monitor grid renders identically.
  • /status/dbDiskSpace.jsp?a=1 regression check — Google Charts chart and tables still render.
  • Sidebar shows Dashboard as the first entry under the agency name, with the active-pill highlight when on the dashboard.

Review notes (non-blocking, for reviewer judgment)

  • Heading-level skip on /status/serverStatus.jsp. The shared serverStatusGrid.tag emits <h3> for the alert and per-monitor headings. On the dashboard the page's own <h1> and section <h2> make this correct, but on serverStatus.jsp (which has only an <h1>) it skips an h2. JSP EL can't expand inside element names, so making this a tag attribute would mean a <c:choose> per heading. Leaving as-is for now; happy to add the choose if reviewer prefers strict heading hierarchy.
  • No new test for getTopTables. The existing DbDiskSpaceQueryTest covers getTotalsJson / getDetailsJson. A unit test pinning the LIMIT clamp at the bounds and the addRow mapping into TableSize would catch future drift; leaving as a follow-up.
  • TableSize.prettySize field couples the API surface to Postgres pg_size_pretty formatting. Fine for the current single consumer but worth revisiting if a second consumer ever wants different formatting/locale; a Bytes.humanize(long) helper plus dropping the field would be the cleanup.
  • Pre-existing GenericQuery static-Connection. org.transitclock.db.GenericQuery keeps a static Connection reassigned by every constructor and never closed. The dashboard adds another concurrent caller (getTopTables alongside the existing getTotalsJson), making the latent thread-safety/leak concern a little more reachable. Out of scope for this PR.
  • Pre-existing test failure unrelated to this branch. DbDiskSpaceResourceTest.happyPath_wrapsBothJsonsInEnvelope fails with NoClassDefFound com/fasterxml/jackson/databind/ObjectMapper. The webapp pom.xml deliberately excludes jersey-media-json-jackson (per its own comment) to keep Hibernate's Jackson chain at 2.8.9. Worth a separate fix to either provide Jackson at test scope only or remove the ObjectMapper.readTree line.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new Dashboard page featuring server status monitoring, top database table disk usage metrics, and active block statistics.
  • Localization

    • Added Polish language support for Dashboard labels.
  • Refactor

    • Updated styling and layout in API reports and removed legacy CSS rules.

Removes the unused body/#mainDiv/#title/#subtitle/.choicesList/#dataTable
rules from general.css and migrates apiCalls/index.jsp and
vertStopsScheduleApiParams.jsp off those legacy classes onto Tailwind
utilities, matching the rest of the redesigned pages.
Combines the Active Blocks summary, Server Status monitor grid, and the
five largest DB tables into a single overview page. The summary strip and
monitor grid are extracted into shared tags so the original Active Blocks
and Server Status pages render the same markup; the active-blocks Stimulus
controller short-circuits its route fetch when accordion targets aren't
present so the dashboard can mount the controller for the summary alone.
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Introduces a new dashboard feature for transit agencies that displays server monitoring status and top disk-consuming database tables. Includes a new dashboard JSP page, supporting JSP tag components for rendering active blocks summaries and server status grids, a database API for querying top tables, i18n support, CSS cleanup, and refactors existing status views to use reusable tag components.

Changes

Cohort / File(s) Summary
Database Query API
DbDiskSpaceQuery.java
Adds TableSize record and getTopTables(agencyId, limit) public API to retrieve list of largest N tables with size information, backed by new TOP_TABLES_SQL statement and TopTablesQuery inner class.
Internationalization
text.properties, text_pl.properties
Adds new i18n property div.dashboard with values Dashboard (English) and Pulpit (Polish) to support dashboard label localization.
JSP Tag Components
activeBlocksSummary.tag, serverStatusGrid.tag, layout.tag
Introduces reusable JSP tags for rendering active blocks metrics summary, conditional server status display (error or results grid), and adds dashboard navigation link to sidebar layout with active-state styling.
New Dashboard Page
dashboard/index.jsp
New dashboard JSP requiring agency parameter; fetches and displays server monitoring status via ServerStatusInterfaceFactory, renders top disk-consuming tables from DbDiskSpaceQuery, and includes active blocks summary with progress-bar visualizations.
CSS Cleanup
general.css
Removes legacy global CSS rules including body defaults, layout IDs, tooltip styles, pre-Tailwind form input styling, color states, and table-specific styling while preserving Tailwind-aligned .form-control classes.
JavaScript Controller Update
active_blocks_controller.js
Conditionally fetches route data only when both accordionTarget and routeTemplateTarget elements are present, leaving summary fetching behavior unchanged.
JSP View Refactoring
status/activeBlocks.jsp, status/serverStatus.jsp
Replaces inline markup with custom tag components: activeBlocks.jsp uses <t:activeBlocksSummary/> tag; serverStatus.jsp delegates result rendering to <t:serverStatusGrid/> tag.
API Calls Index Refactoring
reports/apiCalls/index.jsp
Removes outer mainDiv wrapper and updates list containers from ul.choicesList to ul with Tailwind-style classes (list-disc list-outside pl-4), preserving all navigation links.
Vertical Stops Schedule Page
reports/apiCalls/vertStopsScheduleApiParams.jsp
Reformats title attribute using multi-line <jsp:attribute> block, normalizes CSS whitespace, and fixes indentation inconsistencies without changing functional behavior.

Sequence Diagram

sequenceDiagram
    actor User
    participant Browser
    participant DashboardJSP as Dashboard JSP
    participant ServerStatusFactory as ServerStatusFactory
    participant RMICore as RMI Core
    participant DbDiskSpace as DbDiskSpaceQuery
    participant Database as Database

    User->>Browser: GET /dashboard?a=agencyId
    Browser->>DashboardJSP: Request dashboard page
    
    DashboardJSP->>ServerStatusFactory: getServerStatus()
    ServerStatusFactory->>RMICore: Fetch monitoring results
    RMICore-->>ServerStatusFactory: monitorResults + stats
    ServerStatusFactory-->>DashboardJSP: Server status data
    
    DashboardJSP->>DbDiskSpace: getTopTables(agencyId, 5)
    DbDiskSpace->>Database: Execute TOP_TABLES_SQL query
    Database-->>DbDiskSpace: Table size rows
    DbDiskSpace-->>DashboardJSP: List<TableSize> records
    
    DashboardJSP->>Browser: Render dashboard with status grid & disk usage table
    Browser-->>User: Display dashboard UI
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a new Dashboard page as the first sidebar entry for each agency.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ui-redesign-3

Review rate limit: 2/3 reviews remaining, refill in 20 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
transitclockWebapp/src/main/java/org/transitclock/reports/DbDiskSpaceQuery.java (1)

105-109: Consider returning an immutable list from run().

q.rows is mutable and exposed directly to callers. Returning an immutable copy avoids accidental downstream mutation.

♻️ Proposed hardening
         static List<TableSize> run(String agencyId, String sql) throws SQLException {
             TopTablesQuery q = new TopTablesQuery(agencyId);
             q.doQuery(sql);
-            return q.rows;
+            return List.copyOf(q.rows);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@transitclockWebapp/src/main/java/org/transitclock/reports/DbDiskSpaceQuery.java`
around lines 105 - 109, The run method currently returns the mutable q.rows list
from TopTablesQuery, exposing internal state; modify
DbDiskSpaceQuery.run(String,String) to return an immutable copy (e.g., use
List.copyOf(q.rows) or Collections.unmodifiableList(new ArrayList<>(q.rows))) so
callers cannot mutate the internal list while still preserving contents; locate
the run method and replace the direct return of q.rows with the immutable
wrapper or copy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@transitclockWebapp/src/main/webapp/dashboard/index.jsp`:
- Around line 81-83: The JSP is inserting unescaped request/DB values directly
into attributes (e.g., agencyId in the anchor href and t.tableName used
elsewhere), which can lead to XSS; fix by building hrefs via JSTL c:url with
param (use c:url
value="${pageContext.request.contextPath}/status/activeBlocks.jsp" and <c:param
name="a" value="${agencyId}"/>) so agencyId is URL-encoded, and escape any
attribute/text output from DB like t.tableName with JSTL fn:escapeXml (or the
equivalent server-side escaping utility) before inserting into attributes or
text nodes; apply the same changes to the other occurrences referenced (lines
~100-103, 115-118, 136) so all dynamic attributes are URL-encoded or
XML-escaped.
- Line 140: The width expression can divide by zero when maxBytes == 0; update
the JSP expression that builds the style width (the inline style using
${(t.bytes * 100.0) / maxBytes} ) to guard against zero by computing the
percentage only when maxBytes > 0 (otherwise use 0%), e.g. replace the raw
division with a conditional expression that yields (t.bytes * 100.0) / maxBytes
if maxBytes > 0, else 0, so the resulting style attribute always contains a
valid width value.
- Around line 19-21: WebAgency.getCachedWebAgency(agencyId) may return null and
the code currently dereferences it in pageContext.setAttribute(...,
WebAgency.getCachedWebAgency(agencyId).getAgencyName()), causing a 500; update
the JSP to null-check the result of WebAgency.getCachedWebAgency(agencyId) (or
store it in a local variable) before calling getAgencyName(), and set a safe
fallback (e.g., empty string or "Unknown Agency") into pageContext via
pageContext.setAttribute("agencyName", ...) when the cached agency is null so
the page does not error on invalid agencyId (refer to
WebAgency.getCachedWebAgency, getAgencyName, and agencyId).

In `@transitclockWebapp/src/main/webapp/WEB-INF/tags/activeBlocksSummary.tag`:
- Line 13: Replace the hard-coded English label in activeBlocksSummary.tag (the
<span class="text-xs text-gray-500 font-medium">total</span>) with a
localization lookup (use the same message key naming used elsewhere in this
component), and add a matching "div.total" entry to each locale bundle so Polish
and other locales render correctly; ensure the tag uses the same resource bundle
reference pattern as other labels in activeBlocksSummary.tag.

---

Nitpick comments:
In
`@transitclockWebapp/src/main/java/org/transitclock/reports/DbDiskSpaceQuery.java`:
- Around line 105-109: The run method currently returns the mutable q.rows list
from TopTablesQuery, exposing internal state; modify
DbDiskSpaceQuery.run(String,String) to return an immutable copy (e.g., use
List.copyOf(q.rows) or Collections.unmodifiableList(new ArrayList<>(q.rows))) so
callers cannot mutate the internal list while still preserving contents; locate
the run method and replace the direct return of q.rows with the immutable
wrapper or copy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 444fa892-23ec-4b6c-a26d-c770ee7a7f36

📥 Commits

Reviewing files that changed from the base of the PR and between ef46285 and 88f8412.

📒 Files selected for processing (13)
  • transitclockWebapp/src/main/java/org/transitclock/reports/DbDiskSpaceQuery.java
  • transitclockWebapp/src/main/resources/org/transitclock/i18n/text.properties
  • transitclockWebapp/src/main/resources/org/transitclock/i18n/text_pl.properties
  • transitclockWebapp/src/main/webapp/WEB-INF/tags/activeBlocksSummary.tag
  • transitclockWebapp/src/main/webapp/WEB-INF/tags/layout.tag
  • transitclockWebapp/src/main/webapp/WEB-INF/tags/serverStatusGrid.tag
  • transitclockWebapp/src/main/webapp/css/general.css
  • transitclockWebapp/src/main/webapp/dashboard/index.jsp
  • transitclockWebapp/src/main/webapp/javascript/controllers/active_blocks_controller.js
  • transitclockWebapp/src/main/webapp/reports/apiCalls/index.jsp
  • transitclockWebapp/src/main/webapp/reports/apiCalls/vertStopsScheduleApiParams.jsp
  • transitclockWebapp/src/main/webapp/status/activeBlocks.jsp
  • transitclockWebapp/src/main/webapp/status/serverStatus.jsp
💤 Files with no reviewable changes (1)
  • transitclockWebapp/src/main/webapp/css/general.css

Comment on lines +19 to +21
pageContext.setAttribute("agencyId", agencyId);
pageContext.setAttribute("agencyName", WebAgency.getCachedWebAgency(agencyId).getAgencyName());
pageContext.setAttribute("now", Time.timeStrNoTimeZone(new Date()));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard unknown agencies before dereferencing cached metadata.

WebAgency.getCachedWebAgency(agencyId) can be null for invalid a values, which will 500 the page when calling .getAgencyName().

🛠️ Proposed fix
 <%@ page import="org.transitclock.db.webstructs.WebAgency" %>
@@
 String agencyId = request.getParameter("a");
 if (agencyId == null || agencyId.isEmpty()) {
     response.getWriter().write("You must specify agency in query string (e.g. ?a=mbta)");
     return;
 }
+WebAgency agency = WebAgency.getCachedWebAgency(agencyId);
+if (agency == null) {
+    response.setStatus(404);
+    response.getWriter().write("Unknown agency: " + agencyId);
+    return;
+}
@@
-pageContext.setAttribute("agencyName", WebAgency.getCachedWebAgency(agencyId).getAgencyName());
+pageContext.setAttribute("agencyName", agency.getAgencyName());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transitclockWebapp/src/main/webapp/dashboard/index.jsp` around lines 19 - 21,
WebAgency.getCachedWebAgency(agencyId) may return null and the code currently
dereferences it in pageContext.setAttribute(...,
WebAgency.getCachedWebAgency(agencyId).getAgencyName()), causing a 500; update
the JSP to null-check the result of WebAgency.getCachedWebAgency(agencyId) (or
store it in a local variable) before calling getAgencyName(), and set a safe
fallback (e.g., empty string or "Unknown Agency") into pageContext via
pageContext.setAttribute("agencyName", ...) when the cached agency is null so
the page does not error on invalid agencyId (refer to
WebAgency.getCachedWebAgency, getAgencyName, and agencyId).

Comment on lines +81 to +83
<a href="${pageContext.request.contextPath}/status/activeBlocks.jsp?a=${agencyId}"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium text-gray-700 bg-white border border-gray-300 hover:bg-gray-50">
View details &rarr;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Avoid raw attribute interpolation for request/DB values.

agencyId (request-derived) and t.tableName (DB-derived) are inserted directly into HTML attributes. Encode URLs and escape attribute text to prevent attribute-break/XSS paths.

🔒 Proposed fix
+<c:url var="activeBlocksUrl" value="/status/activeBlocks.jsp">
+  <c:param name="a" value="${agencyId}" />
+</c:url>
+<c:url var="serverStatusUrl" value="/status/serverStatus.jsp">
+  <c:param name="a" value="${agencyId}" />
+</c:url>
+<c:url var="dbDiskSpaceUrl" value="/status/dbDiskSpace.jsp">
+  <c:param name="a" value="${agencyId}" />
+</c:url>
@@
-        <a href="${pageContext.request.contextPath}/status/activeBlocks.jsp?a=${agencyId}"
+        <a href="${pageContext.request.contextPath}${activeBlocksUrl}"
@@
-        <a href="${pageContext.request.contextPath}/status/serverStatus.jsp?a=${agencyId}"
+        <a href="${pageContext.request.contextPath}${serverStatusUrl}"
@@
-      <a href="${pageContext.request.contextPath}/status/dbDiskSpace.jsp?a=${agencyId}"
+      <a href="${pageContext.request.contextPath}${dbDiskSpaceUrl}"
@@
-                  <span class="font-mono text-gray-900 truncate" title="${t.tableName}"><c:out value="${t.tableName}"/></span>
+                  <span class="font-mono text-gray-900 truncate"><c:out value="${t.tableName}"/></span>

Also applies to: 100-103, 115-118, 136-136

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transitclockWebapp/src/main/webapp/dashboard/index.jsp` around lines 81 - 83,
The JSP is inserting unescaped request/DB values directly into attributes (e.g.,
agencyId in the anchor href and t.tableName used elsewhere), which can lead to
XSS; fix by building hrefs via JSTL c:url with param (use c:url
value="${pageContext.request.contextPath}/status/activeBlocks.jsp" and <c:param
name="a" value="${agencyId}"/>) so agencyId is URL-encoded, and escape any
attribute/text output from DB like t.tableName with JSTL fn:escapeXml (or the
equivalent server-side escaping utility) before inserting into attributes or
text nodes; apply the same changes to the other occurrences referenced (lines
~100-103, 115-118, 136) so all dynamic attributes are URL-encoded or
XML-escaped.

<span class="text-gray-500 font-mono tabular-nums shrink-0"><c:out value="${t.prettySize}"/></span>
</div>
<div class="h-2 rounded-full bg-gray-100 overflow-hidden">
<div class="h-full bg-brand-accent rounded-full" style="width: ${(t.bytes * 100.0) / maxBytes}%"></div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Protect the width calculation against zero maxBytes.

If all rows resolve to 0 bytes, this computes a divide-by-zero and produces invalid width output.

🧮 Proposed fix
-                  <div class="h-full bg-brand-accent rounded-full" style="width: ${(t.bytes * 100.0) / maxBytes}%"></div>
+                  <div class="h-full bg-brand-accent rounded-full"
+                       style="width: ${maxBytes gt 0 ? (t.bytes * 100.0) / maxBytes : 0}%"></div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="h-full bg-brand-accent rounded-full" style="width: ${(t.bytes * 100.0) / maxBytes}%"></div>
<div class="h-full bg-brand-accent rounded-full"
style="width: ${maxBytes gt 0 ? (t.bytes * 100.0) / maxBytes : 0}%"></div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transitclockWebapp/src/main/webapp/dashboard/index.jsp` at line 140, The
width expression can divide by zero when maxBytes == 0; update the JSP
expression that builds the style width (the inline style using ${(t.bytes *
100.0) / maxBytes} ) to guard against zero by computing the percentage only when
maxBytes > 0 (otherwise use 0%), e.g. replace the raw division with a
conditional expression that yields (t.bytes * 100.0) / maxBytes if maxBytes > 0,
else 0, so the resulting style attribute always contains a valid width value.

<div class="text-[11px] font-semibold uppercase tracking-wider text-gray-500"><fmt:message key="div.blocks"/></div>
<div class="flex items-baseline gap-1.5 mt-0.5">
<span data-field="total-blocks" class="text-[22px] font-bold tabular-nums text-gray-900">—</span>
<span class="text-xs text-gray-500 font-medium">total</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Localize the remaining hard-coded label.

total is the only visible label in this shared component that is still English, so Polish and future locales will render it inconsistently.

Suggested fix
-      <span class="text-xs text-gray-500 font-medium">total</span>
+      <span class="text-xs text-gray-500 font-medium"><fmt:message key="div.total"/></span>

Add the matching div.total entry to the locale bundles as well.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span class="text-xs text-gray-500 font-medium">total</span>
<span class="text-xs text-gray-500 font-medium"><fmt:message key="div.total"/></span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transitclockWebapp/src/main/webapp/WEB-INF/tags/activeBlocksSummary.tag` at
line 13, Replace the hard-coded English label in activeBlocksSummary.tag (the
<span class="text-xs text-gray-500 font-medium">total</span>) with a
localization lookup (use the same message key naming used elsewhere in this
component), and add a matching "div.total" entry to each locale bundle so Polish
and other locales render correctly; ensure the tag uses the same resource bundle
reference pattern as other labels in activeBlocksSummary.tag.

@aaronbrethorst
aaronbrethorst merged commit 0206e9f into develop Apr 29, 2026
2 checks passed
@aaronbrethorst
aaronbrethorst deleted the ui-redesign-3 branch April 29, 2026 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant