@@ -5,13 +5,16 @@ import { useState, useEffect, useCallback } from 'react'
55import { pipe } from '@/lib/tinybird'
66import { Card , CardContent , CardHeader , CardTitle } from '@/components/ui/card'
77import { formatDuration , formatNumber , formatPercentage } from '@/lib/utils'
8- import Overview from '@/components/overview-chart'
8+ import Overview from '@/components/tools/pagerduty/ overview-chart'
99import BarList from '@/components/bar-list'
1010import { DateRangePicker , DateRange } from '@/components/ui/date-range-picker'
1111import { startOfDay , endOfDay , format } from 'date-fns'
1212import MetricCard from '@/components/metric-card'
13- import IncidentCategoriesTable from "@/components/incident-categories-table"
13+ import IncidentCategoriesTable from "@/components/tools/pagerduty/ incident-categories-table"
1414import { Filter } from './filters'
15+ import InterruptionsChart from "@/components/tools/pagerduty/interruptions-chart"
16+ import ResponseEffortChart from "@/components/tools/pagerduty/response-effort-chart"
17+ import SleepInterruptions from "@/components/tools/pagerduty/sleep-interruptions"
1518
1619interface IncidentType {
1720 title : string
@@ -22,6 +25,14 @@ interface IncidentType {
2225 example_title : string
2326}
2427
28+ interface Responder {
29+ html_url : string ;
30+ id : string ;
31+ self : string ;
32+ summary : string ;
33+ type : string ;
34+ }
35+
2536export default function PagerDutyDashboard ( ) {
2637 const [ token ] = useQueryState ( 'token' )
2738 const [ dateRange , setDateRange ] = useState < DateRange > ( {
@@ -52,9 +63,10 @@ export default function PagerDutyDashboard() {
5263 high_urgency_rate : number
5364 } > > ( [ ] )
5465 const [ responders , setResponders ] = useState < Array < {
55- responder : string
56- responses : number
57- avg_response_time : number
66+ responder : Responder [ ] ;
67+ responses : number ;
68+ acknowledgements : number ;
69+ avg_response_time : number ;
5870 } > > ( [ ] )
5971 const [ statusDistribution , setStatusDistribution ] = useState < Array < {
6072 event_type : string
@@ -65,6 +77,32 @@ export default function PagerDutyDashboard() {
6577 const pageSize = 10
6678 const [ incidentTypes , setIncidentTypes ] = useState < IncidentType [ ] > ( [ ] )
6779 const [ selectedService , setSelectedService ] = useState < string > ( )
80+ const [ interruptions , setInterruptions ] = useState < Array < {
81+ day : string
82+ interruptions : number
83+ day_type : 'business' | 'off'
84+ } > > ( [ ] )
85+ const [ responseEffort , setResponseEffort ] = useState < Array < {
86+ responder : Array < {
87+ html_url : string
88+ id : string
89+ self : string
90+ summary : string
91+ type : string
92+ } >
93+ hours : number
94+ } > > ( [ ] )
95+ const [ sleepInterruptions , setSleepInterruptions ] = useState < Array < {
96+ responder : Array < {
97+ html_url : string
98+ id : string
99+ self : string
100+ summary : string
101+ type : string
102+ } >
103+ interruptions : number
104+ avg_response_time : number
105+ } > > ( [ ] )
68106
69107 const fetchIncidentTypes = useCallback ( async ( newPage : number ) => {
70108 if ( ! token ) return
@@ -116,15 +154,21 @@ export default function PagerDutyDashboard() {
116154 statusDistributionData ,
117155 resolutionTimesData ,
118156 serviceDistributionData ,
119- incidentTypesData
157+ incidentTypesData ,
158+ interruptionsData ,
159+ responseEffortData ,
160+ sleepInterruptionsData
120161 ] = await Promise . all ( [
121162 pipe ( token , 'pagerduty_incident_metrics' , baseParams ) ,
122163 pipe ( token , 'pagerduty_incidents_over_time' , baseParams ) ,
123164 pipe ( token , 'pagerduty_responders' , baseParams ) ,
124165 pipe ( token , 'pagerduty_status_distribution' , baseParams ) ,
125166 pipe ( token , 'pagerduty_resolution_times' , baseParams ) ,
126167 pipe ( token , 'pagerduty_service_distribution' , baseParams ) ,
127- pipe ( token , 'pagerduty_incident_types' , baseParams )
168+ pipe ( token , 'pagerduty_incident_types' , baseParams ) ,
169+ pipe ( token , 'pagerduty_interruptions' , baseParams ) ,
170+ pipe ( token , 'pagerduty_response_effort' , baseParams ) ,
171+ pipe ( token , 'pagerduty_sleep_interruptions' , baseParams )
128172 ] )
129173
130174 setMetrics ( ( incidentMetrics ?. data ?. [ 0 ] || {
@@ -143,9 +187,10 @@ export default function PagerDutyDashboard() {
143187 escalated : number
144188 } > )
145189 setResponders ( respondersData . data as Array < {
146- responder : string
147- responses : number
148- avg_response_time : number
190+ responder : Responder [ ] ;
191+ responses : number ;
192+ acknowledgements : number ;
193+ avg_response_time : number ;
149194 } > )
150195 setStatusDistribution ( statusDistributionData . data as Array < {
151196 event_type : string
@@ -166,6 +211,9 @@ export default function PagerDutyDashboard() {
166211 high_urgency_rate : number
167212 } > )
168213 setIncidentTypes ( incidentTypesData . data as IncidentType [ ] )
214+ setInterruptions ( interruptionsData . data )
215+ setResponseEffort ( responseEffortData . data )
216+ setSleepInterruptions ( sleepInterruptionsData . data )
169217
170218 } catch ( error ) {
171219 console . error ( 'Failed to fetch metrics:' , error )
@@ -270,9 +318,9 @@ export default function PagerDutyDashboard() {
270318 data = { incidentsOverTime }
271319 categories = { [ 'triggered' , 'resolved' , 'escalated' ] }
272320 colors = { {
273- 'triggered' : '#dc2626 ' , // Red-600
274- 'resolved' : '#16a34a ' , // Green-600
275- 'escalated' : '#d97706 ' // Amber-600
321+ 'triggered' : 'hsl(var(--primary)) ' , // Red-600
322+ 'resolved' : '#93c5fd ' , // Green-600
323+ 'escalated' : '#6b7280 ' // Amber-600
276324 } }
277325 index = "hour"
278326 valueKey = "count"
@@ -282,31 +330,65 @@ export default function PagerDutyDashboard() {
282330 </ Card >
283331
284332 { /* Response Analysis */ }
285- < div className = "grid gap-4 grid-cols-3 " >
333+ < div className = "grid gap-4 grid-cols-2 " >
286334 < Card >
287335 < CardHeader >
288- < CardTitle > Response Team Activity</ CardTitle >
336+ < CardTitle > Oncall Team Activity</ CardTitle >
289337 </ CardHeader >
290338 < CardContent className = "max-h-[400px] overflow-auto" >
291339 < BarList
292- data = { ( responders || [ ] ) . map ( ( item ) => ( {
293- name : item . responder ,
294- value : item . responses ,
295- extra : `${ formatDuration ( item . avg_response_time ) } avg response time` ,
296- } ) ) }
340+ data = { responders
341+ . reduce ( ( acc , item ) => {
342+ if ( item . responder . length > 1 ) return acc ;
343+
344+ const name = item . responder [ 0 ] ?. summary || 'Unknown'
345+ const existing = acc . find ( x => x . name === name )
346+ if ( existing ) {
347+ existing . value += item . responses
348+ existing . acknowledgements += item . acknowledgements
349+ existing . avgTime = ( existing . avgTime * existing . count + item . avg_response_time ) / ( existing . count + 1 )
350+ existing . count ++
351+ } else {
352+ acc . push ( {
353+ name,
354+ value : item . responses ,
355+ acknowledgements : item . acknowledgements ,
356+ avgTime : item . avg_response_time ,
357+ count : 1
358+ } )
359+ }
360+ return acc
361+ } , [ ] as Array < {
362+ name : string
363+ value : number
364+ acknowledgements : number
365+ avgTime : number
366+ count : number
367+ } > )
368+ . map ( item => ( {
369+ name : item . name ,
370+ value : item . value ,
371+ extra : `${ item . acknowledgements } acks • ${ formatDuration ( item . avgTime ) } avg response time`
372+ } ) )
373+ }
297374 />
298375 </ CardContent >
299376 </ Card >
300- < div className = "col-span-2" >
301- < IncidentCategoriesTable
302- data = { incidentTypes || [ ] }
303- page = { page }
304- onPageChange = { handlePageChange }
305- pageSize = { pageSize }
306- isLoading = { isTableLoading }
307- />
308- </ div >
377+ < ResponseEffortChart data = { responseEffort } />
309378 </ div >
379+
380+ < div className = "grid gap-4 grid-cols-2" >
381+ < InterruptionsChart data = { interruptions } />
382+ < SleepInterruptions data = { sleepInterruptions } />
383+ </ div >
384+
385+ < IncidentCategoriesTable
386+ data = { incidentTypes || [ ] }
387+ page = { page }
388+ onPageChange = { handlePageChange }
389+ pageSize = { pageSize }
390+ isLoading = { isTableLoading }
391+ />
310392 </ div >
311393 )
312394}
0 commit comments