Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions components/StatusPage/StatusPage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
title: "StatusPage"
description: "A widget that displays the operational status of a service."
author: "@trishaprile"
version: "1.0.0"
---

import { useEffect, useState } from 'react';

export const StatusPage = ({ title, url}) => {
const [status, setStatus] = useState(null);
const [indicator, setIndicator] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
let isMounted = true;

if (url) {
const fetchStatus = async () => {
try {
const res = await fetch(`${url.replace(/\/$/, '')}/api/v2/status.json`);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was traveling on Friday so I didn't get a chance to ask then, but is this meant to only show ReadMe statuses?
If this is meant to be dynamic for the customer I have a couple of questions:

  1. Are we requiring the customer to have an endpoint that ends in /api/v2/status.json? It seems strange that we would force them into a specific endpoint form instead of just taking the url and using it. If we aren't forcing them to have an endpoint ending in /api/v2/status.json then I don't think this will work. It will fail because we are modifying the url by appending /api/v2/status.json to the end of it.

E.g. if I have a status endpoint http://www.mycompany.com/service1/status, this component will modify it and make it http://www.mycompany.com/service1/status_/api/v2/status.json_.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component should only work for sites that use Atlassian's Status Page service. It seems like a lot of companies do, including ReadMe. So adding /api/v2/status.json to the URL should work in these cases, for example https://www.readmestatus.com/api/v2/status.json, https://www.githubstatus.com/api/v2/status.json, and https://atlas-status.mit.edu/api/v2/status.json. Let me know if you want me to be more specific in the Overview section of the README!

Copy link

@mosesj-readme mosesj-readme Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope that answers my question and the one below.

I would mention that in the readme.md page and also that the url shouldn't end in /api/v2/status.json. The component assumes the passed in url doesn't end in /api/v2/status.json but a customer might put the full url, eg. https://www.myservice.com/api/v2/status.json which the component will change to https://www.myservice.com/api/v2/status.json/api/v2/status.json. The component should only add the suffix if it isn't present or we should make the documentation clear that the passed in url should not end in /api/v2/status.json.

Copy link
Member Author

@trishaprile trishaprile Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha, I'll update the documentation! ideally the user should set the url as their actual status page site and not the .json version. the open link in new tab icon button takes in the url

if (!res.ok) throw new Error(`Failed to fetch status: ${res.status}`);
const data = await res.json();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't seen anywhere that describes what the response form needs to be. It might be good if the readme.md showed what the endpoint's return shape is so it's clear to anyone using this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response from a Statuspage endpoint should include status, indicator, and description

{"page":{"id":"nz3r09cr7dk1","name":"ReadMe","url":"https://www.readmestatus.com","time_zone":"America/Los_Angeles","updated_at":"2025-08-25T07:16:06.459-07:00"},"status":{"indicator":"none","description":"All Systems Operational"}}

if (!isMounted) return;

setStatus(data.status.description);
setIndicator(data.status.indicator);
} catch (err) {
if (!isMounted) return;

setError('Unable to fetch status');
}
};
fetchStatus();
}

return () => {
isMounted = false;
};
}, [url]);

return (
<div className="relative max-w-sm p-5 rounded-lg shadow-sm border border-gray-200 dark:border-gray-400">
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className="absolute top-3 right-3 text-gray-400 hover:text-gray-600"
aria-label="View full status page"
>
<i className="fa fa-arrow-up-right-from-square" />
</a>
<h3 className="mt-0! mb-2 text-gray-600! dark:text-white!">{title}</h3>
{error ? (
<div className="flex items-center space-x-2 text-red-600">
<span className="w-3 h-3 rounded-full bg-red-500" />
<span>{error}</span>
</div>
) : !status ? (
<div className="flex items-center space-x-2">
<span className="w-3 h-3 rounded-full bg-gray-400 animate-pulse" />
<span>Loading status…</span>
</div>
) : (
<div className="flex items-center space-x-2">
<span
className={`fa-duotone fa-solid ${
indicator === 'none'
? 'fa-circle-check text-green-500'
: indicator === 'minor'
? 'fa-circle-exclamation text-yellow-500'
: indicator === 'major'
? 'fa-circle-exclamation text-orange-500'
: indicator === 'critical'
? 'fa-circle-x text-red-500'
: 'fa-circle text-gray-500'
}`}
/>
<span className="text-sm font-medium">{status}</span>
</div>
)}
</div>
);
};

<StatusPage title="ReadMe Status" url="https://www.readmestatus.com" />
20 changes: 20 additions & 0 deletions components/StatusPage/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# StatusPage

## Overview

A `<StatusPage />` can be used to embed the current operational status, health, or uptime of a service or system. It fetches live status information from a public [Statuspage](https://www.atlassian.com/software/statuspage) endpoint (e.g. https://www.githubstatus.com) and displays the status indicator and description.

<img src="status-page.png" width="800" />

## Usage

```mdx
<StatusPage title="ReadMe Status" url="https://www.readmestatus.com" />
```

## Props

| Prop | Type | Description |
| ------- | ------ | --------------------------------- |
| `title` | string | The heading displayed at the top. |
| `url` | string | The URL of the status page. |
Binary file added components/StatusPage/status-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.