Skip to content

Commit

Permalink
Merge pull request #1595 from flanksource/1594-Catalog-relationships-…
Browse files Browse the repository at this point in the history
…--handle-bidirectional-relationships

1594-Catalog-relationships---handle-bidirectional-relationships
  • Loading branch information
moshloop authored Jan 5, 2024
2 parents 72c49cc + 3284747 commit b026f90
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 70 deletions.
16 changes: 9 additions & 7 deletions src/api/query-hooks/useComponentConfigRelationshipQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ export function useComponentConfigRelationshipQuery({
configId?: string;
hideDeleted?: boolean;
}) {
return useQuery(
componentConfigRelationshipQueryKey({ topologyId, configId, hideDeleted }),
() => getConfigsBy({ topologyId, configId, hideDeleted }),
{
enabled: !!topologyId || !!configId
}
);
return useQuery({
queryKey: componentConfigRelationshipQueryKey({
topologyId,
configId,
hideDeleted
}),
queryFn: () => getConfigsBy({ topologyId, configId, hideDeleted }),
enabled: !!topologyId || !!configId
});
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CellContext } from "@tanstack/react-table";
import { Age } from "../../../../ui/Age";
import { ConfigChange } from "../../../../api/types/configs";
import { Age } from "../../../../../ui/Age";
import { ConfigChange } from "../../../../../api/types/configs";

