From 4837b24a43e9ed673443d5b726d1d140ed379c63 Mon Sep 17 00:00:00 2001 From: Maina Wycliffe Date: Thu, 2 Nov 2023 16:58:49 +0300 Subject: [PATCH] refactor: improve the canary modal layout Closes #1288 fix: fix height issues chore: show labels until full width fix: remove bg issues fix: fix height issue in the table --- .../CanaryPopup/CanaryCheckDetailsLabel.tsx | 44 --------- .../Canary/CanaryPopup/CheckDetails.tsx | 51 ++-------- .../Canary/CanaryPopup/CheckLabels.tsx | 92 +++++++++++++++++++ .../StatusHistory/StatusHistory.tsx | 7 +- src/components/Modal/index.tsx | 4 +- src/components/Popover/Popover.tsx | 4 +- src/components/TagList/TagList.tsx | 14 ++- 7 files changed, 119 insertions(+), 97 deletions(-) delete mode 100644 src/components/Canary/CanaryPopup/CanaryCheckDetailsLabel.tsx create mode 100644 src/components/Canary/CanaryPopup/CheckLabels.tsx diff --git a/src/components/Canary/CanaryPopup/CanaryCheckDetailsLabel.tsx b/src/components/Canary/CanaryPopup/CanaryCheckDetailsLabel.tsx deleted file mode 100644 index e785ef3f9..000000000 --- a/src/components/Canary/CanaryPopup/CanaryCheckDetailsLabel.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useEffect } from "react"; -import ReactTooltip from "react-tooltip"; -import { HealthCheck } from "../../../api/types/health"; - -type CanaryCheckDetailsLabelProps = { - check?: Partial; -}; - -export function CanaryCheckDetailsLabel({ - check -}: CanaryCheckDetailsLabelProps) { - useEffect(() => { - ReactTooltip.rebuild(); - }); - - if (!check?.labels) { - return null; - } - - return ( -
- {Object.entries(check?.labels).map((entry) => { - const key = entry[0]; - const value = entry[1] === "true" || entry[1] === true ? "" : entry[1]; - - return ( -
- {value === "" ? ( - key - ) : ( - <> - {key}: {value} - - )} -
- ); - })} -
- ); -} diff --git a/src/components/Canary/CanaryPopup/CheckDetails.tsx b/src/components/Canary/CanaryPopup/CheckDetails.tsx index 7cfe2a8b6..b8b24add3 100644 --- a/src/components/Canary/CanaryPopup/CheckDetails.tsx +++ b/src/components/Canary/CanaryPopup/CheckDetails.tsx @@ -1,4 +1,4 @@ -import React, { Suspense, useMemo, useRef } from "react"; +import React, { Suspense, useRef } from "react"; import { useCanaryGraphQuery } from "../../../api/query-hooks/health"; import { HealthCheck } from "../../../api/types/health"; import { @@ -7,15 +7,12 @@ import { } from "../../../utils/common"; import { usePrevious } from "../../../utils/hooks"; import mixins from "../../../utils/mixins.module.css"; -import { AccordionBox } from "../../AccordionBox"; import { DropdownStandaloneWrapper } from "../../Dropdown/StandaloneWrapper"; import { TimeRange, timeRanges } from "../../Dropdown/TimeRange"; -import { Age } from "../../../ui/Age"; import { Duration } from "../renderers"; -import { CanaryCheckDetailsLabel } from "./CanaryCheckDetailsLabel"; import { CanaryCheckDetailsSpecTab } from "./CanaryCheckDetailsSpec"; +import CheckLabels from "./CheckLabels"; import { CheckStat } from "./CheckStat"; -import { DetailField } from "./DetailField"; import { StatusHistory } from "./StatusHistory/StatusHistory"; import { PopupTabs } from "./tabs"; import { getUptimePercentage } from "./utils"; @@ -47,23 +44,9 @@ export function CheckDetails({ check, timeRange, ...rest }: CheckDetailsProps) { const validUptime = !Number.isNaN(validCheck?.uptime?.passed) && !Number.isNaN(validCheck?.uptime?.failed); - const severityValue = validCheck?.severity || "-"; - const details: Record = useMemo( - () => ({ - Labels: , - Owner: validCheck?.owner || "-", - Interval: validCheck?.interval || "-", - Location: validCheck?.location || "-", - Schedule: validCheck?.schedule || "-", - "Last Runtime": validCheck?.lastRuntime ? ( - - ) : ( - "-" - ) - }), - [validCheck] - ); + const severityValue = + validCheck?.severity ?? validCheck?.spec?.severity ?? "-"; if (validCheck == null) { return null; @@ -72,6 +55,7 @@ export function CheckDetails({ check, timeRange, ...rest }: CheckDetailsProps) { return (
+
Loading..
}> - {/* */}
@@ -156,7 +139,7 @@ export function CheckDetails({ check, timeRange, ...rest }: CheckDetailsProps) { content: (
@@ -164,28 +147,6 @@ export function CheckDetails({ check, timeRange, ...rest }: CheckDetailsProps) { class: "flex-1 flex flex-col overflow-y-hidden border-b h-full border-gray-300" }, - checkDetails: { - label: "Check details", - content: ( -
- - {Object.entries(details).map(([label, value]) => ( - - ))} -
- } - /> -
- ), - class: `flex-1 flex flex-col overflow-y-auto border border-gray-300 ${mixins.appleScrollbar}` - }, specs: { label: "Spec", content: , diff --git a/src/components/Canary/CanaryPopup/CheckLabels.tsx b/src/components/Canary/CanaryPopup/CheckLabels.tsx new file mode 100644 index 000000000..cc9b62cf9 --- /dev/null +++ b/src/components/Canary/CanaryPopup/CheckLabels.tsx @@ -0,0 +1,92 @@ +import { useLayoutEffect, useMemo, useState } from "react"; +import { HealthCheck } from "../../../api/types/health"; +import Popover from "../../Popover/Popover"; +import { TagItem, TagList } from "../../TagList/TagList"; + +type Props = { + check: Partial>; +}; + +export default function CheckLabels({ check }: Props) { + const [isOverflowing, setIsOverflowing] = useState(false); + + const checkLabels = useMemo(() => { + if (check?.labels) { + return Object.entries(check.labels).map(([key, value]) => ({ + key, + value + })); + } + return []; + }, [check?.labels]); + + useLayoutEffect(() => { + if (isOverflowing) { + return; + } + const node = document.getElementById("labels-container"); + if (node) { + const isOverflowing = + node.scrollWidth > node.clientWidth || + node.scrollHeight > node.clientHeight; + + if (isOverflowing) { + const childNodes = Array.from(node.childNodes) as HTMLDivElement[]; + let width = 0; + + childNodes.forEach((childNode) => { + width += childNode.clientWidth; + if (width > node.clientWidth) { + childNode.style.display = "none"; + } + }); + } + setIsOverflowing(isOverflowing); + } + }, [checkLabels, isOverflowing]); + + if (checkLabels.length === 0) { + return null; + } + + return ( +
+ +
+ {checkLabels.map((item) => ( + + ))} +
+ {isOverflowing && ( +
+ +{checkLabels.length - 1} more +
+ )} +
+ } + placement="left" + > +
+
+ +
+
+ +
+ ); +} diff --git a/src/components/Canary/CanaryPopup/StatusHistory/StatusHistory.tsx b/src/components/Canary/CanaryPopup/StatusHistory/StatusHistory.tsx index 618cad449..23cf79893 100644 --- a/src/components/Canary/CanaryPopup/StatusHistory/StatusHistory.tsx +++ b/src/components/Canary/CanaryPopup/StatusHistory/StatusHistory.tsx @@ -162,7 +162,10 @@ export function StatusHistory({ return (
@@ -173,7 +176,7 @@ export function StatusHistory({ columns={columns} data={statii} tableStyle={{ borderSpacing: "0" }} - className="flex-1" + className="" pagination={pagination} paginationClassName="px-2 pb-2" preferencesKey="health-check-status-list" diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index 779b52247..696dd80b3 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -27,6 +27,7 @@ interface IModalProps { size: ModalSize; children: React.ReactNode; containerClassName?: string; + dialogClassName?: string; } export function Modal({ @@ -42,6 +43,7 @@ export function Modal({ size, children, containerClassName = "overflow-auto max-h-full", + dialogClassName = "fixed z-50 inset-0 overflow-y-auto 2xl:my-20", ...rest }: IModalProps) { return ( @@ -50,7 +52,7 @@ export function Modal({ onClose() : () => {}} {...rest} > diff --git a/src/components/Popover/Popover.tsx b/src/components/Popover/Popover.tsx index a39931a41..6842985c9 100644 --- a/src/components/Popover/Popover.tsx +++ b/src/components/Popover/Popover.tsx @@ -19,7 +19,7 @@ export default function Popover({ children, placement = "right", className, - menuClass = "top-6", + menuClass = "top-6 w-56", toggle, autoCloseTimeInMS = 5000, ...props @@ -99,7 +99,7 @@ export default function Popover({ aria-orientation="vertical" aria-labelledby="menu-button" className={clsx( - "flex flex-col origin-top-right absolute w-96 z-50 divide-y divide-gray-100 rounded-md drop-shadow-xl bg-slate-50 ring-1 ring-black ring-opacity-5 focus:outline-none", + "flex flex-col origin-top-right absolute z-50 divide-y divide-gray-100 rounded-md drop-shadow-xl bg-slate-50 ring-1 ring-black ring-opacity-5 focus:outline-none", isPopoverOpen ? "display-block" : "hidden", placement === "right" ? "right-0" : "left-0", menuClass diff --git a/src/components/TagList/TagList.tsx b/src/components/TagList/TagList.tsx index 8166e9f6f..ba319bd11 100644 --- a/src/components/TagList/TagList.tsx +++ b/src/components/TagList/TagList.tsx @@ -39,24 +39,30 @@ export function sortTags(tags: TagEntry[]) { type TagListProps = React.HTMLProps & { tags: TagEntry[]; minimumItemsToShow?: number; + childClassName?: string; }; type TagItemProps = { containerWidth?: string; + className?: string; tag: { key: string; value: string; }; }; -export function TagItem({ tag: { key, value }, containerWidth }: TagItemProps) { +export function TagItem({ + tag: { key, value }, + containerWidth, + className = "bg-gray-200 text-gray-600 mx-1" +}: TagItemProps) { return (
{key}: @@ -70,6 +76,7 @@ export function TagList({ tags, minimumItemsToShow = 1, className = `flex flex-row text-left items-start flex-1`, + childClassName = "bg-gray-200 text-gray-600 mx-1", ...rest }: TagListProps) { const [showAll, setShowAll] = useState(false); @@ -133,6 +140,7 @@ export function TagList({ ))}