Skip to content

Commit 25a5a8b

Browse files
cursoragentdobrac
andcommitted
use new incident io page
Co-authored-by: Jakub Dobry <dobrac@users.noreply.github.com>
1 parent 8307ce6 commit 25a5a8b

5 files changed

Lines changed: 84 additions & 75 deletions

File tree

.env.example

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
6868
# NEXT_PUBLIC_INCLUDE_REPORT_ISSUE=0
6969

7070
### Enable dashboard status indicator feature: set to 1 to enable
71-
### When enabled, the E2B status is read from the incident.io widget API
71+
### When enabled, the E2B status is read from the incident.io summary API
7272
# NEXT_PUBLIC_INCLUDE_STATUS_INDICATOR=0
73-
# NEXT_PUBLIC_STATUS_PAGE_URL=https://status.e2b.dev
74-
# NEXT_PUBLIC_STATUS_PAGE_WIDGET_URL=https://status.e2b.dev/api/widget
73+
# NEXT_PUBLIC_STATUS_PAGE_URL=https://statuspage.incident.io/e2b-service
74+
# NEXT_PUBLIC_STATUS_PAGE_SUMMARY_URL=https://statuspage.incident.io/e2b-service/api/v2/summary.json
7575

7676
### Set to 1 to use mock data
7777
# NEXT_PUBLIC_MOCK_DATA=0

src/features/dashboard/layouts/status-indicator.server.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import { l } from '@/core/shared/clients/logger/logger'
66
import { LiveDot } from '@/ui/live'
77
import {
88
type AggregateState,
9-
getStatusPageStateFromWidget,
9+
getStatusPageStateFromSummary,
10+
getStatusPageSummaryUrl,
1011
getStatusPageUrl,
11-
getStatusPageWidgetUrl,
12-
type IncidentIOWidgetResponse,
12+
type IncidentIOStatusPageSummaryResponse,
1313
} from './status-indicator'
1414

1515
export const STATUS_PAGE_URL = getStatusPageUrl()
16-
const STATUS_PAGE_WIDGET_URL = getStatusPageWidgetUrl(STATUS_PAGE_URL)
16+
const STATUS_PAGE_SUMMARY_URL = getStatusPageSummaryUrl(STATUS_PAGE_URL)
1717
const STATUS_PAGE_FETCH_TIMEOUT_MS = 5_000
1818
const STATUS_PAGE_CACHE_SECONDS = 300
1919

@@ -67,7 +67,7 @@ async function getStatusPageState(): Promise<AggregateState> {
6767
})
6868

