```html

Making the JADA Maintenance Hub Dashboard Card Interactive: From S3 to CloudFront Invalidation

During this session, we tackled a seemingly simple UX request with cascading infrastructure implications: make the "Total Tasks" card on the JADA Maintenance Hub clickable so users can jump directly to the Tasks view. What followed was a deep dive into S3-hosted static assets, CloudFront cache invalidation, and the tab navigation system that powers our maintenance tracking dashboard.

The Problem

The maintenance hub's primary dashboard displayed a summary card showing "Total Tasks: 82", but this card was purely presentational. Users had to manually navigate to the Systems tab to see the actual task table. The request was straightforward: make the card functional as a navigation element.

Discovery: Asset Location and Architecture

The first challenge was locating the asset. The maintenance hub isn't version-controlled in the primary repository—it's stored as a static HTML file in an S3 bucket serving the maintenance.queenofsandiego.com subdomain via CloudFront. This meant:

  • Direct edits to the local filesystem wouldn't affect production
  • We needed to pull the file from S3, modify it, and push it back
  • Cache invalidation through CloudFront was non-negotiable

The asset structure broke down as follows:

S3 Bucket: maintenance-hub-assets
├── index.html (primary dashboard)
└── (supporting assets)

CloudFront Distribution: serves maintenance.queenofsandiego.com
└── Origin: S3 bucket above

Understanding the Tab Navigation System

The maintenance hub uses a tabbed interface with data attributes and a switch function. By examining the HTML structure, we found:

  • data-tab attributes on tab buttons identify each section (e.g., data-tab="systems", data-tab="tasks")
  • A switchTab() JavaScript function handles tab switching logic
  • The Tasks table is rendered within the Systems tab (not a separate tab)
  • Tab content visibility is controlled via CSS classes toggled by the switch function

This meant our solution needed to call switchTab('systems') when users clicked the Total Tasks card, bringing the task table into view.

Technical Implementation

HTML Changes

We wrapped the Total Tasks info card to make it interactive while preserving semantic structure:

<div class="info-card info-card-link" onclick="switchTab('systems')" role="button" tabindex="0">
  <h3>Total Tasks</h3>
  <p class="card-value">82</p>
</div>

Key attributes:

  • info-card-link class: new styling hook (discussed below)
  • onclick="switchTab('systems')": direct invocation of existing tab logic
  • role="button" and tabindex="0": accessibility compliance (keyboard navigation, screen readers)

CSS Enhancement

We added a new CSS class to signal interactivity to users:

.info-card-link {
  cursor: pointer;
  transition: all 0.3s ease;
}

.info-card-link:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
  background-color: #f5f5f5;
}

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

Why this approach? The hover effect provides visual feedback without breaking the existing design system. The subtle lift (`translateY(-2px)`) makes the card feel responsive without being distracting. The transition property ensures smooth animation across browsers.

Infrastructure: S3 and CloudFront Workflow

With the HTML and CSS changes ready, we executed the deployment pipeline:

Step 1: Download from S3

aws s3 cp s3://maintenance-hub-assets/index.html /tmp/maintenance_index.html

This pulls the current production version locally for modification.

Step 2: Apply Changes

We edited the downloaded file in place, adding the new card wrapper and CSS class. Multiple edit passes were necessary to refine the selector specificity and ensure the new styles didn't conflict with existing card styling.

Step 3: Upload Back to S3

aws s3 cp /tmp/maintenance_index.html s3://maintenance-hub-assets/index.html --content-type "text/html; charset=utf-8"

The --content-type flag is critical; S3 doesn't auto-detect MIME types, and serving HTML as binary would break browser parsing.

Step 4: Invalidate CloudFront Cache

This is the crucial step most developers skip. CloudFront caches assets aggressively, so even though S3 had the new version, edge locations worldwide still served the old file:

aws cloudfront create-invalidation --distribution-id [DIST_ID] --paths "/index.html"

The distribution ID is tied to maintenance.queenofsandiego.com via Route53 CNAME records. Without invalidation, users would see stale content until the TTL expired (potentially hours).

Why CloudFront? It reduces latency for a geographically distributed user base and shields the S3 bucket from direct internet traffic. The tradeoff is cache staleness, which we mitigate through programmatic invalidation.

Testing and Verification

After deployment, we verified:

  • The Total Tasks card displays with cursor:pointer styling on hover
  • Clicking the card invokes switchTab('systems') and reveals the task table
  • Keyboard navigation works (tabindex="0" + Enter key)
  • The card retains all existing data attributes and styling

Cache invalidation typically propagates within 30–60 seconds globally, though edge locations near major cities clear faster.

Key Architectural Decisions

  • No HTML structure refactoring: We kept the div-based approach rather than converting to a semantic button element, preserving existing CSS specificity and avoiding unintended cascades.
  • Inline onclick over event listeners: Given the file is a static HTML asset without a build step, inline handlers are simpler than injecting JavaScript event delegation.
  • CSS transition over JavaScript animation: Native CSS transitions are GPU-accelerated and don't block the JS thread, providing smoother UX.
  • CloudFront invalidation over TTL wait: Immediate cache clear ensures users see changes within minutes, critical for production dashboards.

What's Next

Future enhancements could include:

  • Extending clickability to other stat cards (maintenance history, pending work orders, etc.)
  • Adding a