diff --git a/.github/workflows/end-to-end-test.yml b/.github/workflows/end-to-end-test.yml
index a74408be..f7412f11 100644
--- a/.github/workflows/end-to-end-test.yml
+++ b/.github/workflows/end-to-end-test.yml
@@ -136,6 +136,7 @@ jobs:
- name: Upload playwright report
uses: actions/upload-artifact@v3
+ if: always()
with:
name: playwright-report
path: playwright-report/
diff --git a/playwright.config.js b/playwright.config.js
index 294d54e4..c88309c9 100644
--- a/playwright.config.js
+++ b/playwright.config.js
@@ -42,7 +42,8 @@ const config = {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
- ignoreHTTPSErrors: true
+ ignoreHTTPSErrors: true,
+ screenshot: 'only-on-failure'
},
/* Configure projects for major browsers */
@@ -101,7 +102,7 @@ const config = {
],
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
- // outputDir: 'test-results/',
+ outputDir: 'test-results/',
/* Run your local dev server before starting the tests */
// webServer: {
diff --git a/src/__tests__/TagPage/VulnerabilitiesDetails.test.js b/src/__tests__/TagPage/VulnerabilitiesDetails.test.js
index 13d3cdff..c8dcadc6 100644
--- a/src/__tests__/TagPage/VulnerabilitiesDetails.test.js
+++ b/src/__tests__/TagPage/VulnerabilitiesDetails.test.js
@@ -586,6 +586,22 @@ describe('Vulnerabilties page', () => {
expect(await screen.findByTestId('export-excel-menuItem')).not.toBeInTheDocument();
});
+ it('should expand/collapse the list of CVEs', async () => {
+ jest
+ .spyOn(api, 'get')
+ .mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } })
+ .mockResolvedValueOnce({ status: 200, data: { data: mockCVEList } });
+ render();
+ await waitFor(() => expect(screen.getAllByText('Vulnerabilities')).toHaveLength(1));
+ await waitFor(() => expect(screen.getAllByText('Fixed in')).toHaveLength(20));
+ const collapseListBtn = await screen.findAllByTestId('ViewHeadlineIcon');
+ fireEvent.click(collapseListBtn[0]);
+ expect(await screen.findByText('Fixed in')).not.toBeVisible();
+ const expandListBtn = await screen.findAllByTestId('ViewAgendaIcon');
+ fireEvent.click(expandListBtn[0]);
+ await waitFor(() => expect(screen.getAllByText('Fixed in')).toHaveLength(20));
+ });
+
it('should handle fixed CVE query errors', async () => {
jest
.spyOn(api, 'get')
diff --git a/src/components/Shared/VulnerabilityCard.jsx b/src/components/Shared/VulnerabilityCard.jsx
index 0ee3b7cd..ea3a0a69 100644
--- a/src/components/Shared/VulnerabilityCard.jsx
+++ b/src/components/Shared/VulnerabilityCard.jsx
@@ -66,13 +66,18 @@ const useStyles = makeStyles((theme) => ({
cursor: 'pointer',
textAlign: 'center'
},
+ dropdownCVE: {
+ color: '#1479FF',
+ cursor: 'pointer'
+ },
vulnerabilityCardDivider: {
margin: '1rem 0'
}
}));
function VulnerabilitiyCard(props) {
const classes = useStyles();
- const { cve, name, platform } = props;
+ const { cve, name, platform, expand } = props;
+ const [openCVE, setOpenCVE] = useState(expand);
const [openDesc, setOpenDesc] = useState(false);
const [openFixed, setOpenFixed] = useState(false);
const [loadingFixed, setLoadingFixed] = useState(true);
@@ -122,6 +127,10 @@ function VulnerabilitiyCard(props) {
};
}, [openFixed, pageNumber]);
+ useEffect(() => {
+ setOpenCVE(expand);
+ }, [expand]);
+
const loadMore = () => {
if (loadingFixed || isEndOfList) return;
setPageNumber((pageNumber) => pageNumber + 1);
@@ -166,49 +175,56 @@ function VulnerabilitiyCard(props) {
+ {!openCVE ? (
+ setOpenCVE(!openCVE)} />
+ ) : (
+ setOpenCVE(!openCVE)} />
+ )}
{cve.id}
-
- {cve.title}
-
-
- setOpenFixed(!openFixed)}>
- {!openFixed ? (
-
- ) : (
-
- )}
- Fixed in
-
-
-
- {loadingFixed ? (
- 'Loading...'
+
+
+ {cve.title}
+
+
+ setOpenFixed(!openFixed)}>
+ {!openFixed ? (
+
) : (
-
- {renderFixedVer()}
- {renderLoadMore()}
-
+
)}
-
-
- setOpenDesc(!openDesc)}>
- {!openDesc ? (
-
- ) : (
-
- )}
- Description
-
-
-
-
- {cve.description}
-
-
+ Fixed in
+
+
+
+ {loadingFixed ? (
+ 'Loading...'
+ ) : (
+
+ {renderFixedVer()}
+ {renderLoadMore()}
+
+ )}
+
+
+ setOpenDesc(!openDesc)}>
+ {!openDesc ? (
+
+ ) : (
+
+ )}
+ Description
+
+
+
+
+ {cve.description}
+
+
+
diff --git a/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx b/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx
index 1872f6a0..9b7ba323 100644
--- a/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx
+++ b/src/components/Tag/Tabs/VulnerabilitiesDetails.jsx
@@ -9,6 +9,7 @@ import {
Stack,
Typography,
InputBase,
+ ToggleButton,
Menu,
MenuItem,
Divider,
@@ -26,6 +27,8 @@ import DownloadIcon from '@mui/icons-material/Download';
import * as XLSX from 'xlsx';
import exportFromJSON from 'export-from-json';
+import ViewHeadlineIcon from '@mui/icons-material/ViewHeadline';
+import ViewAgendaIcon from '@mui/icons-material/ViewAgenda';
import VulnerabilitiyCard from '../../Shared/VulnerabilityCard';
@@ -71,6 +74,17 @@ const useStyles = makeStyles((theme) => ({
border: '0.063rem solid #E7E7E7',
borderRadius: '0.625rem'
},
+ view: {
+ alignContent: 'right',
+ variant: 'outlined'
+ },
+ viewModes: {
+ position: 'relative',
+ maxWidth: '100%',
+ flexDirection: 'row',
+ alignItems: 'right',
+ justifyContent: 'right'
+ },
searchIcon: {
color: '#52637A',
paddingRight: '3%'
@@ -87,9 +101,6 @@ const useStyles = makeStyles((theme) => ({
opacity: '1'
}
},
- export: {
- alignContent: 'right'
- },
popper: {
width: '100%',
overflow: 'hidden',
@@ -117,6 +128,8 @@ function VulnerabilitiesDetails(props) {
const [anchorExport, setAnchorExport] = useState(null);
const openExport = Boolean(anchorExport);
+ const [selectedViewMore, setSelectedViewMore] = useState(true);
+
const getCVERequestName = () => {
return digest !== '' ? `${name}@${digest}` : `${name}:${tag}`;
};
@@ -263,7 +276,7 @@ function VulnerabilitiesDetails(props) {
const renderCVEs = () => {
return !isEmpty(cveData) ? (
cveData.map((cve, index) => {
- return ;
+ return ;
})
) : (
{!isLoading && No Vulnerabilities }
@@ -286,14 +299,36 @@ function VulnerabilitiesDetails(props) {
Vulnerabilities
-
-
-
- }
- />
+
+
+
+
+ }
+ />
+ setSelectedViewMore(false)}
+ >
+
+
+ setSelectedViewMore(true)}
+ >
+
+
+