Skip to content

Commit

Permalink
feat: Dashbar add fetch data (#1617)
Browse files Browse the repository at this point in the history
  • Loading branch information
AsToNlele authored Apr 11, 2022
1 parent e8cfd62 commit f49dfd9
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 88 deletions.
1 change: 1 addition & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
"cvssVector.popoverTitle": "vector breakdown",
"cvssVector.value": "Value",
"cvssVector.vector": "base score",
"dashbarAnnouncementTitle": "Announcement",
"dashbarCriticalSeverityTitle": "CVEs with critical severity",
"dashbarImportantSeverityTitle": "CVEs with important severity",
"dashbarKnownExploitsTitle": "CVEs with known exploits",
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@redhat-cloud-services/frontend-components-pdf-generator": "2.6.7",
"@redhat-cloud-services/frontend-components-translations": "3.2.3",
"@redhat-cloud-services/frontend-components-utilities": "3.2.8",
"@redhat-cloud-services/vulnerabilities-client": "^1.0.104",
"@redhat-cloud-services/vulnerabilities-client": "1.0.106",
"axios": "^0.26.1",
"classnames": "^2.2.5",
"dot": "^1.1.3",
Expand Down
135 changes: 91 additions & 44 deletions src/Components/SmartComponents/Dashbar/Dashbar.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Card, Grid, GridItem, StackItem, Stack, Alert, CardBody, Text } from '@patternfly/react-core';
import { Main } from '@redhat-cloud-services/frontend-components/Main';
import { SecurityIcon } from '@patternfly/react-icons';
Expand All @@ -10,6 +10,9 @@ import { FormattedMessage } from 'react-intl';
import messages from '../../../Messages';
import propTypes from 'prop-types';
import { buildActiveFilters, removeFilters } from '../../../Helpers/TableToolbarHelper';
import { getAnnouncement, getDashbar } from '../../../Helpers/APIHelper';
import WithLoader, { LoaderType } from '../../PresentationalComponents/WithLoader/WithLoader';
import { useIntl } from 'react-intl';

const DashbarItem = ({ title, count, impact, onLinkClick, hasIcon }) => {
return (
Expand All @@ -33,6 +36,8 @@ const DashbarItem = ({ title, count, impact, onLinkClick, hasIcon }) => {
);
};

export { DashbarItem };

DashbarItem.propTypes = {
title: propTypes.node,
count: propTypes.number.isRequired,
Expand All @@ -42,8 +47,12 @@ DashbarItem.propTypes = {
};

const Dashbar = () => {
const intl = useIntl();
const dispatch = useDispatch();
const [urlParameters] = useUrlParams([CVES_ALLOWED_PARAMS]);
const [dashbar, setDashbar] = useState({});
const [announcement, setAnnouncement] = useState({});
const [isDashbarLoading, setDashbarLoading] = useState(true);

const parameters = useSelector(
({ CVEsStore }) => CVEsStore.parameters
Expand All @@ -60,54 +69,92 @@ const Dashbar = () => {
removeFilters(chips, apply, true, filterParams);
};

useEffect(() => {
const fetchAnnouncements = async () => {
let data = await getAnnouncement();
setAnnouncement(data);
};

const fetchDashbar = async () => {
let data = await getDashbar();
setDashbar(data);
setDashbarLoading(false);
};

fetchAnnouncements();
fetchDashbar();
}, []);

return (urlParameters?.dashbar === 'true' &&
<Main style={{ paddingBottom: 0 }}>
<Stack hasGutter>
<StackItem>
<Grid hasGutter>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarKnownExploitsTitle} />}
count={12}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, known_exploit: 'true' })}
/>
</GridItem>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarSecurityRulesTitle} />}
count={5}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, rule_presence: 'true' })}
/>
</GridItem>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarCriticalVulnerabilitiesTitle} />}
count={5}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, impact: '7' })}
impact="Critical"
hasIcon
/>
</GridItem>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarImportantVulnerabilitiesTitle} />}
count={5}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, impact: '5' })}
impact="Important"
hasIcon
/>
</GridItem>
</Grid>
</StackItem>
<StackItem>
<Alert
variant="warning"
isInline
title="This is an announcement"
>
Lorem ipsum
</Alert>
{!isDashbarLoading ? (
<Grid hasGutter>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarKnownExploitsTitle} />}
count={dashbar?.exploitable_cves}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, known_exploit: 'true' })}
/>
</GridItem>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarSecurityRulesTitle} />}
count={dashbar?.cves_with_rule}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, rule_presence: 'true' })}
/>
</GridItem>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarCriticalVulnerabilitiesTitle} />}
count={dashbar?.critical_cves}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, impact: '7' })}
impact="Critical"
hasIcon
/>
</GridItem>
<GridItem span={12} md={3}>
<DashbarItem
title={<FormattedMessage {...messages.dashbarImportantVulnerabilitiesTitle} />}
count={dashbar?.important_cves}
onLinkClick={() => applyOnly({ ...CVES_DEFAULT_FILTERS, impact: '5' })}
impact="Important"
hasIcon
/>
</GridItem>
</Grid>
) : (
<Grid hasGutter>
<GridItem span={12} md={3}>
<WithLoader isLoading={isDashbarLoading}
variant={LoaderType.inlineSkeleton} style={{ height: '100px' }} />
</GridItem>
<GridItem span={12} md={3}>
<WithLoader isLoading={isDashbarLoading}
variant={LoaderType.inlineSkeleton} style={{ height: '100px' }} />
</GridItem>
<GridItem span={12} md={3}>
<WithLoader isLoading={isDashbarLoading}
variant={LoaderType.inlineSkeleton} style={{ height: '100px' }} />
</GridItem>
<GridItem span={12} md={3}>
<WithLoader isLoading={isDashbarLoading}
variant={LoaderType.inlineSkeleton} style={{ height: '100px' }} />
</GridItem>
</Grid>
)}
</StackItem>
{announcement?.message && (
<StackItem>
<Alert
variant="warning"
isInline
title={intl.formatMessage(messages.dashbarAnnouncementTitle)}
>{announcement.message}
</Alert>
</StackItem>
)}
</Stack>
</Main>
);
Expand Down
63 changes: 38 additions & 25 deletions src/Components/SmartComponents/Dashbar/Dashbar.test.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,66 @@
import Dashbar from './Dashbar';
import { Card, Grid } from '@patternfly/react-core';
import toJson from 'enzyme-to-json';
import { mountWithIntl } from '../../../Helpers/MiscHelper';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { BrowserRouter as Router } from 'react-router-dom';
import Dashbar from "./Dashbar";
import { Card, Grid } from "@patternfly/react-core";
import toJson from "enzyme-to-json";
import { mountWithIntl } from "../../../Helpers/MiscHelper";
import { Provider } from "react-redux";
import configureStore from "redux-mock-store";
import { BrowserRouter as Router } from "react-router-dom";
import { DashbarItem } from './Dashbar'

