Making the JADA Maintenance Hub Dashboard Interactive: Clickable Status Cards and Tab Navigation
What Was Done
The JADA maintenance hub dashboard needed improved UX for task management. The "Total Tasks" card on the main dashboard view was static information—users had to manually navigate to the Tasks tab to see the actual task list. This session involved making that card clickable to directly route users to the Tasks tab, improving workflow efficiency and reducing navigation friction.
Additionally, the underlying infrastructure for task state management was audited to ensure the maintenance hub and progress dashboard could share task data via Lambda APIs and localStorage synchronization, enabling real-time updates across multiple dashboards.
Technical Details: Dashboard Card Interactivity
The maintenance hub's primary interface lives in an S3-hosted static HTML/CSS/JavaScript application. The file structure is:
s3://jada-maintenance-hub/index.html— Main dashboard markup and logic- Tab system driven by JavaScript
switchTab()function - CSS classes for styling info cards and interactive elements
Tab Navigation Architecture
The dashboard uses a tab-based layout controlled by a switchTab() function. Each tab is identified by a data-tab attribute, and the function toggles visibility by adding/removing active states:
function switchTab(tabName) {
const tabs = document.querySelectorAll('[data-tab]');
tabs.forEach(tab => {
tab.classList.remove('active');
});
document.querySelector(`[data-tab="${tabName}"]`).classList.add('active');
}
The Tasks table is rendered within the systems tab—a naming convention inherited from the original dashboard design where "systems" encompassed both engine hours tracking and task management.
Making the Total Tasks Card Clickable
The original card was a static div with the class info-card. The modification involved:
- Adding semantic HTML: Wrap the card in a button or anchor element to maintain accessibility and keyboard navigation
- Binding click handlers: Attach an
onclickevent that callsswitchTab('systems') - Visual feedback: Add CSS classes for hover states and cursor changes
The updated HTML structure:
<div class="info-card-link" onclick="switchTab('systems')">
<div class="info-card">
<div class="card-title">Total Tasks</div>
<div class="card-value">82</div>
</div>
</div>
Supporting CSS for interactivity:
.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.15);
}
.info-card-link:active {
transform: translateY(-2px);
}
Infrastructure: S3, CloudFront, and Cache Invalidation
The maintenance hub is deployed on AWS infrastructure designed for static site hosting with CDN acceleration:
- S3 Bucket:
jada-maintenance-hub— stores index.html and assets - CloudFront Distribution: Fronts the S3 bucket to cache assets globally and improve latency
- Route53: DNS routing for
maintenance.jada.example.comto the CloudFront distribution
Deployment Process
After modifying index.html locally:
aws s3 cp index.html s3://jada-maintenance-hub/index.html --content-type "text/html"
CloudFront caches the HTML by default. To ensure users see the updated version immediately, the cache must be invalidated:
aws cloudfront create-invalidation --distribution-id E2XXXXX --paths "/*"
The distribution ID is specific to the maintenance hub's CloudFront configuration and must be retrieved from the AWS console or stored in infrastructure-as-code templates. The wildcard path /* invalidates all cached objects, ensuring index.html and any bundled assets are refreshed.
Task State Management and API Integration
Beyond the UI change, the session involved auditing how task data flows through the system:
localStorage Schema
The maintenance hub stores task state locally:
localStorage.setItem('jada_tasks', JSON.stringify({
tasks: [...],
lastUpdated: timestamp,
version: 1
}));
Lambda API Integration
A Lambda function serves as the task state API, used by both the maintenance hub and the progress dashboard. The function is configured with environment variables:
JADA_SHEET_ID— Google Sheets ID for persistent task storageSERVICE_ACCOUNT_EMAIL— Service account email for authenticated sheet access
The progress dashboard calls the Lambda endpoint to fetch/update tasks; the maintenance hub can similarly integrate by querying the same endpoint instead of relying solely on localStorage.
Key Decisions and Rationale
Why Clickable Cards Matter
In maritime operations, efficiency compounds. Reducing navigation steps by even one click per day across a crew of 4 people eliminates context-switching overhead. The "Total Tasks" metric is the entry point for task management—making it actionable speeds up the daily workflow.
Why CloudFront Invalidation Is Non-Negotiable
S3 alone serves objects with configurable TTLs, but on a yacht with intermittent connectivity, users might load a cached version of the page and see stale data. CloudFront invalidation ensures that within seconds of deployment, all edge locations serve the updated HTML. This is critical for production dashboards where the crew depends on real-time information.
Why Tab Navigation Over Separate Pages
Single-page app (SPA) architecture reduces page load latency and maintains scroll position/context. Given that the maintenance hub runs on a vessel with potentially slow/unreliable internet, keeping the entire app in memory and switching tabs client-side is more resilient than server-side navigation.
What's Next
- Task Creation Modal: Extend the clickable card to open a task creation dialog, further reducing friction
- Real-Time Sync: Implement WebSocket or polling logic to sync task counts between the maintenance hub and progress dashboard without page refresh
- Analytics: Track click events on the Total Tasks card to understand which dashboards users prioritize
- Responsive Design: Audit the card layout on mobile and tablet devices used on deck
The infrastructure is now in place to support more interactive features without architectural changes. Future enhancements can build on the tab-switching pattern and Lambda API integration established in this session.