From 2916426abd0d1a24857ae5a9358c68a5068e46ad Mon Sep 17 00:00:00 2001 From: Moshe Immermam Date: Sun, 29 Oct 2023 20:40:22 +0200 Subject: [PATCH] feat: add embedded topology page --- src/App.tsx | 16 ++++++++- src/components/Head/Head.tsx | 10 ++++-- src/components/HealthChecksSummary/index.tsx | 4 ++- src/components/IncidentCardSummary/index.tsx | 13 +++++-- src/components/StatusLine/StatusLine.tsx | 11 +++++- .../TopologyCard/TopologyCard.stories.tsx | 2 +- .../TopologyConfigAnalysisLine.tsx | 6 ++-- .../TopologyCard/TopologyDropdownMenu.tsx | 10 +++--- src/components/TopologyCard/index.tsx | 24 ++++++++----- src/pages/TopologyCard.tsx | 35 +++++++++++++++++++ src/pages/TopologyPage.tsx | 3 +- 11 files changed, 108 insertions(+), 26 deletions(-) create mode 100644 src/pages/TopologyCard.tsx diff --git a/src/App.tsx b/src/App.tsx index 21d75d1323..366194bee6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -68,6 +68,7 @@ import { features } from "./services/permissions/features"; import { stringSortHelper } from "./utils/common"; import { MdOutlineSupportAgent } from "react-icons/md"; import AgentsPage from "./components/Agents/AgentPage"; +import { TopologyCardPage } from "./pages/TopologyCard"; export type NavigationItems = { name: string; @@ -223,7 +224,11 @@ export function HealthRoutes({ sidebar }: { sidebar: ReactNode }) { export function IncidentManagerRoutes({ sidebar }: { sidebar: ReactNode }) { const { featureFlagsLoaded } = useFeatureFlagsContext(); - if (!featureFlagsLoaded) { + console.log(window.location.pathname); + if ( + !featureFlagsLoaded && + !window.location.pathname.startsWith("/view/topology") + ) { return ; } @@ -231,6 +236,15 @@ export function IncidentManagerRoutes({ sidebar }: { sidebar: ReactNode }) { } /> + , + tables.topologies, + "read" + )} + /> + - {prefix} | Mission Control - + + {prefix} + {suffix} + + ); } diff --git a/src/components/HealthChecksSummary/index.tsx b/src/components/HealthChecksSummary/index.tsx index 7e6a865039..f480a68d32 100644 --- a/src/components/HealthChecksSummary/index.tsx +++ b/src/components/HealthChecksSummary/index.tsx @@ -3,6 +3,7 @@ import { AiFillHeart } from "react-icons/ai"; import { StatusLine, StatusLineProps } from "../StatusLine/StatusLine"; type HealthChecksSummaryProps = React.HTMLProps & { + target?: string; checks?: { health: number; warning: number; @@ -12,6 +13,7 @@ type HealthChecksSummaryProps = React.HTMLProps & { export function HealthChecksSummary({ checks, + target = "", ...rest }: HealthChecksSummaryProps) { const statusLineInfo = useMemo(() => { @@ -53,5 +55,5 @@ export function HealthChecksSummary({ return null; } - return ; + return ; } diff --git a/src/components/IncidentCardSummary/index.tsx b/src/components/IncidentCardSummary/index.tsx index 18f45955a5..c0d061fe04 100644 --- a/src/components/IncidentCardSummary/index.tsx +++ b/src/components/IncidentCardSummary/index.tsx @@ -25,11 +25,13 @@ const chipColorFromSeverity = ( type IncidentSummaryTypes = keyof typeof typeItems; type IncidentCardSummaryProps = { + target?: string; topology: Pick; }; export default function IncidentCardSummary({ - topology + topology, + target = "" }: IncidentCardSummaryProps) { const statusLines: StatusLineProps[] = useMemo(() => { const incidentSummary = Object.entries(topology?.summary?.incidents || {}); @@ -75,7 +77,14 @@ export default function IncidentCardSummary({ return ( <> {statusLines.map((statusLine, index) => { - return ; + return ( + + ); })} ); diff --git a/src/components/StatusLine/StatusLine.tsx b/src/components/StatusLine/StatusLine.tsx index b296438c87..d3da5658a8 100644 --- a/src/components/StatusLine/StatusLine.tsx +++ b/src/components/StatusLine/StatusLine.tsx @@ -31,13 +31,20 @@ const renderIcon = (icon: string | React.ReactNode) => { } }; -const StatusInfoEntry = ({ statusInfo }: { statusInfo: StatusInfo }) => { +const StatusInfoEntry = ({ + statusInfo, + target +}: { + statusInfo: StatusInfo; + target?: string; +}) => { if (statusInfo.url) { return ( {statusInfo.icon && renderIcon(statusInfo.icon)} @@ -55,6 +62,7 @@ const StatusInfoEntry = ({ statusInfo }: { statusInfo: StatusInfo }) => { export function StatusLine({ icon, + target = "", label, url, statuses, @@ -70,6 +78,7 @@ export function StatusLine({ {url && ( diff --git a/src/components/TopologyCard/TopologyCard.stories.tsx b/src/components/TopologyCard/TopologyCard.stories.tsx index 0d52ca280a..3b918e7232 100644 --- a/src/components/TopologyCard/TopologyCard.stories.tsx +++ b/src/components/TopologyCard/TopologyCard.stories.tsx @@ -3,7 +3,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { MemoryRouter } from "react-router-dom"; import { Size } from "../../types"; import { TopologyCard } from "./index"; -import { Topology } from "../../context/TopologyPageContext"; +import { Topology } from "../../api/types/topology"; const defaultQueryClient = new QueryClient(); diff --git a/src/components/TopologyCard/TopologyConfigAnalysisLine.tsx b/src/components/TopologyCard/TopologyConfigAnalysisLine.tsx index d3b72cd20e..7718918098 100644 --- a/src/components/TopologyCard/TopologyConfigAnalysisLine.tsx +++ b/src/components/TopologyCard/TopologyConfigAnalysisLine.tsx @@ -31,11 +31,13 @@ const severityToColorMap = (severity: string) => { }; type TopologyConfigAnalysisLineProps = { + target?: string; topology: Pick; }; export function TopologyConfigAnalysisLine({ - topology + topology, + target = "" }: TopologyConfigAnalysisLineProps) { const insights = topology?.summary?.insights; @@ -86,5 +88,5 @@ export function TopologyConfigAnalysisLine({ return null; } - return ; + return ; } diff --git a/src/components/TopologyCard/TopologyDropdownMenu.tsx b/src/components/TopologyCard/TopologyDropdownMenu.tsx index e061db5cd9..fd8fd7ee69 100644 --- a/src/components/TopologyCard/TopologyDropdownMenu.tsx +++ b/src/components/TopologyCard/TopologyDropdownMenu.tsx @@ -31,13 +31,13 @@ function TopologyMenuItem({ interface IProps { topology: Topology; onRefresh?: () => void; - isTopologyPage?: boolean; + position?: "fixed" | "absolute"; } export const TopologyDropdownMenu = ({ topology, onRefresh, - isTopologyPage = false + position = "fixed" }: IProps) => { const [dropDownMenuStyles, setDropDownMenuStyles] = useState(); @@ -62,13 +62,13 @@ export const TopologyDropdownMenu = ({ const top = node.getBoundingClientRect().bottom; if (left && top) { - if (isTopologyPage) { + if (position === "absolute") { setDropDownMenuStyles({ right: 0, top: "1.5rem", position: "absolute" }); - } else { + } else if (position === "fixed") { setDropDownMenuStyles({ left: left - 200, top: top, @@ -77,7 +77,7 @@ export const TopologyDropdownMenu = ({ } } }, - [isTopologyPage] + [position] ); const [ diff --git a/src/components/TopologyCard/index.tsx b/src/components/TopologyCard/index.tsx index f22f6d101e..d8c9499ae4 100644 --- a/src/components/TopologyCard/index.tsx +++ b/src/components/TopologyCard/index.tsx @@ -3,7 +3,6 @@ import clsx from "clsx"; import { MouseEventHandler, useMemo } from "react"; import { Link, useParams, useSearchParams } from "react-router-dom"; import { getTopology } from "../../api/services/topology"; -import { Topology } from "../../context/TopologyPageContext"; import { Size } from "../../types"; import AgentName from "../Agents/AgentName"; import { CustomScroll } from "../CustomScroll"; @@ -16,6 +15,7 @@ import { CardMetrics } from "./CardMetrics"; import { Property } from "./Property"; import { TopologyConfigAnalysisLine } from "./TopologyConfigAnalysisLine"; import { TopologyDropdownMenu } from "./TopologyDropdownMenu"; +import { Topology } from "../../api/types/topology"; export enum ComponentStatus { unhealthy = "unhealthy", @@ -39,9 +39,12 @@ interface IProps { topologyId?: string; topology?: Topology; selectionMode?: boolean; + hideMenu?: boolean; + // where to open new links + target?: string; selected?: boolean; onSelectionChange?: MouseEventHandler; - isTopologyPage?: boolean; + menuPosition?: "fixed" | "absolute"; } export function TopologyCard({ @@ -49,9 +52,11 @@ export function TopologyCard({ topology: topologyData, topologyId, selectionMode, + target = "", + hideMenu, selected, onSelectionChange, - isTopologyPage = false + menuPosition = "fixed" }: IProps) { const [searchParams] = useSearchParams(); const { id: parentId } = useParams(); @@ -177,7 +182,7 @@ export function TopologyCard({ )}
- {selectionMode ? ( + {selectionMode && (
- ) : ( - + )} + + {!selectionMode && !hideMenu && ( + )}
@@ -231,6 +235,7 @@ export function TopologyCard({ {canShowChildHealth() && ( @@ -240,6 +245,7 @@ export function TopologyCard({ {topology?.components?.map((component: any) => ( diff --git a/src/pages/TopologyCard.tsx b/src/pages/TopologyCard.tsx new file mode 100644 index 0000000000..aa31050708 --- /dev/null +++ b/src/pages/TopologyCard.tsx @@ -0,0 +1,35 @@ +import { useQuery } from "@tanstack/react-query"; +import { useParams } from "react-router-dom"; +import { getTopology } from "../api/services/topology"; +import { TopologyCard } from "../components/TopologyCard"; +import { Head } from "../components/Head/Head"; +import { InfoMessage } from "../components/InfoMessage"; + +export function TopologyCardPage() { + const { id, size } = useParams(); + + const { data } = useQuery({ + queryKey: ["topology", id], + queryFn: () => getTopology({ id: id }) + }); + + if (!data || !data.components || data.components?.length === 0) { + return ; + } + + const topology = data.components[0]; + return ( + <> + + +
+ +
+ + ); +} diff --git a/src/pages/TopologyPage.tsx b/src/pages/TopologyPage.tsx index 2ed7ba105e..3449811fe5 100644 --- a/src/pages/TopologyPage.tsx +++ b/src/pages/TopologyPage.tsx @@ -80,6 +80,7 @@ export function TopologyPage() { const refererId = searchParams.get("refererId") ?? undefined; const sortBy = searchParams.get("sortBy") ?? undefined; const sortOrder = searchParams.get("sortOrder") ?? undefined; + const hideFilters = searchParams.get("hideFilters") ?? undefined; const showHiddenComponents = searchParams.get("showHiddenComponents") ?? undefined; @@ -230,7 +231,7 @@ export function TopologyPage() { key={item.id} topology={item} size={topologyCardSize} - isTopologyPage + menuPosition="absolute" /> ))} {!topology?.length && !isLoading && (