jest.mock("react-redux", () => ({
...jest.requireActual("react-redux"),
useSelector: jest.fn()
useSelector: jest.fn(),
}));

const mockStore = configureStore([store => next => action => { }]);
const mockStore = configureStore([(store) => (next) => (action) => { }]);
let store = mockStore({});

jest.mock('../../../Helpers/MiscHelper', () => ({
...jest.requireActual('../../../Helpers/MiscHelper'),
useUrlParams: () => [{ dashbar: "true" }, jest.fn()]
jest.mock("../../../Helpers/MiscHelper", () => ({
...jest.requireActual("../../../Helpers/MiscHelper"),
useUrlParams: () => [{ dashbar: "true" }, jest.fn()],
}));


jest.mock("../../../Helpers/APIHelper", () => ({
...jest.requireActual("../../../Helpers/APIHelper"),
getAnnouncement: () => new Promise((resolve) => resolve({ message: "Message test!" })),
getDashbar: () => new Promise((resolve) => resolve({ exploitable_cves: 1, cves_with_rule: 2, critical_cves: 3, important_cves: 4 }))
}))

describe('Dashbar', () => {
it('Should match the snapshot', () => {
const wrapper = mountWithIntl(
describe("Dashbar", () => {
it("Should match the snapshot", async () => {

const wrapper = await mountWithIntl(
<Provider store={store}>
<Router>
<Dashbar />
</Router>
</Provider>);
</Provider>
);
wrapper.update()
expect(toJson(wrapper)).toMatchSnapshot();
})
it('Should render Grid with props hasGutter = true', () => {
const wrapper = mountWithIntl(
});
it("Should render Grid with props hasGutter = true", async () => {
const wrapper = await mountWithIntl(
<Provider store={store}>
<Router>
<Dashbar />
</Router>
</Provider>
);
wrapper.update()
expect(wrapper.find(Grid)).toHaveLength(1);
expect(wrapper.find(Grid).prop('hasGutter')).toBeTruthy();
expect(wrapper.find(Grid).prop("hasGutter")).toBeTruthy();
});
it('Should have 4 card items', () => {
const wrapper = mountWithIntl(
it("Should have 4 DashbarItems", async () => {
const wrapper = await mountWithIntl(
<Provider store={store}>
<Router>
<Dashbar />
</Router>
</Provider>
);
expect(wrapper.find(Card)).toHaveLength(4);
})
})
wrapper.update()
expect(wrapper.find(DashbarItem)).toHaveLength(4);
});
});
Loading

0 comments on commit f49dfd9

Please sign in to comment.