Skip to content

Commit

Permalink
Add advisory details page
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosthe19916 committed Mar 8, 2024
1 parent d3d55bb commit e896632
Show file tree
Hide file tree
Showing 26 changed files with 805 additions and 85 deletions.
19 changes: 18 additions & 1 deletion frontend/client/src/app/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import React, { Suspense, lazy } from "react";
import { useRoutes } from "react-router-dom";
import { useParams, useRoutes } from "react-router-dom";

import { Bullseye, Spinner } from "@patternfly/react-core";

const Home = lazy(() => import("./pages/home"));
const AdvisoryList = lazy(() => import("./pages/advisory-list"));
const AdvisoryDetails = lazy(() => import("./pages/advisory-details"));

export enum PathParam {
ADVISORY_ID = "advisoryId",
CVE_ID = "cveId",
SBOM_ID = "sbomId",
PACKAGE_ID = "packageId",
}

export const AppRoutes = () => {
const allRoutes = useRoutes([
{ path: "/", element: <Home /> },
{ path: "/advisories", element: <AdvisoryList /> },
{
path: `/advisories/:${PathParam.ADVISORY_ID}`,
element: <AdvisoryDetails />,
},
]);

return (
Expand All @@ -24,3 +36,8 @@ export const AppRoutes = () => {
</Suspense>
);
};

export const useRouteParams = (pathParam: PathParam) => {
const params = useParams();
return params[pathParam];
};
28 changes: 23 additions & 5 deletions frontend/client/src/app/api/model-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,42 @@ import {
} from "@patternfly/react-tokens";

import { Severity } from "./models";
import { ProgressProps } from "@patternfly/react-core";

type ListType = {
[key in Severity]: {
color: { name: string; value: string; var: string };
shieldIconColor: { name: string; value: string; var: string };
progressProps: Pick<ProgressProps, "variant">;
};
};

export const severityList: ListType = {
low: {
color: lowColor,
shieldIconColor: lowColor,
progressProps: { variant: undefined },
},
moderate: {
color: moderateColor,
shieldIconColor: moderateColor,
progressProps: { variant: "warning" },
},
important: {
color: importantColor,
shieldIconColor: importantColor,
progressProps: { variant: "danger" },
},
critical: {
color: criticalColor,
shieldIconColor: criticalColor,
progressProps: { variant: "danger" },
},
};

export const severityFromNumber = (score: number): Severity => {
if (score >= 9.0) {
return "critical";
} else if (score >= 7.0) {
return "important";
} else if (score >= 4.0) {
return "moderate";
} else {
return "low";
}
};
25 changes: 21 additions & 4 deletions frontend/client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,29 @@ export type Severity = "low" | "moderate" | "important" | "critical";

export interface Advisory {
id: string;
severity: Severity;
aggregated_severity: Severity;
revision_date: string;
vulnerabilities: { [key in Severity]: number };
vulnerabilities_count: { [key in Severity]: number };
vulnerabilities: AdvisoryVulnerability[];
metadata: {
title: string;
category: string;
publisher: {
name: string;
namespace: string;
contact_details: string;
issuing_authority: string;
};
tracking: {
status: string;
initial_release_date: string;
current_release_date: string;
};
references: {
url: string;
label?: string;
}[];
notes: string[];
};
}

Expand All @@ -52,7 +70,6 @@ export interface AdvisoryVulnerability {
title: string;
discovery_date: string;
release_date: string;
revision_date: string;
score: number;
cwe: number;
cwe: string;
}
8 changes: 7 additions & 1 deletion frontend/client/src/app/api/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ export const getAdvisoryById = (id: number | string) => {
.then((response) => response.data);
};

export const getAdvisorySourceById = (id: number | string) => {
return axios
.get<string>(`${ADVISORIES}/${id}/source`)
.then((response) => response.data);
};

export const downloadAdvisoryById = (id: number | string) => {
return axios.get(`${ADVISORIES}/${id}/source`, {
return axios.get<string>(`${ADVISORIES}/${id}/source`, {
responseType: "arraybuffer",
headers: { Accept: "text/plain", responseType: "blob" },
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const SeverityRenderer: React.FC<SeverityRendererProps> = ({
style={{ whiteSpace: "nowrap" }}
>
<FlexItem>
<ShieldIcon color={severityProps.color.value} />
<ShieldIcon color={severityProps.shieldIconColor.value} />
</FlexItem>
{showLabel && (
<FlexItem>{value.charAt(0).toUpperCase() + value.slice(1)}</FlexItem>
Expand Down
5 changes: 3 additions & 2 deletions frontend/client/src/app/components/AnalyticsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export const AnalyticsContextProvider: React.FC<IAnalyticsProviderProps> = ({
if (auth) {
const claims = auth.user?.profile;
analytics.identify(claims?.sub, {
organization_id: (claims?.organization as any)?.id,
/* eslint-disable @typescript-eslint/no-explicit-any */
organization_id: ((claims as any)?.organization as any)?.id,
domain: claims?.email?.split("@")[1],
});
}
Expand All @@ -45,7 +46,7 @@ export const AnalyticsContextProvider: React.FC<IAnalyticsProviderProps> = ({
const location = useLocation();
useEffect(() => {
analytics.page();
}, [location]);
}, [analytics, location]);

return (
<AnalyticsContext.Provider value={analytics}>
Expand Down
1 change: 1 addition & 0 deletions frontend/client/src/app/components/ConfirmDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface ConfirmDialogProps {
| "danger"
| "warning"
| "info"
/* eslint-disable @typescript-eslint/no-explicit-any */
| React.ComponentType<any>;
message: string | React.ReactNode;

Expand Down
21 changes: 21 additions & 0 deletions frontend/client/src/app/components/LoadingWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import ErrorState from "@patternfly/react-component-groups/dist/esm/ErrorState";
import { Bullseye, Spinner } from "@patternfly/react-core";

export const LoadingWrapper = (props: {
isFetching: boolean;
fetchError?: Error;
children: React.ReactNode;
}) => {
if (props.isFetching) {
return (
<Bullseye>
<Spinner />
</Bullseye>
);
} else if (props.fetchError) {
return <ErrorState errorTitle="Error" />;
} else {
return props.children;
}
};
1 change: 0 additions & 1 deletion frontend/client/src/app/components/PageDrawerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ export const PageDrawerContent: React.FC<IPageDrawerContentProps> = ({
header = null,
children,
drawerPanelContentProps,
focusKey,
pageKey: localPageKeyProp,
}) => {
const {
Expand Down
30 changes: 30 additions & 0 deletions frontend/client/src/app/components/SeverityProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";

import { Progress } from "@patternfly/react-core";

import { severityFromNumber, severityList } from "@app/api/model-utils";

interface SeverityRendererProps {
value: number;
showLabel?: boolean;
}

export const SeverityProgressBar: React.FC<SeverityRendererProps> = ({
value,
}) => {
const severityType = severityFromNumber(value);
const severityProps = severityList[severityType];

return (
<>
<Progress
aria-labelledby="severity"
size="sm"
max={10}
value={value}
label={`${value}/10`}
{...severityProps.progressProps}
/>
</>
);
};
35 changes: 0 additions & 35 deletions frontend/client/src/app/components/SeverityRenderer.tsx

This file was deleted.

46 changes: 46 additions & 0 deletions frontend/client/src/app/components/SeverityShieldAndText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from "react";

import { Flex, FlexItem } from "@patternfly/react-core";
import ShieldIcon from "@patternfly/react-icons/dist/esm/icons/shield-alt-icon";

import { severityFromNumber, severityList } from "@app/api/model-utils";
import { Severity } from "@app/api/models";

interface SeverityShieldAndTextProps {
value: Severity | number;
showLabel?: boolean;
}

export const SeverityShieldAndText: React.FC<SeverityShieldAndTextProps> = ({
value,
showLabel,
}) => {
let severity: Severity;
if (typeof value === "number") {
severity = severityFromNumber(value);
} else {
severity = value;
}

const severityProps = severityList[severity];

return (
<>
<Flex
spaceItems={{ default: "spaceItemsXs" }}
alignItems={{ default: "alignItemsCenter" }}
flexWrap={{ default: "nowrap" }}
style={{ whiteSpace: "nowrap" }}
>
<FlexItem>
<ShieldIcon color={severityProps.shieldIconColor.value} />
</FlexItem>
{showLabel && (
<FlexItem>
{severity.charAt(0).toUpperCase() + severity.slice(1)}
</FlexItem>
)}
</Flex>
</>
);
};
22 changes: 22 additions & 0 deletions frontend/client/src/app/components/markdownPFComponents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from "react";
import { Components } from "react-markdown";
import { CodeBlock, CodeBlockCode, Text } from "@patternfly/react-core";
import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";

export const markdownPFComponents: Components = {
h1: (props) => <Text component="h1" {...props} />,
h2: (props) => <Text component="h2" {...props} />,
h3: (props) => <Text component="h3" {...props} />,
h4: (props) => <Text component="h4" {...props} />,
h5: (props) => <Text component="h5" {...props} />,
h6: (props) => <Text component="h6" {...props} />,
p: (props) => <Text component="p" {...props} />,
a: (props) => <Text component="a" {...props} />,
small: (props) => <Text component="small" {...props} />,
blockquote: (props) => <Text component="blockquote" {...props} />,
pre: (props) => (
<CodeBlock className={spacing.mbMd}>
<CodeBlockCode {...props} />
</CodeBlock>
),
};
29 changes: 29 additions & 0 deletions frontend/client/src/app/components/notes-markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";

import { Text, TextContent } from "@patternfly/react-core";
import ReactMarkdown from "react-markdown";
import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";
import { markdownPFComponents } from "./markdownPFComponents";

interface NotesMarkdownProps {
isCompact?: boolean;
notes: {
category: string;
text: string;
title: string;
}[];
}

export const NotesMarkdown: React.FC<NotesMarkdownProps> = ({
isCompact,
notes,
}) => {
return notes.map((e, index) => (
<TextContent key={index} className={spacing.mbMd}>
<Text component={isCompact ? "h4" : "h1"}>
{e.title} ({e.category.replace("_", " ")})
</Text>
<ReactMarkdown components={markdownPFComponents}>{e.text}</ReactMarkdown>
</TextContent>
));
};
Loading

0 comments on commit e896632

Please sign in to comment.