From 90eca83e80ef55147291081ca5f66df6c9054144 Mon Sep 17 00:00:00 2001 From: John Goh Date: Mon, 29 Nov 2021 15:22:37 +0800 Subject: [PATCH] fix: refactor CanaryPopup-related files --- .../Canary/CanaryPopup/CheckDetails.js | 151 ++++++++ .../Canary/CanaryPopup/CheckStat.js | 20 + .../Canary/CanaryPopup/CheckTitle.js | 52 +++ .../Canary/CanaryPopup/DetailField.js | 14 + .../Canary/CanaryPopup/StatusHistory.js | 44 +++ src/components/Canary/CanaryPopup/index.js | 345 ------------------ src/components/Canary/CanaryPopup/tabs.js | 69 ++++ src/components/Canary/CanaryPopup/utils.js | 7 + src/components/Canary/index.js | 3 +- 9 files changed, 359 insertions(+), 346 deletions(-) create mode 100644 src/components/Canary/CanaryPopup/CheckDetails.js create mode 100644 src/components/Canary/CanaryPopup/CheckStat.js create mode 100644 src/components/Canary/CanaryPopup/CheckTitle.js create mode 100644 src/components/Canary/CanaryPopup/DetailField.js create mode 100644 src/components/Canary/CanaryPopup/StatusHistory.js delete mode 100644 src/components/Canary/CanaryPopup/index.js create mode 100644 src/components/Canary/CanaryPopup/tabs.js create mode 100644 src/components/Canary/CanaryPopup/utils.js diff --git a/src/components/Canary/CanaryPopup/CheckDetails.js b/src/components/Canary/CanaryPopup/CheckDetails.js new file mode 100644 index 000000000..eaf59e176 --- /dev/null +++ b/src/components/Canary/CanaryPopup/CheckDetails.js @@ -0,0 +1,151 @@ +import React from "react"; +import { usePrevious } from "../../../utils/hooks"; +import { Badge } from "../../Badge"; +import { toFormattedDuration } from "../renderers"; +import { AccordionBox } from "../../AccordionBox"; +import { + capitalizeFirstLetter, + toFixedIfNecessary +} from "../../../utils/common"; +import styles from "../index.module.css"; +import { PopupTabs } from "./tabs"; +import { CheckStat } from "./CheckStat"; +import { getUptimePercentage } from "./utils"; +import { StatusHistory } from "./StatusHistory"; +import { DetailField } from "./DetailField"; + +export function CheckDetails({ check, ...rest }) { + const prevCheck = usePrevious(check); + const validCheck = check || prevCheck; + + const [val, unit] = toFormattedDuration(validCheck?.latency?.rolling1h); + const latencyValue = validCheck?.latency?.rolling1h ? `${val}${unit}` : "-"; + const uptimeValue = toFixedIfNecessary(getUptimePercentage(validCheck), 2); + const validUptime = + !Number.isNaN(validCheck?.uptime?.passed) && + !Number.isNaN(validCheck?.uptime?.failed); + const severityValue = validCheck?.severity || "-"; + const statusHistoryList = validCheck?.checkStatuses; + + const details = { + Name: + validCheck?.name || validCheck?.canaryName || validCheck?.endpoint || "-", + Type: validCheck?.type || "-", + Labels: ( + <> + {validCheck?.labels && + Object.entries(validCheck?.labels).map((entry) => { + const key = entry[0]; + return ; + })} + + ), + Owner: validCheck?.owner || "-", + Interval: validCheck?.interval || "-", + Location: validCheck?.location || "-", + Schedule: validCheck?.schedule || "-" + }; + + return ( +
+ {/* stats section */} +
+ + + {validCheck?.uptime?.passed} passed + + + {validCheck?.uptime?.failed} failed + +
+ ) + } + /> + + +
+ {/* chart section */} +
+
+ Health overview + (time dropdown) +
+
+
+ + {statusHistoryList && statusHistoryList.length > 0 ? ( + + ) : ( +
+ No status history available +
+ )} +
+ ), + class: "flex flex-col overflow-y-hidden border-b border-gray-300" + }, + checkDetails: { + label: "Check details", + content: ( +
+ + {Object.entries(details).map(([label, value]) => ( + + ))} +
+ } + /> + + ), + class: `flex flex-col overflow-y-auto border border-gray-300 ${styles.appleScrollbar}` + } + }} + /> + + ); +} diff --git a/src/components/Canary/CanaryPopup/CheckStat.js b/src/components/Canary/CanaryPopup/CheckStat.js new file mode 100644 index 000000000..d400b87f1 --- /dev/null +++ b/src/components/Canary/CanaryPopup/CheckStat.js @@ -0,0 +1,20 @@ +import React from "react"; + +export function CheckStat({ + title, + value, + append, + containerClass, + className, + ...rest +}) { + return ( +
+
{title}
+
+ {value} + {append} +
+
+ ); +} diff --git a/src/components/Canary/CanaryPopup/CheckTitle.js b/src/components/Canary/CanaryPopup/CheckTitle.js new file mode 100644 index 000000000..a01f5b607 --- /dev/null +++ b/src/components/Canary/CanaryPopup/CheckTitle.js @@ -0,0 +1,52 @@ +import React from "react"; +import { usePrevious } from "../../../utils/hooks"; +import { Badge } from "../../Badge"; +import { Icon } from "../../Icon"; + +export function CheckTitle({ check, className, ...rest }) { + const prevCheck = usePrevious(check); + const validCheck = check || prevCheck; + + return ( +
+
+ +
+
+
+ + {validCheck?.name} + + + + +
+ {true && ( +
+ {validCheck?.endpoint} +
+ )} + + + +
+
+ ); +} diff --git a/src/components/Canary/CanaryPopup/DetailField.js b/src/components/Canary/CanaryPopup/DetailField.js new file mode 100644 index 000000000..f1c414485 --- /dev/null +++ b/src/components/Canary/CanaryPopup/DetailField.js @@ -0,0 +1,14 @@ +import React from "react"; + +export function DetailField({ label, value, className, ...rest }) { + return ( +
+
+ {label} +
+
+ {value} +
+
+ ); +} diff --git a/src/components/Canary/CanaryPopup/StatusHistory.js b/src/components/Canary/CanaryPopup/StatusHistory.js new file mode 100644 index 000000000..30783b1eb --- /dev/null +++ b/src/components/Canary/CanaryPopup/StatusHistory.js @@ -0,0 +1,44 @@ +import React from "react"; +import { format } from "timeago.js"; +import { CanaryStatus, Duration } from "../renderers"; +import { isEmpty } from "../utils"; +import { Table } from "../../Table"; + +export function StatusHistory({ check, sticky = "false" }) { + const statii = check + ? check.checkStatuses != null + ? check.checkStatuses + : [] + : []; + const data = []; + statii.forEach((status) => { + data.push({ + key: `${check.key}.${check.description}`, + age: format(`${status.time} UTC`), + message: ( + <> + {status.message}{" "} + {!isEmpty(status.error) && + status.error.split("\n").map((item) => ( + <> + {item} +
+ + ))} + + ), + duration: + }); + }); + + return ( + check && ( + + ) + ); +} diff --git a/src/components/Canary/CanaryPopup/index.js b/src/components/Canary/CanaryPopup/index.js deleted file mode 100644 index 3b4dc80b8..000000000 --- a/src/components/Canary/CanaryPopup/index.js +++ /dev/null @@ -1,345 +0,0 @@ -import React, { useState } from "react"; -import { format } from "timeago.js"; -import { usePrevious } from "../../../utils/hooks"; -import { Badge } from "../../Badge"; -import { Icon } from "../../Icon"; -import { CanaryStatus, Duration, toFormattedDuration } from "../renderers"; -import { AccordionBox } from "../../AccordionBox"; -import { Table } from "../../Table"; -import { isEmpty } from "../utils"; -import { - capitalizeFirstLetter, - toFixedIfNecessary -} from "../../../utils/common"; -import styles from "../index.module.css"; - -export function CheckTitle({ check, className, ...rest }) { - const prevCheck = usePrevious(check); - const validCheck = check || prevCheck; - - return ( -
-
- -
-
-
- - {validCheck?.name} - - - - -
- {true && ( -
- {validCheck?.endpoint} -
- )} - - - -
-
- ); -} - -export function CheckDetails({ check, ...rest }) { - const prevCheck = usePrevious(check); - const validCheck = check || prevCheck; - - const [val, unit] = toFormattedDuration(validCheck?.latency?.rolling1h); - const latencyValue = validCheck?.latency?.rolling1h ? `${val}${unit}` : "-"; - const uptimeValue = toFixedIfNecessary(getUptimePercentage(validCheck), 2); - const validUptime = - !Number.isNaN(validCheck?.uptime?.passed) && - !Number.isNaN(validCheck?.uptime?.failed); - const severityValue = validCheck?.severity || "-"; - const statusHistoryList = validCheck?.checkStatuses; - - const details = { - Name: - validCheck?.name || validCheck?.canaryName || validCheck?.endpoint || "-", - Type: validCheck?.type || "-", - Labels: ( - <> - {validCheck?.labels && - Object.entries(validCheck?.labels).map((entry) => { - const key = entry[0]; - return ; - })} - - ), - Owner: validCheck?.owner || "-", - Interval: validCheck?.interval || "-", - Location: validCheck?.location || "-", - Schedule: validCheck?.schedule || "-" - }; - - return ( -
- {/* stats section */} -
- - - {validCheck?.uptime?.passed} passed - - - {validCheck?.uptime?.failed} failed - -
- ) - } - /> - - -
- {/* chart section */} -
-
- Health overview - (time dropdown) -
-
-
- - {statusHistoryList && statusHistoryList.length > 0 ? ( - - ) : ( -
- No status history available -
- )} -
- ), - class: "flex flex-col overflow-y-hidden border-b border-gray-300" - }, - checkDetails: { - label: "Check details", - content: ( -
- - {Object.entries(details).map(([label, value]) => ( - - ))} -
- } - /> - - ), - class: `flex flex-col overflow-y-auto border border-gray-300 ${styles.appleScrollbar}` - } - }} - /> - - ); -} - -function CheckStat({ - title, - value, - append, - containerClass, - className, - ...rest -}) { - return ( -
-
{title}
-
- {value} - {append} -
-
- ); -} - -export function getUptimePercentage(check) { - const uptime = check?.uptime; - const passed = uptime?.passed; - const failed = uptime?.failed; - const valid = !Number.isNaN(passed) && !Number.isNaN(failed); - return valid ? (passed / (passed + failed)) * 100 : null; -} - -function DetailField({ label, value, className, ...rest }) { - return ( -
-
- {label} -
-
- {value} -
-
- ); -} - -function StatusHistory({ check, sticky = "false" }) { - const statii = check - ? check.checkStatuses != null - ? check.checkStatuses - : [] - : []; - const data = []; - statii.forEach((status) => { - data.push({ - key: `${check.key}.${check.description}`, - age: format(`${status.time} UTC`), - message: ( - <> - {status.message}{" "} - {!isEmpty(status.error) && - status.error.split("\n").map((item) => ( - <> - {item} -
- - ))} - - ), - duration: - }); - }); - - return ( - check && ( -
- ) - ); -} - -export function PopupTabs({ - tabs, - contentStyle, - contentClass, - variant = "line", - ...rest -}) { - const [selected, setSelected] = useState(Object.keys(tabs)[0]); - - const buttonStyles = { - line: { - container: "flex space-x-4 border-b border-gray-300 z-10", - button: "border-b-2 font-medium text-sm py-2 px-1", - active: "border-indigo-500 text-indigo-600", - inactive: - "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300" - }, - simple: { - container: "flex flex-wrap border-b border-gray-300 z-10", - button: - "-mb-px z-10 bg-white px-4 py-2 font-medium text-sm rounded-t-md border-gray-300 hover:text-gray-900", - active: "text-gray-900 border", - inactive: "text-gray-500 border-b", - styles: { - active: { - borderBottomColor: "white" - } - } - } - }; - return ( -
-
- {Object.entries(tabs).map(([key, tab]) => ( - - ))} -
-
- {Object.entries(tabs).map( - ([key, tab]) => - selected === key && ( -
- {tab.content} -
- ) - )} -
-
- ); -} diff --git a/src/components/Canary/CanaryPopup/tabs.js b/src/components/Canary/CanaryPopup/tabs.js new file mode 100644 index 000000000..0c020144f --- /dev/null +++ b/src/components/Canary/CanaryPopup/tabs.js @@ -0,0 +1,69 @@ +import React, { useState } from "react"; + +export function PopupTabs({ + tabs, + contentStyle, + contentClass, + variant = "line", + ...rest +}) { + const [selected, setSelected] = useState(Object.keys(tabs)[0]); + + const buttonStyles = { + line: { + container: "flex space-x-4 border-b border-gray-300 z-10", + button: "border-b-2 font-medium text-sm py-2 px-1", + active: "border-indigo-500 text-indigo-600", + inactive: + "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300" + }, + simple: { + container: "flex flex-wrap border-b border-gray-300 z-10", + button: + "-mb-px z-10 bg-white px-4 py-2 font-medium text-sm rounded-t-md border-gray-300 hover:text-gray-900", + active: "text-gray-900 border", + inactive: "text-gray-500 border-b", + styles: { + active: { + borderBottomColor: "white" + } + } + } + }; + return ( +
+
+ {Object.entries(tabs).map(([key, tab]) => ( + + ))} +
+
+ {Object.entries(tabs).map( + ([key, tab]) => + selected === key && ( +
+ {tab.content} +
+ ) + )} +
+
+ ); +} diff --git a/src/components/Canary/CanaryPopup/utils.js b/src/components/Canary/CanaryPopup/utils.js new file mode 100644 index 000000000..56f4c5480 --- /dev/null +++ b/src/components/Canary/CanaryPopup/utils.js @@ -0,0 +1,7 @@ +export function getUptimePercentage(check) { + const uptime = check?.uptime; + const passed = uptime?.passed; + const failed = uptime?.failed; + const valid = !Number.isNaN(passed) && !Number.isNaN(failed); + return valid ? (passed / (passed + failed)) * 100 : null; +} diff --git a/src/components/Canary/index.js b/src/components/Canary/index.js index fe9ccf0b8..f52c451a5 100644 --- a/src/components/Canary/index.js +++ b/src/components/Canary/index.js @@ -25,7 +25,8 @@ import { SidebarSubPanel } from "./SidebarSubPanel"; import { RefreshIntervalDropdown } from "../Dropdown/RefreshIntervalDropdown"; import { getLocalItem, setLocalItem } from "../../utils/storage"; import { Modal } from "../Modal"; -import { CheckDetails, CheckTitle } from "./CanaryPopup"; +import { CheckTitle } from "./CanaryPopup/CheckTitle"; +import { CheckDetails } from "./CanaryPopup/CheckDetails"; import styles from "./index.module.css";