Skip to content

Commit

Permalink
Merge pull request #1474 from flanksource/1288-canary-detail-modal-im…
Browse files Browse the repository at this point in the history
…provements

refactor: improve the canary modal layout
  • Loading branch information
moshloop authored Nov 14, 2023
2 parents 05970a2 + 4837b24 commit fa0d3a1
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 97 deletions.
44 changes: 0 additions & 44 deletions src/components/Canary/CanaryPopup/CanaryCheckDetailsLabel.tsx

This file was deleted.

51 changes: 6 additions & 45 deletions src/components/Canary/CanaryPopup/CheckDetails.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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";
Expand Down Expand Up @@ -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<string, React.ReactNode> = useMemo(
() => ({
Labels: <CanaryCheckDetailsLabel check={validCheck} />,
Owner: validCheck?.owner || "-",
Interval: validCheck?.interval || "-",
Location: validCheck?.location || "-",
Schedule: validCheck?.schedule || "-",
"Last Runtime": validCheck?.lastRuntime ? (
<Age from={validCheck.lastRuntime} />
) : (
"-"
)
}),
[validCheck]
);
const severityValue =
validCheck?.severity ?? validCheck?.spec?.severity ?? "-";

if (validCheck == null) {
return null;
Expand All @@ -72,6 +55,7 @@ export function CheckDetails({ check, timeRange, ...rest }: CheckDetailsProps) {
return (
<div {...rest} ref={containerRef}>
<div className="flex flex-col" ref={statsRef}>
<CheckLabels check={validCheck} />
<div className="flex flex-row flex-wrap">
<CheckStat
containerClassName="w-52 mb-4"
Expand Down Expand Up @@ -129,7 +113,6 @@ export function CheckDetails({ check, timeRange, ...rest }: CheckDetailsProps) {
</div>
<div className="w-full h-52 overflow-visible">
<Suspense fallback={<div>Loading..</div>}>
{/* */}
<CanaryStatusChart timeRange={timeRange} check={validCheck} />
</Suspense>
</div>
Expand All @@ -156,36 +139,14 @@ export function CheckDetails({ check, timeRange, ...rest }: CheckDetailsProps) {
content: (
<div
key="status-history"
className={`border border-b-0 border-gray-300 bg-gray-50 overflow-y-auto flex flex-col flex-1 relative -mb-px ${mixins.appleScrollbar}`}
className={`border border-b-0 border-gray-300 bg-white overflow-y-auto flex flex-col flex-1 relative -mb-px ${mixins.appleScrollbar}`}
>
<StatusHistory timeRange={timeRange} check={validCheck} />
</div>
),
class:
"flex-1 flex flex-col overflow-y-hidden border-b h-full border-gray-300"
},
checkDetails: {
label: "Check details",
content: (
<div key="check-details" className="px-6 py-6 h-full">
<AccordionBox
content={
<div className="flex flex-row flex-wrap">
{Object.entries(details).map(([label, value]) => (
<DetailField
key={label}
className="w-1/3 mb-3 whitespace-nowrap"
label={label}
value={value as any}
/>
))}
</div>
}
/>
</div>
),
class: `flex-1 flex flex-col overflow-y-auto border border-gray-300 ${mixins.appleScrollbar}`
},
specs: {
label: "Spec",
content: <CanaryCheckDetailsSpecTab check={validCheck} />,
Expand Down
92 changes: 92 additions & 0 deletions src/components/Canary/CanaryPopup/CheckLabels.tsx
Original file line number Diff line number Diff line change
@@ -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<Pick<HealthCheck, "labels">>;
};

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 (
<div className="flex flex-row gap-2 mb-4 items-center w-full">
<Popover
menuClass="w-auto top-6"
toggle={
<div className="flex flex-row flex-1 gap-1 items-center">
<div
id="labels-container"
className="flex w-auto flex-row flex-shrink overflow-hidden h-7 gap-1 flex-wrap cursor-pointer"
>
{checkLabels.map((item) => (
<TagItem
className="bg-blue-100 text-blue-800"
key={item.key}
tag={item}
/>
))}
</div>
{isOverflowing && (
<div className="w-auto gap-2 underline decoration-solid justify-left text-xs cursor-pointer">
+{checkLabels.length - 1} more
</div>
)}
</div>
}
placement="left"
>
<div className="flex flex-col p-1">
<div className="flex flex-col items-stretch max-h-96 overflow-y-auto">
<TagList
className="flex flex-col flex-1"
tags={checkLabels}
minimumItemsToShow={checkLabels.length}
childClassName="bg-blue-100 text-blue-800"
/>
</div>
</div>
</Popover>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,10 @@ export function StatusHistory({

return (
<div
className={clsx("w-full flex flex-col flex-1 overflow-y-auto", className)}
className={clsx(
"w-full flex flex-col flex-1 overflow-y-auto bg-white",
className
)}
{...props}
>
<StatusHistoryFilters onFiltersChanges={onFiltersChange} />
Expand All @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface IModalProps {
size: ModalSize;
children: React.ReactNode;
containerClassName?: string;
dialogClassName?: string;
}

export function Modal({
Expand All @@ -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 (
Expand All @@ -50,7 +52,7 @@ export function Modal({
<Dialog
as="div"
auto-reopen="true"
className="fixed z-50 inset-0 overflow-y-auto my-20"
className={dialogClassName}
onClose={allowBackgroundClose ? () => onClose() : () => {}}
{...rest}
>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Popover/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function Popover({
children,
placement = "right",
className,
menuClass = "top-6",
menuClass = "top-6 w-56",
toggle,
autoCloseTimeInMS = 5000,
...props
Expand Down Expand Up @@ -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
Expand Down
14 changes: 11 additions & 3 deletions src/components/TagList/TagList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,30 @@ export function sortTags(tags: TagEntry[]) {
type TagListProps = React.HTMLProps<HTMLDivElement> & {
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 (
<div
className="flex flex-row p-[0.15rem] bg-gray-200 rounded-md mx-1"
className={`flex flex-row p-[0.15rem] rounded-md ${className}`}
data-tip={`${key}:${value}`}
>
<div
className="flex flex-row space-x-1 font-semibold p-[0.2rem] text-gray-600 text-xs truncate"
className="flex flex-row space-x-1 font-semibold p-[0.2rem] text-xs whitespace-nowrap break-inside-avoid-column"
style={containerWidth ? { width: containerWidth } : {}}
>
<span className="inline">{key}:</span>
Expand All @@ -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);
Expand Down Expand Up @@ -133,6 +140,7 @@ export function TagList({
<TagItem
key={key}
tag={{ key, value }}
className={childClassName}
containerWidth={containerWidth}
/>
))}
Expand Down

0 comments on commit fa0d3a1

Please sign in to comment.