```html

Making Dashboard Stat Cards Interactive: Linking the Total Tasks Counter to Task Management View

During a recent maintenance cycle on JADA's operational dashboards, we identified a UX gap: the "Total Tasks 82" stat card on the maintenance hub was displaying live task counts but wasn't actionable. Users had to navigate manually to the Systems tab to view the actual task list. This post details how we made that card clickable to improve workflow efficiency, including the infrastructure decisions and deployment pipeline.

The Problem

The maintenance hub dashboard at maintenance.jada.local displays several key performance indicators as static cards, including total active tasks. While the card was visually prominent and correctly tallying task counts, clicking it did nothing. Users performing quick status checks had to perform an extra navigation step to drill into the task details, breaking the natural interaction pattern.

Architecture Overview

The JADA maintenance hub is a single-page application (SPA) built with vanilla JavaScript, deployed as a static HTML file to AWS S3 with CloudFront distribution for global caching and low-latency access. The application uses tab-based navigation controlled by a JavaScript switch statement that manages visibility of different functional areas: Dashboard, Systems (tasks), Maintenance Log, and Configuration.

Key infrastructure components:

  • Origin: S3 bucket (credentials withheld)
  • CDN: CloudFront distribution with index.html cache policy
  • DNS: Route53 alias record pointing CloudFront distribution to maintenance.jada.local
  • Source file: /index.html in S3 root

Technical Implementation

DOM Structure and Tab Navigation

The maintenance hub uses a data-attribute-based tab system. Each section is a div with data-tab="tab-name", and navigation logic lives in a function called switchTab(tabName). For example:

function switchTab(tabName) {
  // Hide all tabs
  document.querySelectorAll('[data-tab]').forEach(tab => {
    tab.style.display = 'none';
  });
  // Show selected tab
  document.querySelector(`[data-tab="${tabName}"]`).style.display = 'block';
  // Update active indicator
  document.querySelectorAll('[data-nav-item]').forEach(item => {
    item.classList.remove('active');
  });
  document.querySelector(`[data-nav-item="${tabName}"]`).classList.add('active');
}

The Systems tab, where the task table lives, is identified by data-tab="systems". This is the target we needed to wire the stat card to.

Making the Stat Card Clickable

The "Total Tasks" display exists as an HTML card with class info-card. The solution involved three changes:

  1. Add onclick handler: Wrap the card content or add an onclick attribute to invoke switchTab('systems')
  2. Update CSS for interactivity: Add a new class info-card-link that applies hover states and cursor feedback
  3. Preserve semantics: Keep the card's existing content and structure; don't restructure the DOM

The HTML change was minimal:

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

CSS additions for the interactive state:

.info-card-link {
  cursor: pointer;
  transition: background-color 0.2s ease, transform 0.15s ease;
}

.info-card-link:hover {
  background-color: rgba(66, 135, 245, 0.1);
  transform: translateY(-2px);
}

.info-card-link:active {
  transform: translateY(0);
}

These styles provide immediate visual feedback that the card is interactive without breaking the existing design language.

Deployment Pipeline

Local Changes and S3 Sync

The maintenance hub lives as a static file in S3, not in a traditional git repository. Updates required a download-modify-upload cycle:

# Download current index.html from S3
aws s3 cp s3://jada-maintenance-hub/index.html ./index.html

# Edit locally (add onclick and CSS)
vim index.html

# Upload back to S3
aws s3 cp ./index.html s3://jada-maintenance-hub/index.html --content-type "text/html"

Cache Invalidation

Static files in CloudFront are cached based on TTL and version headers. Simply uploading to S3 doesn't guarantee immediate updates to end users. CloudFront invalidation was required:

# Invalidate the CloudFront distribution cache
aws cloudfront create-invalidation --distribution-id DISTRIBUTION_ID --paths "/index.html"

This command clears the cached version of index.html from all CloudFront edge nodes, forcing a fresh fetch from origin on the next request. Without this step, users would see the old version for up to 24 hours (depending on cache TTL).

Why These Decisions

Why not restructure the DOM? The maintenance hub's JS relies on querySelectorors for tab logic. Restructuring cards risked breaking CSS layouts or event delegation. Adding a single class and onclick attribute minimized surface area for bugs.

Why use onclick instead of event listeners? For a single card with high confidence in where it'll be placed, inline onclick is acceptable and more maintainable than hunting for the card element in a large JS file. In a larger app, delegated event listeners would be preferred.

Why CSS classes for hover instead of inline styles? Separation of concerns: styles belong in the stylesheet, not inline attributes. This also ensures the hover and active states remain consistent if the card design changes later.

Why invalidate CloudFront? CloudFront's default behavior is to cache aggressively. Without invalidation, users in different geographic regions or on repeat visits would see stale HTML. The invalidation ensures a hard refresh of the origin within minutes.

Testing and Verification

Post-deployment validation involved:

  • Opening the maintenance hub in a browser and confirming the Total Tasks card shows hover effects
  • Clicking the card and verifying the Systems tab becomes active
  • Checking browser DevTools to confirm CloudFront served the new version (cache-control headers, ETag changes)
  • Testing from a different network to ensure the invalidation reached all edge nodes

What's Next

This change was a quick win, but opens the door for broader dashboard interactivity improvements. Future enhancements could include:

  • Making other stat cards (maintenance log count, system alerts) clickable and contextual
  • Adding a filter or search box that switches to the Systems tab with pre-filtered results
  • Refactoring the entire SPA to use a proper state management library (Vue, React) and a build pipeline

For now, the maintenance hub users can click