export default function ConfigChangeAgeCell({
row,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CellContext } from "@tanstack/react-table";
import { ViewType } from "../../../../types";
import { ConfigDetailsChanges } from "../../../Configs/Changes/ConfigDetailsChanges/ConfigDetailsChanges";
import { ConfigChange } from "../../../../api/types/configs";
import { ViewType } from "../../../../../types";
import { ConfigDetailsChanges } from "../../../Changes/ConfigDetailsChanges/ConfigDetailsChanges";
import { ConfigChange } from "../../../../../api/types/configs";

export default function ConfigChangeNameCell({
row,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { ColumnDef } from "@tanstack/table-core";
import { useEffect, useMemo, useState } from "react";
import { useGetConfigChangesByConfigIdQuery } from "../../../api/query-hooks";
import { ConfigChange } from "../../../api/types/configs";
import { CreatedAtCell } from "../../../ui/table/DateCells";
import PillBadge from "../../Badge/PillBadge";
import CollapsiblePanel from "../../CollapsiblePanel";
import EmptyState from "../../EmptyState";
import { Icon } from "../../Icon";
import { InfiniteTable } from "../../InfiniteTable/InfiniteTable";
import TextSkeletonLoader from "../../SkeletonLoader/TextSkeletonLoader";
import Title from "../../Title/title";
import { toastError } from "../../Toast/toast";
import { useGetConfigChangesByConfigIdQuery } from "../../../../api/query-hooks";
import { ConfigChange } from "../../../../api/types/configs";
import { CreatedAtCell } from "../../../../ui/table/DateCells";
import PillBadge from "../../../Badge/PillBadge";
import CollapsiblePanel from "../../../CollapsiblePanel";
import EmptyState from "../../../EmptyState";
import { Icon } from "../../../Icon";
import { InfiniteTable } from "../../../InfiniteTable/InfiniteTable";
import TextSkeletonLoader from "../../../SkeletonLoader/TextSkeletonLoader";
import Title from "../../../Title/title";
import { toastError } from "../../../Toast/toast";
import ConfigChangeNameCell from "./Cells/ConfigChangeNameCell";

type Props = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { MdOutlineInsights } from "react-icons/md";
import { useGetConfigInsights } from "../../../api/query-hooks";
import CollapsiblePanel from "../../CollapsiblePanel";
import InsightsDetails from "../../Insights/Insights";
import Title from "../../Title/title";
import PillBadge from "../../Badge/PillBadge";
import { useGetConfigInsights } from "../../../../api/query-hooks";
import CollapsiblePanel from "../../../CollapsiblePanel";
import InsightsDetails from "../../../Insights/Insights";
import Title from "../../../Title/title";
import PillBadge from "../../../Badge/PillBadge";

type Props = {
configID: string;
Expand Down
16 changes: 8 additions & 8 deletions src/components/Configs/Sidebar/ConfigSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useCallback, useState } from "react";
import { useParams } from "react-router-dom";
import ConfigChanges from "../../Sidebars/ConfigChanges";
import ConfigInsights from "../../Sidebars/ConfigInsights";
import Configs from "../../Sidebars/configs";
import Incidents from "../../Sidebars/incidents";
import Incidents from "../../Incidents/Sidebars/incidents";
import { PlaybookRunsSidePanel } from "../../Playbooks/Runs/PlaybookRunsSidePanel";
import SlidingSideBar from "../../SlidingSideBar";
import { ConfigDetails } from "./ConfigDetails";
import ConfigActionBar from "./ConfigActionBar";
import { useCallback, useState } from "react";
import { PlaybookRunsSidePanel } from "../../Playbooks/Runs/PlaybookRunsSidePanel";
import ConfigChanges from "./ConfigChanges";
import { ConfigDetails } from "./ConfigDetails";
import ConfigInsights from "./ConfigInsights";
import ConfigsPanel from "./ConfigsPanel";

type SidePanels =
| "ConfigDetails"
Expand Down Expand Up @@ -79,7 +79,7 @@ export default function ConfigSidebar() {
panelCollapsedStatusChange(status, "ConfigChanges")
}
/>
<Configs
<ConfigsPanel
configId={id}
isCollapsed={openedPanel !== "Configs"}
onCollapsedStateChange={(status) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import { useEffect, useState } from "react";
import { TbTrash, TbTrashOff } from "react-icons/tb";
import { VscJson } from "react-icons/vsc";
import ReactTooltip from "react-tooltip";
import { useComponentConfigRelationshipQuery } from "../../api/query-hooks/useComponentConfigRelationshipQuery";
import { removeManualComponentConfigRelationship } from "../../api/services/configs";
import { Badge } from "../Badge";
import CollapsiblePanel from "../CollapsiblePanel";
import ConfigLink from "../Configs/ConfigLink/ConfigLink";
import { ConfirmationPromptDialog } from "../Dialogs/ConfirmationPromptDialog";
import EmptyState from "../EmptyState";
import { IconButton } from "../IconButton";
import TextSkeletonLoader from "../SkeletonLoader/TextSkeletonLoader";
import { refreshButtonClickedTrigger } from "../SlidingSideBar";
import Title from "../Title/title";
import { toastError, toastSuccess } from "../Toast/toast";
import TopologyConfigsActionsDropdown from "../Topology/Sidebar/Utils/TopologyConfigsActionsDropdown";
import { useComponentConfigRelationshipQuery } from "../../../api/query-hooks/useComponentConfigRelationshipQuery";
import { removeManualComponentConfigRelationship } from "../../../api/services/configs";
import { Badge } from "../../Badge";
import CollapsiblePanel from "../../CollapsiblePanel";
import { ConfirmationPromptDialog } from "../../Dialogs/ConfirmationPromptDialog";
import EmptyState from "../../EmptyState";
import { IconButton } from "../../IconButton";
import TextSkeletonLoader from "../../SkeletonLoader/TextSkeletonLoader";
import { refreshButtonClickedTrigger } from "../../SlidingSideBar";
import Title from "../../Title/title";
import { toastError, toastSuccess } from "../../Toast/toast";
import TopologyConfigsActionsDropdown from "../../Topology/Sidebar/Utils/TopologyConfigsActionsDropdown";
import ConfigLink from "../ConfigLink/ConfigLink";

type Props = {
topologyId?: string;
Expand All @@ -26,7 +26,7 @@ type Props = {
onCollapsedStateChange?: (isClosed: boolean) => void;
};

export function ConfigsList({
export function ConfigsPanelList({
topologyId,
configId,
hideDeletedConfigs
Expand Down Expand Up @@ -81,13 +81,21 @@ export function ConfigsList({
<ol className="flex flex-col w-full overflow-x-hidden">
{configs.map((config) => (
<li
key={config.config_id}
key={
config.configs.id === configId
? config.related.id
: config.configs.id
}
className={clsx("p-1 relative flex flex-row flex-1", {
hidden: hideDeletedConfigs && config.deleted_at
})}
>
<ConfigLink
config={config.configs}
config={
config.configs.id === configId
? config.related
: config.configs
}
className="overflow-hidden text-ellipsis flex-1 whitespace-nowrap"
/>
{config.deleted_at && (
Expand Down Expand Up @@ -123,7 +131,7 @@ export function ConfigsList({
);
}

export default function Configs({
export default function ConfigsPanel({
isCollapsed,
onCollapsedStateChange,
...props
Expand Down Expand Up @@ -160,6 +168,7 @@ export default function Configs({
className="w-5 h-5 flex items-center justify-center"
roundedClass="rounded-full"
text={configs?.length ?? 0}
title="Total catalog count"
/>
<div className="flex grow text-right justify-center">
<IconButton
Expand All @@ -180,7 +189,7 @@ export default function Configs({
}
>
<div className="flex flex-col">
<ConfigsList {...{ ...props, hideDeletedConfigs }} />
<ConfigsPanelList {...{ ...props, hideDeletedConfigs }} />
</div>
</CollapsiblePanel>
);
Expand Down
171 changes: 171 additions & 0 deletions src/components/Configs/Sidebar/__tests__/ConfigsPanel.unit.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { QueryClient } from "@tanstack/query-core";
import { QueryClientProvider } from "@tanstack/react-query";
import { render, screen } from "@testing-library/react";
import { rest } from "msw";
import { setupServer } from "msw/node";
import { MemoryRouter } from "react-router-dom";
import Config, { ConfigsPanelList } from "../ConfigsPanel";

const server = setupServer(
rest.get("/api/db/config_relationships", (req, res, ctx) => {
return res(
ctx.json([
{
config_id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
related_id: "0189a50f-afca-1425-9e15-56d0af533c76",
relation: "NamespaceConfigMap",
created_at: "2024-01-03T13:30:23.113168+00:00",
updated_at: "2024-01-03T13:30:23.113168+00:00",
deleted_at: null,
selector_id: "",
configs: {
id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
type: "Kubernetes::ConfigMap",
name: "apacheds-ldif",
config_class: "ConfigMap",
deleted_at: null
},
related: {
id: "0189a50f-afca-1425-9e15-56d0af533c76",
type: "Kubernetes::Namespace",
name: "canaries",
config_class: "Namespace",
deleted_at: null
}
},
{
config_id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
related_id: "0189da8a-8407-e486-4824-58b8a060301d",
relation: "NamespaceConfigMap",
created_at: "2024-01-02T13:10:20.943685+00:00",
updated_at: "2024-01-02T13:10:20.943685+00:00",
deleted_at: null,
selector_id: "",
configs: {
id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
type: "Kubernetes::ConfigMap",
name: "apacheds-ldif",
config_class: "ConfigMap",
deleted_at: null
},
related: {
id: "0189da8a-8407-e486-4824-58b8a060301d",
type: "Kubernetes::Namespace",
name: "canaries 1",
config_class: "Namespace",
deleted_at: null
}
},
{
config_id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
related_id: "018a6789-eab0-0d45-ae6e-41de5cc68b92",
relation: "KustomizationConfigMap",
created_at: "2023-12-27T07:26:26.111838+00:00",
updated_at: "2023-12-27T07:26:26.111838+00:00",
deleted_at: null,
selector_id: "",
configs: {
id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
type: "Kubernetes::ConfigMap",
name: "apacheds-ldif",
config_class: "ConfigMap",
deleted_at: null
},
related: {
id: "018a6789-eab0-0d45-ae6e-41de5cc68b92",
type: "Kubernetes::Kustomization",
name: "canaries 2",
config_class: "Kustomization",
deleted_at: null
}
},
{
config_id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
related_id: "01899765-8381-a5d5-dd4f-cb83bc89437d",
relation: "KustomizationConfigMap",
created_at: "2023-12-27T07:26:26.115612+00:00",
updated_at: "2023-12-27T07:26:26.115612+00:00",
deleted_at: null,
selector_id: "",
configs: {
id: "0189a50f-aa44-32b7-0e3b-dc86b37c9236",
type: "Kubernetes::ConfigMap",
name: "apacheds-ldif",
config_class: "ConfigMap",
deleted_at: null
},
related: {
id: "01899765-8381-a5d5-dd4f-cb83bc89437d",
type: "Kubernetes::Kustomization",
name: "canaries 3",
config_class: "Kustomization",
deleted_at: null
}
}
])
);
})
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

const queryClient = new QueryClient({});

describe("ConfigsPanelList", () => {
test("should render the correct config, the config whose config id, isn't the same as the prop", async () => {
render(
<MemoryRouter>
<QueryClientProvider client={queryClient}>
<ConfigsPanelList configId="0189a50f-aa44-32b7-0e3b-dc86b37c9236" />
</QueryClientProvider>
</MemoryRouter>
);

// should render the correct config name, the one that is not the configId
expect(await screen.findByText(/canaries/i)).toBeInTheDocument();
expect(await screen.findByText(/canaries 1/i)).toBeInTheDocument();
expect(await screen.findByText(/canaries 2/i)).toBeInTheDocument();
expect(await screen.findByText(/canaries 3/i)).toBeInTheDocument();

// should have 4 links, with correct configs
expect(screen.getAllByRole("link")).toHaveLength(4);
expect(screen.getAllByRole("link")[0]).toHaveAttribute(
"href",
"/catalog/0189a50f-afca-1425-9e15-56d0af533c76"
);
expect(screen.getAllByRole("link")[1]).toHaveAttribute(
"href",
"/catalog/0189da8a-8407-e486-4824-58b8a060301d"
);
expect(screen.getAllByRole("link")[2]).toHaveAttribute(
"href",
"/catalog/018a6789-eab0-0d45-ae6e-41de5cc68b92"
);
expect(screen.getAllByRole("link")[3]).toHaveAttribute(
"href",
"/catalog/01899765-8381-a5d5-dd4f-cb83bc89437d"
);

// should not render current config, as it is the same as the configId
expect(screen.queryByTestId(/apacheds-ldif/i)).not.toBeInTheDocument();
});
});

describe("ConfigsPanel", () => {
test("should show correct config count", async () => {
render(
<MemoryRouter>
<QueryClientProvider client={queryClient}>
<Config configId="0189a50f-aa44-32b7-0e3b-dc86b37c9236" />
</QueryClientProvider>
</MemoryRouter>
);

expect(
await screen.findByTitle(/Total catalog count/i)
).toBeInTheDocument();
expect(screen.queryByTitle(/Total catalog count/i)).toHaveTextContent("4");
});
});
Loading

0 comments on commit b026f90

Please sign in to comment.