Compare commits
3 Commits
commit-808
...
commit-8f4
Author | SHA1 | Date | |
---|---|---|---|
|
8f4c23bf40 | ||
|
54c764c996 | ||
|
44289c751f |
19
src/api.js
19
src/api.js
@@ -1,11 +1,11 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import { sortByCriteria } from 'utilities/sortCriteria';
|
import { sortByCriteria } from 'utilities/sortCriteria';
|
||||||
import { logoutUser } from 'utilities/authUtilities';
|
import { isAuthenticationEnabled, logoutUser } from 'utilities/authUtilities';
|
||||||
import { host } from 'host';
|
import { host } from 'host';
|
||||||
|
|
||||||
axios.interceptors.request.use((config) => {
|
axios.interceptors.request.use((config) => {
|
||||||
if (config.url.includes(endpoints.authConfig)) {
|
if (config.url.includes(endpoints.authConfig) || !isAuthenticationEnabled()) {
|
||||||
config.withCredentials = false;
|
config.withCredentials = false;
|
||||||
} else {
|
} else {
|
||||||
config.headers['X-ZOT-API-CLIENT'] = 'zot-ui';
|
config.headers['X-ZOT-API-CLIENT'] = 'zot-ui';
|
||||||
@@ -19,6 +19,7 @@ axios.interceptors.response.use(
|
|||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
if (error?.response?.status === 401) {
|
if (error?.response?.status === 401) {
|
||||||
|
if (window.location.pathname.includes('/login')) return Promise.reject(error);
|
||||||
logoutUser();
|
logoutUser();
|
||||||
window.location.replace('/login');
|
window.location.replace('/login');
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
@@ -97,10 +98,18 @@ const endpoints = {
|
|||||||
}
|
}
|
||||||
return `${query}){Tag Page {TotalCount ItemCount} CVEList {Id Title Description Severity PackageList {Name InstalledVersion FixedVersion}}}}`;
|
return `${query}){Tag Page {TotalCount ItemCount} CVEList {Id Title Description Severity PackageList {Name InstalledVersion FixedVersion}}}}`;
|
||||||
},
|
},
|
||||||
imageListWithCVEFixed: (cveId, repoName, { pageNumber = 1, pageSize = 3 }) =>
|
imageListWithCVEFixed: (cveId, repoName, { pageNumber = 1, pageSize = 3 }, filter = {}) => {
|
||||||
`/v2/_zot/ext/search?query={ImageListWithCVEFixed(id:"${cveId}", image:"${repoName}", requestedPage: {limit:${pageSize} offset:${
|
let filterParam = '';
|
||||||
|
if (filter.Os || filter.Arch) {
|
||||||
|
filterParam = `,filter:{`;
|
||||||
|
if (filter.Os) filterParam += ` Os:${!isEmpty(filter.Os) ? `${JSON.stringify(filter.Os)}` : '""'}`;
|
||||||
|
if (filter.Arch) filterParam += ` Arch:${!isEmpty(filter.Arch) ? `${JSON.stringify(filter.Arch)}` : '""'}`;
|
||||||
|
filterParam += '}';
|
||||||
|
}
|
||||||
|
return `/v2/_zot/ext/search?query={ImageListWithCVEFixed(id:"${cveId}", image:"${repoName}", requestedPage: {limit:${pageSize} offset:${
|
||||||
(pageNumber - 1) * pageSize
|
(pageNumber - 1) * pageSize
|
||||||
}}) {Page {TotalCount ItemCount} Results {Tag}}}`,
|
}}${filterParam}) {Page {TotalCount ItemCount} Results {Tag}}}`;
|
||||||
|
},
|
||||||
dependsOnForImage: (name, { pageNumber = 1, pageSize = 15 } = {}) =>
|
dependsOnForImage: (name, { pageNumber = 1, pageSize = 15 } = {}) =>
|
||||||
`/v2/_zot/ext/search?query={BaseImageList(image: "${name}", requestedPage: {limit:${pageSize} offset:${
|
`/v2/_zot/ext/search?query={BaseImageList(image: "${name}", requestedPage: {limit:${pageSize} offset:${
|
||||||
(pageNumber - 1) * pageSize
|
(pageNumber - 1) * pageSize
|
||||||
|
@@ -1,37 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { makeStyles } from '@mui/styles';
|
|
||||||
import { Stack, Typography } from '@mui/material';
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
|
||||||
subtext: {
|
|
||||||
color: '#52637A',
|
|
||||||
fontSize: '0.8125rem',
|
|
||||||
fontWeight: '400',
|
|
||||||
lineHeight: '154%',
|
|
||||||
letterSpacing: '0.025rem',
|
|
||||||
marginBottom: '0'
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
color: '#0F2139',
|
|
||||||
fontSize: '0.8125rem',
|
|
||||||
lineHeight: '154%',
|
|
||||||
fontWeight: '600',
|
|
||||||
letterSpacing: '0.025rem'
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default function TermsOfService(props) {
|
|
||||||
const classes = useStyles();
|
|
||||||
return (
|
|
||||||
<Stack spacing={0}>
|
|
||||||
<Typography variant="caption" className={classes.subtext} align="justify" {...props} pb={6}>
|
|
||||||
By using zot UI, you agree to the Terms of Service. For more information about our privacy practices, see
|
|
||||||
zot's Privacy Policy.
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="caption" className={classes.text} align="center" {...props}>
|
|
||||||
Privacy Policy | Terms of Service
|
|
||||||
</Typography>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -72,7 +72,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
}));
|
}));
|
||||||
function VulnerabilitiyCard(props) {
|
function VulnerabilitiyCard(props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { cve, name } = props;
|
const { cve, name, platform } = props;
|
||||||
const [openDesc, setOpenDesc] = useState(false);
|
const [openDesc, setOpenDesc] = useState(false);
|
||||||
const [openFixed, setOpenFixed] = useState(false);
|
const [openFixed, setOpenFixed] = useState(false);
|
||||||
const [loadingFixed, setLoadingFixed] = useState(true);
|
const [loadingFixed, setLoadingFixed] = useState(true);
|
||||||
@@ -90,7 +90,12 @@ function VulnerabilitiyCard(props) {
|
|||||||
setLoadingFixed(true);
|
setLoadingFixed(true);
|
||||||
api
|
api
|
||||||
.get(
|
.get(
|
||||||
`${host()}${endpoints.imageListWithCVEFixed(cve.id, name, { pageNumber, pageSize: CVE_FIXEDIN_PAGE_SIZE })}`,
|
`${host()}${endpoints.imageListWithCVEFixed(
|
||||||
|
cve.id,
|
||||||
|
name,
|
||||||
|
{ pageNumber, pageSize: CVE_FIXEDIN_PAGE_SIZE },
|
||||||
|
platform ? { Os: platform.Os, Arch: platform.Arch } : {}
|
||||||
|
)}`,
|
||||||
abortController.signal
|
abortController.signal
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
@@ -73,7 +73,7 @@ function VulnerabilitiesDetails(props) {
|
|||||||
const [cveData, setCveData] = useState([]);
|
const [cveData, setCveData] = useState([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const abortController = useMemo(() => new AbortController(), []);
|
const abortController = useMemo(() => new AbortController(), []);
|
||||||
const { name, tag } = props;
|
const { name, tag, digest, platform } = props;
|
||||||
|
|
||||||
// pagination props
|
// pagination props
|
||||||
const [cveFilter, setCveFilter] = useState('');
|
const [cveFilter, setCveFilter] = useState('');
|
||||||
@@ -81,11 +81,15 @@ function VulnerabilitiesDetails(props) {
|
|||||||
const [isEndOfList, setIsEndOfList] = useState(false);
|
const [isEndOfList, setIsEndOfList] = useState(false);
|
||||||
const listBottom = useRef(null);
|
const listBottom = useRef(null);
|
||||||
|
|
||||||
|
const getCVERequestName = () => {
|
||||||
|
return digest !== '' ? `${name}@${digest}` : `${name}:${tag}`;
|
||||||
|
};
|
||||||
|
|
||||||
const getPaginatedCVEs = () => {
|
const getPaginatedCVEs = () => {
|
||||||
api
|
api
|
||||||
.get(
|
.get(
|
||||||
`${host()}${endpoints.vulnerabilitiesForRepo(
|
`${host()}${endpoints.vulnerabilitiesForRepo(
|
||||||
`${name}:${tag}`,
|
getCVERequestName(),
|
||||||
{ pageNumber, pageSize: EXPLORE_PAGE_SIZE },
|
{ pageNumber, pageSize: EXPLORE_PAGE_SIZE },
|
||||||
cveFilter
|
cveFilter
|
||||||
)}`,
|
)}`,
|
||||||
@@ -171,7 +175,7 @@ function VulnerabilitiesDetails(props) {
|
|||||||
const renderCVEs = () => {
|
const renderCVEs = () => {
|
||||||
return !isEmpty(cveData) ? (
|
return !isEmpty(cveData) ? (
|
||||||
cveData.map((cve, index) => {
|
cveData.map((cve, index) => {
|
||||||
return <VulnerabilitiyCard key={index} cve={cve} name={name} />;
|
return <VulnerabilitiyCard key={index} cve={cve} name={name} platform={platform} />;
|
||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
<div>{!isLoading && <Typography className={classes.none}> No Vulnerabilities </Typography>}</div>
|
<div>{!isLoading && <Typography className={classes.none}> No Vulnerabilities </Typography>}</div>
|
||||||
|
@@ -59,7 +59,6 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
lineHeight: '1.5rem',
|
lineHeight: '1.5rem',
|
||||||
color: '#52637A',
|
color: '#52637A',
|
||||||
padding: '1rem 0 0 0',
|
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
[theme.breakpoints.down('md')]: {
|
[theme.breakpoints.down('md')]: {
|
||||||
padding: '0.5rem 0 0 0',
|
padding: '0.5rem 0 0 0',
|
||||||
@@ -209,7 +208,14 @@ function TagDetails() {
|
|||||||
case 'IsDependentOn':
|
case 'IsDependentOn':
|
||||||
return <IsDependentOn name={imageDetailData.name} digest={selectedManifest.digest} />;
|
return <IsDependentOn name={imageDetailData.name} digest={selectedManifest.digest} />;
|
||||||
case 'Vulnerabilities':
|
case 'Vulnerabilities':
|
||||||
return <VulnerabilitiesDetails name={reponame} tag={tag} />;
|
return (
|
||||||
|
<VulnerabilitiesDetails
|
||||||
|
name={reponame}
|
||||||
|
tag={tag}
|
||||||
|
digest={selectedManifest?.digest}
|
||||||
|
platform={selectedManifest.platform}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case 'ReferredBy':
|
case 'ReferredBy':
|
||||||
return <ReferredBy referrers={imageDetailData.referrers} />;
|
return <ReferredBy referrers={imageDetailData.referrers} />;
|
||||||
default:
|
default:
|
||||||
@@ -227,10 +233,10 @@ function TagDetails() {
|
|||||||
<Card className={classes.cardRoot}>
|
<Card className={classes.cardRoot}>
|
||||||
<CardContent className={classes.cardContent}>
|
<CardContent className={classes.cardContent}>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12} md={8} className={classes.header}>
|
<Grid item xs={12} md={9} className={classes.header}>
|
||||||
<Stack
|
<Stack
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
sx={{ width: { xs: '100%', md: 'auto' } }}
|
sx={{ width: { xs: '100%', md: 'auto' }, marginBottom: '1rem' }}
|
||||||
direction={{ xs: 'column', md: 'row' }}
|
direction={{ xs: 'column', md: 'row' }}
|
||||||
spacing={1}
|
spacing={1}
|
||||||
>
|
>
|
||||||
@@ -256,30 +262,29 @@ function TagDetails() {
|
|||||||
/>
|
/>
|
||||||
<SignatureIconCheck isSigned={imageDetailData.isSigned} />
|
<SignatureIconCheck isSigned={imageDetailData.isSigned} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack sx={{ width: { xs: '100%', md: 'auto' } }}>
|
|
||||||
<FormControl sx={{ m: '1', minWidth: '4.6875rem' }} className={classes.sortForm} size="small">
|
|
||||||
<InputLabel>OS/Arch</InputLabel>
|
|
||||||
{!isEmpty(selectedManifest) && (
|
|
||||||
<Select
|
|
||||||
label="OS/Arch"
|
|
||||||
value={selectedManifest}
|
|
||||||
onChange={handleOSArchChange}
|
|
||||||
MenuProps={{ disableScrollLock: true }}
|
|
||||||
>
|
|
||||||
{imageDetailData.manifests.map((el) => (
|
|
||||||
<MenuItem key={el.digest} value={el}>
|
|
||||||
{`${el.platform?.Os}/${el.platform?.Arch}`}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
</FormControl>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
<Typography gutterBottom className={classes.digest}>
|
<Stack direction="row" alignItems="center" spacing="1rem">
|
||||||
Digest: {selectedManifest?.digest}
|
<FormControl sx={{ m: '1', minWidth: '4.6875rem' }} className={classes.sortForm} size="small">
|
||||||
</Typography>
|
<InputLabel>OS/Arch</InputLabel>
|
||||||
|
{!isEmpty(selectedManifest) && (
|
||||||
|
<Select
|
||||||
|
label="OS/Arch"
|
||||||
|
value={selectedManifest}
|
||||||
|
onChange={handleOSArchChange}
|
||||||
|
MenuProps={{ disableScrollLock: true }}
|
||||||
|
>
|
||||||
|
{imageDetailData.manifests.map((el) => (
|
||||||
|
<MenuItem key={el.digest} value={el}>
|
||||||
|
{`${el.platform?.Os}/${el.platform?.Arch}`}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
</FormControl>
|
||||||
|
<Typography gutterBottom className={classes.digest}>
|
||||||
|
Digest: {selectedManifest?.digest}
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
@@ -23,7 +23,7 @@ const VerifiedShieldIcon = createSvgIcon(
|
|||||||
|
|
||||||
const NoneVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
const NoneVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={`${vulnerabilityStringTitle} Vulnerability`} placement="top">
|
<Tooltip title={`${vulnerabilityStringTitle}`} placement="top">
|
||||||
<OutlinedBugIcon
|
<OutlinedBugIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: '#43A047!important',
|
color: '#43A047!important',
|
||||||
@@ -40,7 +40,7 @@ const NoneVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
|||||||
};
|
};
|
||||||
const UnknownVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
const UnknownVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={`${vulnerabilityStringTitle} Vulnerability`} placement="top">
|
<Tooltip title={`${vulnerabilityStringTitle}`} placement="top">
|
||||||
<OutlinedBugIcon
|
<OutlinedBugIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: '#52637A',
|
color: '#52637A',
|
||||||
@@ -75,7 +75,7 @@ const FailedScanIcon = () => {
|
|||||||
};
|
};
|
||||||
const LowVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
const LowVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={`${vulnerabilityStringTitle} Vulnerability`} placement="top">
|
<Tooltip title={`${vulnerabilityStringTitle}`} placement="top">
|
||||||
<OutlinedBugIcon
|
<OutlinedBugIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: '#FB8C00',
|
color: '#FB8C00',
|
||||||
@@ -92,7 +92,7 @@ const LowVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
|||||||
};
|
};
|
||||||
const MediumVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
const MediumVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={`${vulnerabilityStringTitle} Vulnerability`} placement="top">
|
<Tooltip title={`${vulnerabilityStringTitle}`} placement="top">
|
||||||
<FilledBugIcon
|
<FilledBugIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: '#FB8C00',
|
color: '#FB8C00',
|
||||||
@@ -109,7 +109,7 @@ const MediumVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
|||||||
};
|
};
|
||||||
const HighVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
const HighVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={`${vulnerabilityStringTitle} Vulnerability`} placement="top">
|
<Tooltip title={`${vulnerabilityStringTitle}`} placement="top">
|
||||||
<OutlinedBugIcon
|
<OutlinedBugIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: '#E53935',
|
color: '#E53935',
|
||||||
@@ -126,7 +126,7 @@ const HighVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
|||||||
};
|
};
|
||||||
const CriticalVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
const CriticalVulnerabilityIcon = ({ vulnerabilityStringTitle }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={`${vulnerabilityStringTitle} Vulnerability`} placement="top">
|
<Tooltip title={`${vulnerabilityStringTitle}`} placement="top">
|
||||||
<FilledBugIcon
|
<FilledBugIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: '#E53935',
|
color: '#E53935',
|
||||||
|
Reference in New Issue
Block a user