Skip to content

Commit

Permalink
feat: when a catalog has one topology, show only topology card
Browse files Browse the repository at this point in the history
Fixes #2174

fix: show loading animation, until card is shown or not

chore: wip

fix: fix incorrect import

fix: change how merged pages work
  • Loading branch information
mainawycliffe committed Oct 18, 2024
1 parent 0dd788c commit 405c0f3
Show file tree
Hide file tree
Showing 16 changed files with 530 additions and 255 deletions.
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ export function IncidentManagerRoutes({ sidebar }: { sidebar: ReactNode }) {
<Route
path=":id"
element={withAuthorizationAccessCheck(
<TopologyPage />,
<TopologyPage></TopologyPage>,
tables.database,
"read",
true
Expand Down
64 changes: 64 additions & 0 deletions src/api/query-hooks/useTopologyByIDQuery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useQuery } from "@tanstack/react-query";
import { useRef } from "react";
import { useSearchParams } from "react-router-dom";
import { LoadingBarRef } from "react-top-loading-bar";
import { getTopology } from "../services/topology";

export default function useTopologyByIDQuery(id: string) {
const [searchParams] = useSearchParams({
sortBy: "status",
sortOrder: "desc"
});

const selectedLabel = searchParams.get("labels") ?? "All";
const team = searchParams.get("team") ?? "All";
const topologyType = searchParams.get("type") ?? "All";
const healthStatus = searchParams.get("status") ?? "All";
const sortBy = searchParams.get("sortBy") ?? "status";
const sortOrder = searchParams.get("sortOrder") ?? "desc";
const agentId = searchParams.get("agent_id") ?? undefined;
const showHiddenComponents =
searchParams.get("showHiddenComponents") ?? undefined;

const loadingBarRef = useRef<LoadingBarRef>(null);

return useQuery(
[
"topologies",
id,
healthStatus,
team,
selectedLabel,
topologyType,
showHiddenComponents,
sortBy,
sortOrder,
agentId
],
() => {
loadingBarRef.current?.continuousStart();
const apiParams = {
id,
status: healthStatus,
type: topologyType,
team: team,
labels: selectedLabel,
sortBy,
sortOrder,
// only flatten, if topology type is set
...(topologyType &&
topologyType.toString().toLowerCase() !== "all" && {
flatten: true
}),
hidden: showHiddenComponents === "no" ? false : undefined,
agent_id: agentId
};
return getTopology(apiParams);
},
{
onSettled: () => {
loadingBarRef.current?.complete();
}
}
);
}
3 changes: 2 additions & 1 deletion src/api/services/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ConfigChange,
ConfigHealthCheckView,
ConfigItem,
ConfigItemDetails,
ConfigSummary,
ConfigTypeRelationships
} from "../types/configs";
Expand Down Expand Up @@ -144,7 +145,7 @@ export const getAllChanges = (
};

export const getConfig = (id: string) =>
resolvePostGrestRequestWithPagination<ConfigItem[]>(
resolvePostGrestRequestWithPagination<ConfigItemDetails[]>(
ConfigDB.get(`/config_detail?id=eq.${id}&select=*,config_scrapers(id,name)`)
);

Expand Down
19 changes: 12 additions & 7 deletions src/api/types/configs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Agent, Avatar, CreatedAt, Timestamped } from "../traits";
import { HealthCheckSummary } from "./health";
import { Topology } from "./topology";

export interface ConfigChange extends CreatedAt {
id: string;
Expand Down Expand Up @@ -69,13 +70,6 @@ export interface ConfigItem extends Timestamped, Avatar, Agent, Costs {
id: string;
name: string;
};
summary?: {
relationships?: number;
analysis?: number;
changes?: number;
playbook_runs?: number;
checks?: number;
};
properties?: {
icon: string;
name: string;
Expand All @@ -87,6 +81,17 @@ export interface ConfigItem extends Timestamped, Avatar, Agent, Costs {
last_scraped_time?: string;
}

export interface ConfigItemDetails extends ConfigItem {
summary?: {
relationships?: number;
analysis?: number;
changes?: number;
playbook_runs?: number;
checks?: number;
};
components?: Topology[];
}

export interface ConfigItemGraphData extends ConfigItem {
expanded?: boolean;
expandable?: boolean;
Expand Down
3 changes: 3 additions & 0 deletions src/api/types/topology.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Agent, Namespaced, Timestamped } from "../traits";
import { CostsData, Severity, ValueType } from "./common";
import { ConfigItem } from "./configs";
import { HealthCheckSummary } from "./health";
import { IncidentType } from "./incident";
import { User } from "./users";
Expand Down Expand Up @@ -68,6 +69,8 @@ export interface Topology extends Component, CostsData, Agent {
children?: string[];
is_leaf?: boolean;
description?: string;
config_id?: string;
configs?: Pick<ConfigItem, "name" | "id" | "type">[];
}

export type ComponentTeamItem = {
Expand Down
35 changes: 35 additions & 0 deletions src/components/Configs/ConfigComponents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import useTopologyByIDQuery from "@flanksource-ui/api/query-hooks/useTopologyByIDQuery";
import IncidentDetailsPageSkeletonLoader from "@flanksource-ui/ui/SkeletonLoader/IncidentDetailsPageSkeletonLoader";
import { TopologyCard } from "../Topology/TopologyCard";
import { useTopologyCardWidth } from "../Topology/TopologyPopover/topologyPreference";

type ConfigComponentsProps = {
topologyId: string;
};

export default function ConfigComponents({
topologyId
}: ConfigComponentsProps) {
const { data, isLoading } = useTopologyByIDQuery(topologyId);

const [topologyCardSize] = useTopologyCardWidth();

return (
<div className="flex w-full flex-1 overflow-y-auto">
<div className="flex w-full flex-wrap p-4">
{isLoading && data ? (
<IncidentDetailsPageSkeletonLoader />
) : (
data?.components?.[0].components?.map((component) => (
<TopologyCard
key={component.id}
topology={component}
size={topologyCardSize}
menuPosition="absolute"
/>
))
)}
</div>
</div>
);
}
55 changes: 34 additions & 21 deletions src/components/Configs/ConfigDetailsTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SearchLayout } from "@flanksource-ui/ui/Layout/SearchLayout";
import IncidentDetailsPageSkeletonLoader from "@flanksource-ui/ui/SkeletonLoader/IncidentDetailsPageSkeletonLoader";
import clsx from "clsx";
import { useAtom } from "jotai";
import { ReactNode } from "react";
Expand All @@ -9,21 +10,24 @@ import { Head } from "../../ui/Head";
import { refreshButtonClickedTrigger } from "../../ui/SlidingSideBar/SlidingSideBar";
import TabbedLinks from "../../ui/Tabs/TabbedLinks";
import { ErrorBoundary } from "../ErrorBoundary";
import ConfigComponents from "./ConfigComponents";
import { useConfigDetailsTabs } from "./ConfigTabsLinks";
import ConfigSidebar from "./Sidebar/ConfigSidebar";

type ConfigDetailsTabsProps = {
export type ConfigTab =
| "Catalog"
| "Changes"
| "Insights"
| "Relationships"
| "Playbooks"
| "Checks";

export type ConfigDetailsTabsProps = {
refetch?: () => void;
children: ReactNode;
isLoading?: boolean;
pageTitlePrefix: string;
activeTabName:
| "Catalog"
| "Changes"
| "Insights"
| "Relationships"
| "Playbooks"
| "Checks";
activeTabName: ConfigTab;
className?: string;
};

Expand Down Expand Up @@ -69,21 +73,30 @@ export function ConfigDetailsTabs({
loading={isLoading}
contentClass="p-0 h-full overflow-y-hidden"
>
<div className={`flex h-full flex-row`}>
<div className="flex flex-1 flex-col overflow-x-auto">
<TabbedLinks
activeTabName={activeTabName}
tabLinks={configTabList}
contentClassName={clsx(
"bg-white border border-t-0 border-gray-300 flex-1 overflow-y-auto",
className
{isLoadingConfig ? (
<IncidentDetailsPageSkeletonLoader />
) : (
<div className={`flex h-full flex-row bg-gray-100`}>
<div className="flex h-full flex-1 flex-col">
{configItem?.components && configItem.components.length === 1 && (
<ConfigComponents topologyId={configItem.components[0].id} />
)}
>
<ErrorBoundary>{children}</ErrorBoundary>
</TabbedLinks>
<TabbedLinks
activeTabName={activeTabName}
tabLinks={configTabList}
contentClassName={clsx(
"bg-white border border-t-0 border-gray-300 flex-1 overflow-y-auto",
className
)}
>
<ErrorBoundary>{children}</ErrorBoundary>
</TabbedLinks>
</div>
<ConfigSidebar
topologyProperties={configItem?.components?.[0]?.properties}
/>
</div>
<ConfigSidebar />
</div>
)}
</SearchLayout>
</>
);
Expand Down
19 changes: 11 additions & 8 deletions src/components/Configs/ConfigTabsLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Badge } from "@flanksource-ui/ui/Badge/Badge";
import { useParams } from "react-router-dom";
import { ConfigItem } from "../../api/types/configs";
import { ConfigItemDetails } from "../../api/types/configs";

export function useConfigDetailsTabs(countSummary?: ConfigItem["summary"]) {
export function useConfigDetailsTabs(
countSummary?: ConfigItemDetails["summary"],
basePath: `/${string}` = "/catalog"
) {
const { id } = useParams<{ id: string }>();

return [
{ label: "Config", key: "Catalog", path: `/catalog/${id}` },
{ label: "Config", key: "Catalog", path: `${basePath}/${id}` },
{
label: (
<>
Expand All @@ -15,7 +18,7 @@ export function useConfigDetailsTabs(countSummary?: ConfigItem["summary"]) {
</>
),
key: "Changes",
path: `/catalog/${id}/changes`
path: `${basePath}/${id}/changes`
},
{
label: (
Expand All @@ -25,7 +28,7 @@ export function useConfigDetailsTabs(countSummary?: ConfigItem["summary"]) {
</>
),
key: "Insights",
path: `/catalog/${id}/insights`
path: `${basePath}/${id}/insights`
},
{
label: (
Expand All @@ -35,7 +38,7 @@ export function useConfigDetailsTabs(countSummary?: ConfigItem["summary"]) {
</>
),
key: "Relationships",
path: `/catalog/${id}/relationships`
path: `${basePath}/${id}/relationships`
},
{
label: (
Expand All @@ -45,7 +48,7 @@ export function useConfigDetailsTabs(countSummary?: ConfigItem["summary"]) {
</>
),
key: "Playbooks",
path: `/catalog/${id}/playbooks`
path: `${basePath}/${id}/playbooks`
},
{
label: (
Expand All @@ -55,7 +58,7 @@ export function useConfigDetailsTabs(countSummary?: ConfigItem["summary"]) {
</>
),
key: "Checks",
path: `/catalog/${id}/checks`
path: `${basePath}/${id}/checks`
}
];
}
17 changes: 16 additions & 1 deletion src/components/Configs/Sidebar/ConfigDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useGetConfigByIdQuery } from "@flanksource-ui/api/query-hooks";
import { isCostsEmpty } from "@flanksource-ui/api/types/configs";
import { Topology } from "@flanksource-ui/api/types/topology";
import { formatProperties } from "@flanksource-ui/components/Topology/Sidebar/Utils/formatProperties";
import { Age } from "@flanksource-ui/ui/Age";
import TextSkeletonLoader from "@flanksource-ui/ui/SkeletonLoader/TextSkeletonLoader";
Expand All @@ -17,9 +18,10 @@ import { formatConfigLabels } from "./Utils/formatConfigLabels";

type Props = {
configId: string;
topologyProperties?: Topology["properties"];
};

export function ConfigDetails({ configId }: Props) {
export function ConfigDetails({ configId, topologyProperties }: Props) {
const {
data: configDetails,
isLoading,
Expand Down Expand Up @@ -67,6 +69,15 @@ export function ConfigDetails({ configId }: Props) {
[configDetails]
);

const formattedTopologyProperties = useMemo(() => {
if (topologyProperties) {
return formatProperties({
properties: topologyProperties
});
}
return undefined;
}, [topologyProperties]);

const isLastScrappedMoreThan1Hour = useMemo(() => {
if (!configDetails?.last_scraped_time) {
return false;
Expand Down Expand Up @@ -179,6 +190,10 @@ export function ConfigDetails({ configId }: Props) {
]}
/>

{formattedTopologyProperties && (
<DisplayGroupedProperties items={formattedTopologyProperties} />
)}

<DisplayDetailsRow
items={[
{
Expand Down
Loading

0 comments on commit 405c0f3

Please sign in to comment.