Making Dashboard Stats Clickable: Interactive Navigation in the JADA Maintenance Hub

What Was Done

The JADA Maintenance Hub's dashboard displays aggregated task metrics in stat cards — one of which shows "Total Tasks: 82". Previously, these cards were read-only display elements. Users viewing the dashboard had to manually navigate to the Tasks tab to see the underlying task list. This session made the Total Tasks card clickable and wired it to programmatically switch the interface to the Systems tab where the full task table lives.

The implementation required three distinct changes across the stack: DOM structure modifications in the HTML markup, CSS styling to indicate interactivity, and JavaScript event binding to trigger tab navigation logic that was already in place.

Technical Details

File Location and Storage Architecture

The JADA Maintenance Hub is hosted as a static site on AWS S3. The key file modified is:

  • s3://jada-maintenance-hub/index.html — The single-page application containing all dashboard markup, styles, and client-side logic

The file was downloaded from S3, modified locally, and re-uploaded. This S3 bucket is fronted by a CloudFront distribution (CDN) to serve content with low latency and enable cache invalidation for instant propagation of updates.

DOM Structure Changes

The Total Tasks stat card was originally a passive <div> with class info-card:

<div class="info-card">
  <h3>Total Tasks</h3>
  <p class="stat">82</p>
</div>

Converting this to an interactive element required wrapping it in a clickable container with semantic HTML. The pattern used was to add an onclick handler that invokes the existing switchTab() function, passing the target tab identifier:

<div class="info-card info-card-link" onclick="switchTab('systems')">
  <h3>Total Tasks</h3>
  <p class="stat">82</p>
</div>

The info-card-link class was added as a secondary selector to layer interactive styling on top of the base info-card styles without modifying the existing CSS rules.

CSS for Interactive State

Interactivity must be visually signaled to users. Three CSS properties were added under the .info-card-link selector:

.info-card-link {
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.info-card-link:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}

Why these choices:

  • cursor: pointer — Changes the mouse cursor to a hand icon on hover, the universal UI signal for clickability
  • transition — Smooths the hover effect over 200ms so the interaction doesn't feel jarring
  • transform: translateY(-4px) — Lifts the card slightly on hover, giving tactile visual feedback
  • box-shadow — Increases shadow depth on hover to enhance the "lifted" illusion and add emphasis

JavaScript Event Binding

The maintenance hub already had a tab switching system implemented. The switchTab() function was defined in the JavaScript section of index.html and worked by:

  1. Hiding all tab panels with display: none
  2. Removing the active class from all tab buttons
  3. Showing the selected tab panel
  4. Adding the active class to the corresponding tab button

The card's onclick="switchTab('systems')" attribute directly calls this function with the string 'systems', which matches the data-tab="systems" attribute on the Systems tab button in the navigation bar. No additional JavaScript was required; the existing infrastructure supported this use case.

Infrastructure and Deployment

S3 and CloudFront

The deployment workflow involved three steps:

  1. Download from S3: Pulled the current version of index.html to the local development environment
  2. Local edits: Modified the DOM structure and CSS in the local file
  3. Upload to S3: Pushed the updated file back to s3://jada-maintenance-hub/index.html
  4. CloudFront cache invalidation: Invalidated the CloudFront distribution's cache for the path /index.html to force edge nodes to fetch the new version immediately

Cache invalidation is critical because CloudFront caches static assets at edge locations around the world. Without invalidation, some users would continue seeing the old version for up to 24 hours (the default TTL). The invalidation command targeted the specific file path rather than the entire distribution, minimizing API calls and cost.

Why Not Store Locally?

The maintenance hub is served from S3 rather than being version-controlled in a Git repository and deployed through a CI/CD pipeline. This is appropriate for this use case because:

  • The HTML file contains embedded CSS and JavaScript with no external build step
  • Changes are infrequent and typically urgent (like today's feature request)
  • S3 + CloudFront provides sufficient performance and availability without additional infrastructure
  • Direct S3 modification allows non-engineers to update content without Git knowledge

For a higher-velocity product, this would warrant a proper CI/CD pipeline with Git-based deployments, automated testing, and staged rollouts. The current approach is optimized for simplicity and speed.

Key Decisions and Trade-offs

  • Inline onclick vs. event listener: Using onclick in HTML is less modern than binding events via JavaScript, but it's appropriate here because the page has no build step and keeping all logic in a single HTML file simplifies deployment and maintenance.
  • CSS classes for styling: Adding a new info-card-link class rather than modifying info-card preserves the base style definition and allows selective application only to clickable cards if other stat cards are later made non-interactive.
  • Immediate navigation vs. loading state: The switchTab() function executes synchronously and displays the tab instantly. No loading spinner or state indication is needed because the tab content is already loaded in the DOM (this is a SPA pattern, not a server-side MPA).

What's Next

This pattern can be extended to other stat cards — clicking "Open Items" could filter the task table to show only incomplete tasks, for example. The architecture supports this without additional infrastructure changes; it's purely a matter of adding more onclick