6969
try {
70-
const response = await fetch(STATUS_PAGE_WIDGET_URL, {
70+
const response = await fetch(STATUS_PAGE_SUMMARY_URL, {
7171
cache: 'force-cache',
7272
next: { revalidate: STATUS_PAGE_CACHE_SECONDS },
7373
signal: AbortSignal.timeout(STATUS_PAGE_FETCH_TIMEOUT_MS),
@@ -85,8 +85,8 @@ async function getStatusPageState(): Promise<AggregateState> {
8585
return 'unknown'
8686
}
8787

88-
const data = (await response.json()) as IncidentIOWidgetResponse
89-
return getStatusPageStateFromWidget(data)
88+
const data = (await response.json()) as IncidentIOStatusPageSummaryResponse
89+
return getStatusPageStateFromSummary(data)
9090
} catch {
9191
return 'unknown'
9292
}

src/features/dashboard/layouts/status-indicator.ts

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,62 +5,77 @@ export type AggregateState =
55
| 'maintenance'
66
| 'unknown'
77

8-
export interface IncidentIOWidgetEvent {
9-
affected_components?: Array<{
8+
export interface IncidentIOStatusPageSummaryResponse {
9+
status?: {
10+
indicator?: string
11+
}
12+
components?: Array<{
13+
status?: string
14+
}>
15+
scheduled_maintenances?: Array<{
1016
status?: string
1117
}>
12-
}
13-
14-
export interface IncidentIOWidgetResponse {
15-
ongoing_incidents?: IncidentIOWidgetEvent[]
16-
in_progress_maintenances?: IncidentIOWidgetEvent[]
17-
scheduled_maintenances?: IncidentIOWidgetEvent[]
1818
}
1919

2020
export function getStatusPageUrl() {
21-
return (process.env.NEXT_PUBLIC_STATUS_PAGE_URL ?? 'https://status.e2b.dev')
21+
return (
22+
process.env.NEXT_PUBLIC_STATUS_PAGE_URL ??
23+
'https://statuspage.incident.io/e2b-service'
24+
)
2225
.trim()
2326
.replace(/\/+$/, '')
2427
}
2528

26-
export function getStatusPageWidgetUrl(statusPageUrl: string) {
27-
const configuredWidgetUrl =
28-
process.env.NEXT_PUBLIC_STATUS_PAGE_WIDGET_URL?.trim()
29+
export function getStatusPageSummaryUrl(statusPageUrl: string) {
30+
const configuredSummaryUrl =
31+
process.env.NEXT_PUBLIC_STATUS_PAGE_SUMMARY_URL?.trim()
2932

30-
if (configuredWidgetUrl) return configuredWidgetUrl
33+
if (configuredSummaryUrl) return configuredSummaryUrl
3134

32-
return `${statusPageUrl}/api/widget`
35+
return `${statusPageUrl}/api/v2/summary.json`
3336
}
3437

35-
function hasEvents(events: IncidentIOWidgetEvent[] | undefined) {
36-
return Array.isArray(events) && events.length > 0
38+
function stateFromIndicator(indicator: string | undefined) {
39+
if (indicator === 'none') return 'operational'
40+
if (indicator === 'minor') return 'degraded'
41+
if (indicator === 'major') return 'degraded'
42+
if (indicator === 'critical') return 'downtime'
43+
if (indicator === 'maintenance') return 'maintenance'
44+
45+
return undefined
3746
}
3847

3948
function getWorstComponentState(
40-
events: IncidentIOWidgetEvent[] | undefined
49+
components: IncidentIOStatusPageSummaryResponse['components']
4150
): AggregateState | undefined {
4251
const componentStatuses =
43-
events?.flatMap(
44-
(event) =>
45-
event.affected_components?.map((component) => component.status) ?? []
46-
) ?? []
52+
components?.map((component) => component.status) ?? []
4753

48-
if (componentStatuses.includes('full_outage')) return 'downtime'
54+
if (componentStatuses.includes('major_outage')) return 'downtime'
4955
if (componentStatuses.includes('partial_outage')) return 'degraded'
5056
if (componentStatuses.includes('degraded_performance')) return 'degraded'
5157
if (componentStatuses.includes('under_maintenance')) return 'maintenance'
5258

5359
return undefined
5460
}
5561

56-
export function getStatusPageStateFromWidget(
57-
data: IncidentIOWidgetResponse
58-
): AggregateState {
59-
if (hasEvents(data.ongoing_incidents)) {
60-
return getWorstComponentState(data.ongoing_incidents) ?? 'degraded'
61-
}
62+
function hasMaintenanceInProgress(
63+
maintenances: IncidentIOStatusPageSummaryResponse['scheduled_maintenances']
64+
) {
65+
return maintenances?.some(
66+
(maintenance) => maintenance.status === 'maintenance_in_progress'
67+
)
68+
}
6269

63-
if (hasEvents(data.in_progress_maintenances)) return 'maintenance'
70+
export function getStatusPageStateFromSummary(
71+
data: IncidentIOStatusPageSummaryResponse
72+
): AggregateState {
73+
if (hasMaintenanceInProgress(data.scheduled_maintenances))
74+
return 'maintenance'
6475

65-
return 'operational'
76+
return (
77+
stateFromIndicator(data.status?.indicator) ??
78+
getWorstComponentState(data.components) ??
79+
'unknown'
80+
)
6681
}

src/lib/env.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export const clientSchema = z.object({
5656
NEXT_PUBLIC_INCLUDE_REPORT_ISSUE: z.string().optional(),
5757
NEXT_PUBLIC_INCLUDE_STATUS_INDICATOR: z.string().optional(),
5858
NEXT_PUBLIC_STATUS_PAGE_URL: z.url().optional(),
59-
NEXT_PUBLIC_STATUS_PAGE_WIDGET_URL: z.url().optional(),
59+
NEXT_PUBLIC_STATUS_PAGE_SUMMARY_URL: z.url().optional(),
6060
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().optional(),
6161
NEXT_PUBLIC_SCAN: z.string().optional(),
6262
NEXT_PUBLIC_MOCK_DATA: z.string().optional(),

tests/unit/status-indicator.test.ts

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,55 @@
11
import { describe, expect, it } from 'vitest'
2-
import { getStatusPageStateFromWidget } from '@/features/dashboard/layouts/status-indicator'
2+
import { getStatusPageStateFromSummary } from '@/features/dashboard/layouts/status-indicator'
33

44
describe('status-indicator', () => {
5-
it('should report operational when widget has no active events', () => {
5+
it('should report operational for summary indicator none', () => {
66
expect(
7-
getStatusPageStateFromWidget({
8-
ongoing_incidents: [],
9-
in_progress_maintenances: [],
10-
scheduled_maintenances: [
11-
{
12-
affected_components: [{ status: 'under_maintenance' }],
13-
},
14-
],
7+
getStatusPageStateFromSummary({
8+
status: {
9+
indicator: 'none',
10+
},
1511
})
1612
).toBe('operational')
1713
})
1814

19-
it('should report maintenance for in-progress maintenances', () => {
15+
it('should report maintenance for in-progress maintenance', () => {
2016
expect(
21-
getStatusPageStateFromWidget({
22-
ongoing_incidents: [],
23-
in_progress_maintenances: [{}],
17+
getStatusPageStateFromSummary({
18+
scheduled_maintenances: [
19+
{
20+
status: 'maintenance_in_progress',
21+
},
22+
],
2423
})
2524
).toBe('maintenance')
2625
})
2726

28-
it('should report downtime for full outage incidents', () => {
27+
it('should report downtime for critical summary indicator', () => {
2928
expect(
30-
getStatusPageStateFromWidget({
31-
ongoing_incidents: [
32-
{
33-
affected_components: [
34-
{ status: 'degraded_performance' },
35-
{ status: 'full_outage' },
36-
],
37-
},
38-
],
29+
getStatusPageStateFromSummary({
30+
status: {
31+
indicator: 'critical',
32+
},
3933
})
4034
).toBe('downtime')
4135
})
4236

43-
it('should report degraded for partial outage incidents', () => {
37+
it('should report degraded for major summary indicator', () => {
4438
expect(
45-
getStatusPageStateFromWidget({
46-
ongoing_incidents: [
47-
{
48-
affected_components: [{ status: 'partial_outage' }],
49-
},
50-
],
39+
getStatusPageStateFromSummary({
40+
status: {
41+
indicator: 'major',
42+
},
5143
})
5244
).toBe('degraded')
5345
})
5446

55-
it('should report degraded when incident has no component status', () => {
47+
it('should report degraded for minor summary indicator', () => {
5648
expect(
57-
getStatusPageStateFromWidget({
58-
ongoing_incidents: [{}],
49+
getStatusPageStateFromSummary({
50+
status: {
51+
indicator: 'minor',
52+
},
5953
})
6054
).toBe('degraded')
6155
})

0 commit comments

Comments
 (0)