Skip to content

Commit

Permalink
feat: show linked catalogs and components for check
Browse files Browse the repository at this point in the history
Closes #1505

tests: add tests for relationships

refactor: rename to CheckLinkedTo
  • Loading branch information
mainawycliffe committed Dec 23, 2023
1 parent 7cf7125 commit 38b4188
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/api/services/topology.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export const getHealthCheckSummary = async (id: string) => {
export const getHealthCheckDetails = async (id: string) => {
const res = await resolve<Omit<HealthCheck, "source">[] | null>(
IncidentCommander.get(
`/checks?id=eq.${id}&select=*,canaries(id,name,source),agents(id, name)`
`/checks?id=eq.${id}&select=*,canaries(id,name,source),agents(id, name),components:check_component_relationships(components(id,name,icon)),configs:check_config_relationships(configs(id,name,type))`
)
);
return res.data?.[0];
Expand Down
8 changes: 8 additions & 0 deletions src/api/types/health.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { SchemaResourceI } from "../schemaResources";
import { Agent, Avatar, Timestamped } from "../traits";
import { AgentItem } from "./common";
import { ConfigItem } from "./configs";
import { Topology } from "./topology";

export interface HealthChecksResponse {
duration: number;
Expand Down Expand Up @@ -36,6 +38,12 @@ export interface HealthCheck extends Timestamped, Avatar, Agent {
next_runtime?: string;
agents?: AgentItem;
canaries?: SchemaResourceI;
configs: {
configs: Pick<ConfigItem, "id" | "name" | "type">;
}[];
components?: {
components: Pick<Topology, "id" | "name" | "icon">;
}[];
}

export type HealthCheckSummary = Pick<
Expand Down
6 changes: 6 additions & 0 deletions src/components/Canary/CanaryPopup/CheckDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { StatusHistory } from "./StatusHistory/StatusHistory";
import { calculateDefaultTimeRangeValue } from "./Utils/calculateDefaultTimeRangeValue";
import { PopupTabs } from "./tabs";
import { getUptimePercentage } from "./utils";
import CheckLinkedTo from "./CheckLinkedTo";

const CanaryStatusChart = React.lazy(() =>
import("../CanaryStatusChart").then(({ CanaryStatusChart }) => ({
Expand Down Expand Up @@ -183,6 +184,11 @@ export function CheckDetails({ check, ...rest }: CheckDetailsProps) {
label: "Spec",
content: <CanaryCheckDetailsSpecTab check={check} />,
class: `flex-1 flex flex-col overflow-y-auto border border-gray-300 ${mixins.appleScrollbar}`
},
related: {
label: "Linked to",
content: <CheckLinkedTo check={check} />,
class: `flex-1 flex flex-col overflow-y-auto border border-gray-300 ${mixins.appleScrollbar}`
}
}}
/>
Expand Down
107 changes: 107 additions & 0 deletions src/components/Canary/CanaryPopup/CheckLinkedTo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { ColumnDef } from "@tanstack/react-table";
import { useMemo } from "react";
import { useNavigate } from "react-router-dom";
import { HealthCheck } from "../../../api/types/health";
import { DataTable } from "../../DataTable";
import { Icon } from "../../Icon";

type CheckRelationshipsComponent = {
relationship: "component";
name: string;
id: string;
icon?: string;
};

type CheckRelationshipsConfig = {
relationship: "config";
name: string;
id: string;
type?: string;
};

type CheckRelationshipsRow =
| CheckRelationshipsComponent
| CheckRelationshipsConfig;

const columns: ColumnDef<CheckRelationshipsRow>[] = [
{
id: "Name",
header: "Name",
cell: ({ row }) => {
const { name } = row.original;
const icon =
row.original.relationship === "component"
? row.original.icon
: row.original.type;

return (
<div className="flex items-center">
{icon && (
<Icon name={icon} className="mr-2 h-5 w-5 " secondary={name} />
)}
{name}
</div>
);
}
},
{
id: "Type",
header: "Type",
cell: ({ row }) => {
const { relationship } = row.original;
return relationship === "config" ? "Config" : "Component";
}
}
];

type CheckRelationshipsProps = {
check: Partial<HealthCheck>;
};

export default function CheckLinkedTo({ check }: CheckRelationshipsProps) {
const navigate = useNavigate();

const items = useMemo(() => {
const combined: CheckRelationshipsRow[] = [
...(check.components
? check.components?.map((component) => ({
relationship: "component" as const,
name: component.components.name,
id: component.components.id,
icon: component.components.icon
}))
: []),
...(check.configs
? check.configs?.map((config) => ({
relationship: "config" as const,
name: config.configs.name,
id: config.configs.id,
type: config.configs.type
}))
: [])
];
return combined;
}, [check.components, check.configs]);

const handleRowClick = (row: CheckRelationshipsRow) => {
if (row.relationship === "component") {
navigate(`/topology/${row.id}`);
} else {
navigate(`/configs/${row.id}`);
}
};

if (!check || items.length === 0) {
return null;
}

return (
<div className="flex flex-col">
<DataTable
handleRowClick={(row) => handleRowClick(row.original)}
columns={columns}
data={items}
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { render, screen } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import CheckLinkedTo from "../CheckLinkedTo";

describe("CheckLinkedTo", () => {
const mockCheck = {
components: [
{ components: { name: "Component 1", id: "1", icon: "icon1" } },
{ components: { name: "Component 2", id: "2", icon: "icon2" } }
],
configs: [
{ configs: { name: "Config 1", id: "3", type: "type1" } },
{ configs: { name: "Config 2", id: "4", type: "type2" } }
]
};

it("renders correctly", () => {
render(
<MemoryRouter>
<CheckLinkedTo check={mockCheck} />
</MemoryRouter>
);

expect(
screen.getByRole("cell", {
name: "Component 1"
})
).toBeInTheDocument();
expect(
screen.getByRole("cell", { name: /Component 2/i })
).toBeInTheDocument();
expect(screen.getByRole("cell", { name: /Config 1/i })).toBeInTheDocument();
expect(screen.getByRole("cell", { name: /Config 2/i })).toBeInTheDocument();
});
});

0 comments on commit 38b4188

Please sign in to comment.