# Chunk 7: Jobs Pages **Parent:** [Build Graph Dashboard](../build-graph-dashboard.md) **Previous:** [Chunk 6: Partition Pages](./chunk-6-partition-pages.md) **Next:** [Chunk 8: Graph Analysis](./chunk-8-graph-analysis.md) ## Overview Implement job listing and individual job metrics pages with performance data, success rates, and execution history. ## Scope ### In Scope - Jobs listing page with high-level metadata - Individual job metrics and performance pages - Success rate tracking and trends - Recent job runs with execution details - Average duration and timing analysis - Job label URL encoding for safe navigation ### Out of Scope - Complex performance analytics - Historical trend analysis beyond recent runs - Job configuration editing - Advanced filtering beyond basic search ## Technical Approach ### Data Sources From Build Graph Service API and build event log: - Job list from graph analysis - Job execution history from build events - Performance metrics aggregated from event data - Success/failure rates from job events ### URL Encoding ```typescript // Handle job labels in URLs (similar to partition refs) function encodeJobLabel(label: string): string { return btoa(label).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); } function decodeJobLabel(encoded: string): string { const padded = encoded.replace(/-/g, '+').replace(/_/g, '/'); return atob(padded); } ``` ### Component Structure ```typescript const JobsList = { oninit: () => { this.jobs = []; this.searchTerm = ''; this.loadJobs(); }, view: () => [ m('.jobs-header', [ m('h1', 'Jobs'), m('input', { placeholder: 'Search jobs...', oninput: (e) => this.searchTerm = e.target.value, }) ]), m('.jobs-table', [ m('table.table', [ m('thead', [ m('tr', [ m('th', 'Job Label'), m('th', 'Success Rate'), m('th', 'Avg Duration'), m('th', 'Recent Runs'), m('th', 'Last Run'), ]) ]), m('tbody', this.filteredJobs().map(job => m('tr', [ m('td', m('a', { href: `/jobs/${encodeJobLabel(job.label)}` }, job.label)), m('td', [ m('.badge', job.success_rate >= 0.9 ? 'success' : 'warning'), ` ${Math.round(job.success_rate * 100)}%` ]), m('td', formatDuration(job.avg_duration)), m('td', job.recent_runs), m('td', formatTime(job.last_run)), ]) )) ]) ]) ] }; const JobMetrics = { oninit: (vnode) => { this.jobLabel = decodeJobLabel(vnode.attrs.label); this.metrics = null; this.recentRuns = []; this.loadJobMetrics(); }, view: () => [ m('.job-header', [ m('h1', this.jobLabel), m('.job-stats', [ m('.stat', [ m('.stat-title', 'Success Rate'), m('.stat-value', `${Math.round(this.metrics?.success_rate * 100)}%`), ]), m('.stat', [ m('.stat-title', 'Avg Duration'), m('.stat-value', formatDuration(this.metrics?.avg_duration)), ]), m('.stat', [ m('.stat-title', 'Total Runs'), m('.stat-value', this.metrics?.total_runs), ]), ]) ]), m('.job-content', [ m('.performance-chart', [ m('h2', 'Performance Trends'), m('.chart-placeholder', 'Success rate and duration trends over time'), // Simple trend visualization or table m('table.table', [ m('thead', [ m('tr', [ m('th', 'Date'), m('th', 'Success Rate'), m('th', 'Avg Duration'), ]) ]), m('tbody', this.metrics?.daily_stats?.map(stat => m('tr', [ m('td', formatDate(stat.date)), m('td', `${Math.round(stat.success_rate * 100)}%`), m('td', formatDuration(stat.avg_duration)), ]) )) ]) ]), m('.recent-runs', [ m('h2', 'Recent Runs'), m('table.table', [ m('thead', [ m('tr', [ m('th', 'Build Request'), m('th', 'Partitions'), m('th', 'Status'), m('th', 'Duration'), m('th', 'Started'), ]) ]), m('tbody', this.recentRuns.map(run => m('tr', [ m('td', m('a', { href: `/builds/${run.build_id}` }, run.build_id)), m('td', run.partitions.join(', ')), m('td', m('.badge', run.status)), m('td', formatDuration(run.duration)), m('td', formatTime(run.started_at)), ]) )) ]) ]) ]) ] }; ``` ### Metrics Calculation From build event log: - Success rate: completed jobs / total jobs - Average duration: mean time from SCHEDULED to COMPLETED/FAILED - Recent runs: last 50 job executions - Daily aggregations for trend analysis ## Implementation Strategy 1. **Create Data Layer** - API integration for job data - Metrics calculation from build events - Search and filtering logic 2. **Build Jobs List Page** - Job table with search - High-level metrics display - Performance indicators 3. **Individual Job Pages** - Detailed metrics display - Performance trends - Recent runs history 4. **Performance Visualization** - Simple trend charts or tables - Success rate indicators - Duration analysis ## Deliverables - [ ] Jobs listing page with search and metrics - [ ] Individual job metrics pages - [ ] Success rate tracking and display - [ ] Performance trends visualization - [ ] Recent job runs history - [ ] Job label URL encoding/decoding ## Success Criteria - Jobs list loads with accurate metrics - Individual job pages show detailed performance data - Success rates are calculated correctly - Performance trends are meaningful - Recent runs link to build details - URL encoding handles all job label formats ## Testing - Test jobs list search functionality - Verify individual job pages load correctly - Validate metrics calculations against known data - Test performance trend accuracy - Check recent runs links and data - Validate URL encoding with complex job labels - Test with jobs that have no runs yet