Skip to content

Commit

Permalink
Update status widget to use incident.io (#1038)
Browse files Browse the repository at this point in the history
  • Loading branch information
djfarrelly authored Jan 9, 2025
1 parent 572875b commit 038d8af
Showing 1 changed file with 65 additions and 30 deletions.
95 changes: 65 additions & 30 deletions shared/StatusWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,98 @@
"use client";
import { useState, useEffect } from "react";

type Indicator = "none" | "minor" | "major" | "critical";
type StatusPageStatusResponse = {
page: {
type Impact = "partial_outage" | "degraded_performance" | "full_outage";
type Indicator = Impact | "none" | "maintenance";
type StatusEvent = {
id: string;
name: string;
url: string;
last_update_at: string; // ISO-8601
last_update_message: string;
affected_components: {
id: string;
name: string;
url: string;
updated_at: string;
};
status: {
description: string;
indicator: Indicator;
};
group_name?: string;
}[];
};
type Incident = StatusEvent & {
status: "identified" | "investigating" | "monitoring";
current_worst_impact: Impact;
};
type MaintenanceInProgressEvent = StatusEvent & {
status: "maintenance_in_progress";
started_at: string; // ISO-8601
scheduled_end_at: string; // ISO-8601
};
type MaintenanceScheduledEvent = StatusEvent & {
status: "maintenance_scheduled";
starts_at: string; // ISO-8601
ends_at: string; // ISO-8601
};

type StatusPageSummaryResponse = {
page_title: string;
page_url: string;
ongoing_incidents: Incident[];
in_progress_maintenances: MaintenanceInProgressEvent[];
scheduled_maintenances: MaintenanceScheduledEvent[];
};

type Status = {
url: string;
description: string;
indicator: Indicator;
impact: Indicator;
updated_at: string;
};

const STATUS_PAGE_URL = "http://status.inngest.com"; // Not https
const impactMessage: { [K in Indicator]: string } = {
none: "All systems operational",
degraded_performance: "Degraded performance",
partial_outage: "Partial system outage",
full_outage: "Major system outage",
maintenance: "Maintenance in progress",
};
// We use hex colors b/c tailwind only includes what is initially rendered
const statusColor: { [K in Indicator]: string } = {
none: "rgba(var(--color-matcha-500))",
degraded_performance: "rgb(var(--color-honey-300))",
maintenance: "rgb(var(--color-honey-300))",
partial_outage: "rgb(var(--color-honey-500))",
full_outage: "rgb(var(--color-ruby-500))",
};

const fetchStatus = async (): Promise<StatusPageStatusResponse> => {
return await fetch("https://inngest.statuspage.io/api/v2/status.json").then(
(r) => r.json()
const STATUS_PAGE_URL = "https://status.inngest.com";

const fetchStatus = async (): Promise<StatusPageSummaryResponse> => {
return await fetch("https://status.inngest.com/api/v1/summary").then((r) =>
r.json()
);
};

const useStatus = (): Status => {
const [status, setStatus] = useState<Status>({
url: STATUS_PAGE_URL,
description: "Fetching status...",
indicator: "none",
impact: "none",
updated_at: "",
});
useEffect(() => {
(async function () {
try {
const res = await fetchStatus();
// Grab first incident
const incident = res.ongoing_incidents?.[0];
const impact = incident?.current_worst_impact || "none";
setStatus({
...res.status,
updated_at: res.page.updated_at,
url: res.page.url,
impact,
description: impactMessage[impact],
updated_at: incident?.last_update_at || new Date().toString(),
url: incident?.url || STATUS_PAGE_URL,
});
} catch (e) {
setStatus({
description: "Status page",
indicator: "none",
impact: "none",
updated_at: "",
url: STATUS_PAGE_URL,
});
Expand All @@ -59,21 +102,13 @@ const useStatus = (): Status => {
return status;
};

// We use hex colors b/c tailwind only includes what is initially rendered
const statusColor: { [K in Indicator]: string } = {
none: "#22c55e", // green-500
minor: "#fde047", // yellow-300
major: "#f97316", // orange-500
critical: "#dc2626", // red-600
};

export function StatusIcon({ className = "" }: { className?: string }) {
const status = useStatus();
return (
<span className={`${className} inline-flex items-center justify-center`}>
<span
className={`inline-flex m-auto w-2 h-2 rounded-full`}
style={{ backgroundColor: statusColor[status.indicator] }}
style={{ backgroundColor: statusColor[status.impact] }}
title={`${status.description} - Status updated at ${status.updated_at}`}
></span>
</span>
Expand All @@ -96,7 +131,7 @@ export default function StatusWidget({
>
<span
className={`inline-flex w-2 h-2 mr-2 rounded-full`}
style={{ backgroundColor: statusColor[status.indicator] }}
style={{ backgroundColor: statusColor[status.impact] }}
></span>
{status.description}
</a>
Expand Down

0 comments on commit 038d8af

Please sign in to comment.