-
-
Notifications
You must be signed in to change notification settings - Fork 316
Expand file tree
/
Copy pathrepos_and_bots.jsx
More file actions
128 lines (121 loc) · 3.86 KB
/
repos_and_bots.jsx
File metadata and controls
128 lines (121 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { urls } from "@site/src/constants";
import { React, useEffect, useState } from "react";
import styles from "./styles.module.css";
// If CDN status is updated in this window (20 minutes), status is operational.
const OPERATIONAL_WINDOW = 20 * 60 * 1000;
// If CDN status is updated in this window (40 minutes), status is degraded.
const DEGRADED_WINDOW = 40 * 60 * 1000;
export default function ReposAndBots({ onLoad, style }) {
useEffect(() => onLoad?.(), []);
return (
<div className="card margin-top--xs" style={style}>
<div className="card__header">
<h3>Repos and Bots</h3>
</div>
<div className="card__body">
<table style={{ fontSize: "small" }}>
<tbody>
<CDNStatus />
<WebServices />
{urls.repos.badges.map(({ name, ...badge }, index) =>
<Badge key={index} {...badge}>{name}</Badge>
)}
</tbody>
</table>
</div>
</div>
);
}
function Badge({ children, link, badge, badgeLink }) {
return (
<tr>
<td>
<a href={link} style={{ display: "inline-block", minWidth: "100%" }}>
{children}
</a>
</td>
<td style={{ textAlign: "right" }}>
<Image alt={`${children} status`} link={badgeLink}>{badge}</Image>
</td>
</tr>
);
}
function Image({ alt, link, children }) {
const [error, setState] = useState(false);
const onError = () => setState(true);
if (error) return (<>No status available</>);
const image = (
<img alt={alt}
style={{ verticalAlign: "bottom" }} onError={onError} src={children} />
);
return link ? <a href={link}>{image}</a> : image;
}
function CDNStatus() {
const [{ minutes, status }, setState] = useState({ minutes: "…", status: "…" });
useEffect(() => {
void (async () => {
try {
const response = await (await fetch(`${urls.repos.cdn.api}?bustcache=${Date.now()}`)).json();
const updated = new Date(response.timestamp.iso8601).getTime();
const delta = (new Date()).getTime() - updated;
const status = delta < OPERATIONAL_WINDOW ? "operational" :
delta < DEGRADED_WINDOW ? "degraded" : "major outage";
setState({ minutes: Math.round(delta / 1000 / 60), status });
} catch (error) {
console.warn(`error loading cdn cloning status`, error);
}
})();
}, []);
return (
<tr>
<td>
<a href={urls.repos.cdn.link}
style={{ display: "inline-block", minWidth: "100%" }}>
CDN cloning
</a>
</td>
<td>
<div style={{ display: "block", textAlign: "center" }} className={
"badge" +
(status === "operational" ? " badge--success" : "") +
(status === "degraded" ? " badge--warning" : "") +
(status === "major outage" ? " badge--danger" : "")
}>{status}</div>
<div style={{ fontStyle: "italic", textAlign: "right" }}>
(last updated {minutes} min ago)
</div>
</td>
</tr>
);
}
function WebServices() {
const [status, setState] = useState("");
useEffect(() => {
void (async () => {
try {
const { status } = await (await fetch(urls.repos.services.api)).json();
setState(status);
} catch (error) {
console.warn(`error loading web services status`, error);
}
})();
}, []);
return (
<tr>
<td>
<a href={urls.repos.services.link}
style={{ display: "inline-block", minWidth: "100%" }}>
conda-forge-webservices
</a>
</td>
<td>
<div style={{ display: "block", textAlign: "center" }} className={
"badge" +
(status === "operational" ? " badge--success" : "") +
(status === "degraded" ? " badge--warning" : "") +
(status === "major outage" ? " badge--danger" : "")
}>{status}</div>
</td>
</tr>
);
}