feat: Implemented logo display
Signed-off-by: Raul Kele <raulkeleblk@gmail.com>
This commit is contained in:
parent
ac782c04d0
commit
2dc4a35c87
@ -102,7 +102,7 @@ describe('Tags details', () => {
|
|||||||
jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} });
|
jest.spyOn(api, 'get').mockRejectedValue({ status: 500, data: {} });
|
||||||
const error = jest.spyOn(console, 'error').mockImplementation(() => {});
|
const error = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||||
render(<TagDetails />);
|
render(<TagDetails />);
|
||||||
await waitFor(() => expect(error).toBeCalledTimes(2));
|
await waitFor(() => expect(error).toBeCalledTimes(1));
|
||||||
});
|
});
|
||||||
it('should show tag details metadata', async () => {
|
it('should show tag details metadata', async () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -63,11 +63,11 @@ const endpoints = {
|
|||||||
repoList: ({ pageNumber = 1, pageSize = 15 } = {}) =>
|
repoList: ({ pageNumber = 1, pageSize = 15 } = {}) =>
|
||||||
`/v2/_zot/ext/search?query={RepoListWithNewestImage(requestedPage: {limit:${pageSize} offset:${
|
`/v2/_zot/ext/search?query={RepoListWithNewestImage(requestedPage: {limit:${pageSize} offset:${
|
||||||
(pageNumber - 1) * pageSize
|
(pageNumber - 1) * pageSize
|
||||||
}}){Name LastUpdated Size Platforms {Os Arch} NewestImage { Tag Description Licenses Title Source IsSigned Documentation History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}} Vendor Labels} DownloadCount}}`,
|
}}){Name LastUpdated Size Platforms {Os Arch} NewestImage { Tag Description Licenses Logo Title Source IsSigned Documentation History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}} Vendor Labels} DownloadCount}}`,
|
||||||
detailedRepoInfo: (name) =>
|
detailedRepoInfo: (name) =>
|
||||||
`/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Tag LastUpdated Vendor Size Platform {Os Arch} } Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestImage {RepoName Layers {Size Digest} Digest Tag Title Documentation DownloadCount Source Description Licenses History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}}}}}}`,
|
`/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Tag LastUpdated Vendor Size Platform {Os Arch} } Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestImage {RepoName Layers {Size Digest} Digest Tag Logo Title Documentation DownloadCount Source Description Licenses History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}}}}}}`,
|
||||||
detailedImageInfo: (name, tag) =>
|
detailedImageInfo: (name, tag) =>
|
||||||
`/v2/_zot/ext/search?query={Image(image: "${name}:${tag}"){RepoName Tag Digest LastUpdated Size ConfigDigest Platform {Os Arch} Vendor Licenses History {Layer {Size Digest Score} HistoryDescription {Created CreatedBy Author Comment EmptyLayer} }}}`,
|
`/v2/_zot/ext/search?query={Image(image: "${name}:${tag}"){RepoName Tag Digest LastUpdated Size ConfigDigest Platform {Os Arch} Vendor Licenses Logo}}`,
|
||||||
vulnerabilitiesForRepo: (name) =>
|
vulnerabilitiesForRepo: (name) =>
|
||||||
`/v2/_zot/ext/search?query={CVEListForImage(image: "${name}"){Tag, CVEList {Id Title Description Severity PackageList {Name InstalledVersion FixedVersion}}}}`,
|
`/v2/_zot/ext/search?query={CVEListForImage(image: "${name}"){Tag, CVEList {Id Title Description Severity PackageList {Name InstalledVersion FixedVersion}}}}`,
|
||||||
layersDetailsForImage: (name) =>
|
layersDetailsForImage: (name) =>
|
||||||
@ -87,7 +87,7 @@ const endpoints = {
|
|||||||
if (filter.HasToBeSigned) filterParam += ` HasToBeSigned: ${filter.HasToBeSigned}`;
|
if (filter.HasToBeSigned) filterParam += ` HasToBeSigned: ${filter.HasToBeSigned}`;
|
||||||
filterParam += '}';
|
filterParam += '}';
|
||||||
if (Object.keys(filter).length === 0) filterParam = '';
|
if (Object.keys(filter).length === 0) filterParam = '';
|
||||||
return `/v2/_zot/ext/search?query={GlobalSearch(${searchParam}, ${paginationParam} ${filterParam}) {Repos {Name LastUpdated Size Platforms { Os Arch } NewestImage { Tag Description IsSigned Licenses Vendor Labels } DownloadCount}}}`;
|
return `/v2/_zot/ext/search?query={GlobalSearch(${searchParam}, ${paginationParam} ${filterParam}) {Repos {Name LastUpdated Size Platforms { Os Arch } NewestImage { Tag Description IsSigned Logo Licenses Vendor Labels } DownloadCount}}}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,6 +114,7 @@ function Explore() {
|
|||||||
platforms={item.platforms}
|
platforms={item.platforms}
|
||||||
key={index}
|
key={index}
|
||||||
lastUpdated={item.lastUpdated}
|
lastUpdated={item.lastUpdated}
|
||||||
|
logo={item.logo}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -44,7 +44,7 @@ function FilterCard(props) {
|
|||||||
const filterRows = filters;
|
const filterRows = filters;
|
||||||
return filterRows.map((filter, index) => {
|
return filterRows.map((filter, index) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip key={index} title={filter.tooltip ?? filter.label} placement="right">
|
<Tooltip key={index} title={filter.tooltip ?? filter.label} placement="top" arrow>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
componentsProps={{ typography: { variant: 'body2' } }}
|
componentsProps={{ typography: { variant: 'body2' } }}
|
||||||
control={<Checkbox />}
|
control={<Checkbox />}
|
||||||
|
@ -96,7 +96,7 @@ function Home() {
|
|||||||
homeData.slice(0, 4).map((item, index) => {
|
homeData.slice(0, 4).map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<Grid item xs={3} key={index}>
|
<Grid item xs={3} key={index}>
|
||||||
<PreviewCard name={item.name} lastUpdated={item.lastUpdated} isSigned={item.isSigned} />
|
<PreviewCard name={item.name} lastUpdated={item.lastUpdated} isSigned={item.isSigned} logo={item.logo} />
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@ -141,6 +141,7 @@ function Home() {
|
|||||||
platforms={item.platforms}
|
platforms={item.platforms}
|
||||||
key={index}
|
key={index}
|
||||||
lastUpdated={item.lastUpdated}
|
lastUpdated={item.lastUpdated}
|
||||||
|
logo={item.logo}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -12,6 +12,7 @@ import repocube4 from '../assets/repocube-4.png';
|
|||||||
//icons
|
//icons
|
||||||
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
|
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
|
||||||
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
|
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
//import GppMaybeOutlinedIcon from '@mui/icons-material/GppMaybeOutlined';
|
//import GppMaybeOutlinedIcon from '@mui/icons-material/GppMaybeOutlined';
|
||||||
|
|
||||||
// temporary utility to get image
|
// temporary utility to get image
|
||||||
@ -73,7 +74,7 @@ const useStyles = makeStyles(() => ({
|
|||||||
function PreviewCard(props) {
|
function PreviewCard(props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { name, isSigned } = props;
|
const { name, isSigned, logo } = props;
|
||||||
|
|
||||||
const goToDetails = () => {
|
const goToDetails = () => {
|
||||||
navigate(`/image/${encodeURIComponent(name)}`);
|
navigate(`/image/${encodeURIComponent(name)}`);
|
||||||
@ -139,7 +140,7 @@ function PreviewCard(props) {
|
|||||||
img: classes.avatar
|
img: classes.avatar
|
||||||
}}
|
}}
|
||||||
component="img"
|
component="img"
|
||||||
image={randomImage()}
|
image={!isEmpty(logo) ? `data:image/png;base64, ${logo}` : randomImage()}
|
||||||
alt="icon"
|
alt="icon"
|
||||||
/>
|
/>
|
||||||
<Tooltip title={name} placement="top">
|
<Tooltip title={name} placement="top">
|
||||||
|
@ -18,6 +18,7 @@ import repocube4 from '../assets/repocube-4.png';
|
|||||||
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
|
import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined';
|
||||||
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
|
import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined';
|
||||||
import { Markdown } from 'utilities/MarkdowntojsxWrapper';
|
import { Markdown } from 'utilities/MarkdowntojsxWrapper';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
// temporary utility to get image
|
// temporary utility to get image
|
||||||
const randomIntFromInterval = (min, max) => {
|
const randomIntFromInterval = (min, max) => {
|
||||||
@ -90,12 +91,7 @@ const useStyles = makeStyles(() => ({
|
|||||||
function RepoCard(props) {
|
function RepoCard(props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { name, vendor, platforms, description, downloads, isSigned, lastUpdated, version } = props;
|
const { name, vendor, platforms, description, downloads, isSigned, lastUpdated, version, logo } = props;
|
||||||
|
|
||||||
//function that returns a random element from an array
|
|
||||||
// function getRandom(list) {
|
|
||||||
// return list[Math.floor(Math.random() * list.length)];
|
|
||||||
// }
|
|
||||||
|
|
||||||
const goToDetails = () => {
|
const goToDetails = () => {
|
||||||
navigate(`/image/${encodeURIComponent(name)}`);
|
navigate(`/image/${encodeURIComponent(name)}`);
|
||||||
@ -197,7 +193,7 @@ function RepoCard(props) {
|
|||||||
img: classes.avatar
|
img: classes.avatar
|
||||||
}}
|
}}
|
||||||
component="img"
|
component="img"
|
||||||
image={randomImage()}
|
image={!isEmpty(logo) ? `data:image/png;base64, ${logo}` : randomImage()}
|
||||||
alt="icon"
|
alt="icon"
|
||||||
/>
|
/>
|
||||||
<Tooltip title={name} placement="top">
|
<Tooltip title={name} placement="top">
|
||||||
|
@ -19,6 +19,7 @@ import repocube4 from '../assets/repocube-4.png';
|
|||||||
import { TabContext, TabList, TabPanel } from '@mui/lab';
|
import { TabContext, TabList, TabPanel } from '@mui/lab';
|
||||||
import RepoDetailsMetadata from './RepoDetailsMetadata';
|
import RepoDetailsMetadata from './RepoDetailsMetadata';
|
||||||
import Loading from './Loading';
|
import Loading from './Loading';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
@ -141,12 +142,13 @@ function RepoDetails() {
|
|||||||
platforms: repoInfo.Summary?.Platforms,
|
platforms: repoInfo.Summary?.Platforms,
|
||||||
vendors: repoInfo.Summary?.Vendors,
|
vendors: repoInfo.Summary?.Vendors,
|
||||||
newestTag: repoInfo.Summary?.NewestImage,
|
newestTag: repoInfo.Summary?.NewestImage,
|
||||||
description: repoInfo.Summary?.NewestImage.Description,
|
description: repoInfo.Summary?.NewestImage?.Description,
|
||||||
title: repoInfo.Summary?.NewestImage.Title,
|
title: repoInfo.Summary?.NewestImage?.Title,
|
||||||
source: repoInfo.Summary?.NewestImage.Source,
|
source: repoInfo.Summary?.NewestImage?.Source,
|
||||||
downloads: repoInfo.Summary?.NewestImage.DownloadCount,
|
downloads: repoInfo.Summary?.NewestImage?.DownloadCount,
|
||||||
overview: repoInfo.Summary?.NewestImage.Documentation,
|
overview: repoInfo.Summary?.NewestImage?.Documentation,
|
||||||
license: repoInfo.Summary?.NewestImage.Licenses
|
license: repoInfo.Summary?.NewestImage?.Licenses,
|
||||||
|
logo: repoInfo.Summary?.NewestImage?.Logo
|
||||||
};
|
};
|
||||||
setRepoDetailData(imageData);
|
setRepoDetailData(imageData);
|
||||||
setTags(imageData.images);
|
setTags(imageData.images);
|
||||||
@ -163,19 +165,6 @@ function RepoDetails() {
|
|||||||
abortController.abort();
|
abortController.abort();
|
||||||
};
|
};
|
||||||
}, [name]);
|
}, [name]);
|
||||||
//function that returns a random element from an array
|
|
||||||
// function getRandom(list) {
|
|
||||||
// return list[Math.floor(Math.random() * list.length)];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const signatureCheck = () => {
|
|
||||||
// const unverifiedSignature = <Chip label="Unverified Signature" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppBadOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
|
|
||||||
// const untrustedSignature = <Chip label="Untrusted Signature" sx={{backgroundColor: "#ECEFF1",color: "#52637A",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppMaybeOutlinedIcon sx={{ color: "#52637A!important" }} />}/>;
|
|
||||||
// const verifiedSignature = <Chip label="Verified Signature" sx={{backgroundColor: "#E8F5E9",color: "#388E3C",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppGoodOutlinedIcon sx={{ color: "#388E3C!important" }} />}/>;
|
|
||||||
|
|
||||||
// const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature]
|
|
||||||
// return(getRandom(arrSignature));
|
|
||||||
// }
|
|
||||||
|
|
||||||
const platformChips = () => {
|
const platformChips = () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -234,22 +223,6 @@ function RepoDetails() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// const renderDependencies = () => {
|
|
||||||
// return (<Card className={classes.card}>
|
|
||||||
// <CardContent>
|
|
||||||
// <Typography variant="h4" align="left">Dependecies ({dependencies || '---'})</Typography>
|
|
||||||
// </CardContent>
|
|
||||||
// </Card>);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const renderDependents = () => {
|
|
||||||
// return (<Card className={classes.card}>
|
|
||||||
// <CardContent>
|
|
||||||
// <Typography variant="h4" align="left">Dependents ({dependents || '---'})</Typography>
|
|
||||||
// </CardContent>
|
|
||||||
// </Card>);
|
|
||||||
// };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
@ -267,7 +240,9 @@ function RepoDetails() {
|
|||||||
img: classes.avatar
|
img: classes.avatar
|
||||||
}}
|
}}
|
||||||
component="img"
|
component="img"
|
||||||
image={randomImage()}
|
// @ts-ignore
|
||||||
|
// eslint-disable-next-line prettier/prettier
|
||||||
|
image={!isEmpty(repoDetailData?.logo) ? `data:image/png;base64, ${repoDetailData?.logo}` : randomImage()}
|
||||||
alt="icon"
|
alt="icon"
|
||||||
/>
|
/>
|
||||||
<Typography variant="h3" className={classes.repoName}>
|
<Typography variant="h3" className={classes.repoName}>
|
||||||
@ -304,12 +279,6 @@ function RepoDetails() {
|
|||||||
>
|
>
|
||||||
<Tab value="Overview" label="Overview" className={classes.tabContent} />
|
<Tab value="Overview" label="Overview" className={classes.tabContent} />
|
||||||
<Tab value="Tags" label="Tags" className={classes.tabContent} />
|
<Tab value="Tags" label="Tags" className={classes.tabContent} />
|
||||||
{/* <Tab value="Dependencies" label={`${dependencies || 0} Dependencies`} className={classes.tabContent}/>
|
|
||||||
<Tab value="Dependents" label={`${dependents || 0} Dependents`} className={classes.tabContent}/>
|
|
||||||
<Tab value="Vulnerabilities" label="Vulnerabilities" className={classes.tabContent}/>
|
|
||||||
<Tab value="6" label="Tab 6" className={classes.tabContent}/>
|
|
||||||
<Tab value="7" label="Tab 7" className={classes.tabContent}/>
|
|
||||||
<Tab value="8" label="Tab 8" className={classes.tabContent}/> */}
|
|
||||||
</TabList>
|
</TabList>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
@ -319,15 +288,6 @@ function RepoDetails() {
|
|||||||
<TabPanel value="Tags" className={classes.tabPanel}>
|
<TabPanel value="Tags" className={classes.tabPanel}>
|
||||||
<Tags tags={tags} />
|
<Tags tags={tags} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
{/* <TabPanel value="Dependencies" className={classes.tabPanel}>
|
|
||||||
{renderDependencies()}
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel value="Dependents" className={classes.tabPanel}>
|
|
||||||
{renderDependents()}
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel value="Vulnerabilities" className={classes.tabPanel}>
|
|
||||||
{renderVulnerabilities()}
|
|
||||||
</TabPanel> */}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -35,6 +35,8 @@ import VulnerabilitiesDetails from './VulnerabilitiesDetails';
|
|||||||
import HistoryLayers from './HistoryLayers';
|
import HistoryLayers from './HistoryLayers';
|
||||||
import DependsOn from './DependsOn';
|
import DependsOn from './DependsOn';
|
||||||
import IsDependentOn from './IsDependentOn';
|
import IsDependentOn from './IsDependentOn';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import Loading from './Loading';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
@ -133,8 +135,7 @@ const randomImage = () => {
|
|||||||
|
|
||||||
function TagDetails() {
|
function TagDetails() {
|
||||||
const [imageDetailData, setImageDetailData] = useState({});
|
const [imageDetailData, setImageDetailData] = useState({});
|
||||||
// @ts-ignore
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
//const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [selectedTab, setSelectedTab] = useState('Layers');
|
const [selectedTab, setSelectedTab] = useState('Layers');
|
||||||
const abortController = useMemo(() => new AbortController(), []);
|
const abortController = useMemo(() => new AbortController(), []);
|
||||||
|
|
||||||
@ -148,6 +149,7 @@ function TagDetails() {
|
|||||||
// if same-page navigation because of tag update, following 2 lines help ux
|
// if same-page navigation because of tag update, following 2 lines help ux
|
||||||
setSelectedTab('Layers');
|
setSelectedTab('Layers');
|
||||||
window?.scrollTo(0, 0);
|
window?.scrollTo(0, 0);
|
||||||
|
setIsLoading(true);
|
||||||
api
|
api
|
||||||
.get(`${host()}${endpoints.detailedImageInfo(name, tag)}`, abortController.signal)
|
.get(`${host()}${endpoints.detailedImageInfo(name, tag)}`, abortController.signal)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -162,11 +164,12 @@ function TagDetails() {
|
|||||||
platform: imageInfo.Platform,
|
platform: imageInfo.Platform,
|
||||||
vendor: imageInfo.Vendor,
|
vendor: imageInfo.Vendor,
|
||||||
history: imageInfo.History,
|
history: imageInfo.History,
|
||||||
license: imageInfo.Licenses
|
license: imageInfo.Licenses,
|
||||||
|
logo: imageInfo.Logo
|
||||||
};
|
};
|
||||||
setImageDetailData(imageData);
|
setImageDetailData(imageData);
|
||||||
setFullName(imageData.name + ':' + imageData.tag);
|
setFullName(imageData.name + ':' + imageData.tag);
|
||||||
//setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
@ -177,10 +180,6 @@ function TagDetails() {
|
|||||||
abortController.abort();
|
abortController.abort();
|
||||||
};
|
};
|
||||||
}, [name, tag]);
|
}, [name, tag]);
|
||||||
//function that returns a random element from an array
|
|
||||||
// function getRandom(list) {
|
|
||||||
// return list[Math.floor(Math.random() * list.length)];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const signatureCheck = () => {
|
// const signatureCheck = () => {
|
||||||
// const unverifiedSignature = <Chip label="Unverified Signature" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppBadOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
|
// const unverifiedSignature = <Chip label="Unverified Signature" sx={{backgroundColor: "#FEEBEE",color: "#E53935",fontSize: "0.8125rem",}} variant="filled" onDelete={() => { return; }} deleteIcon={ <GppBadOutlinedIcon sx={{ color: "#E53935!important" }} />}/>;
|
||||||
@ -206,134 +205,152 @@ function TagDetails() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.pageWrapper}>
|
<>
|
||||||
<Card className={classes.cardRoot}>
|
{isLoading ? (
|
||||||
<CardContent>
|
<Loading />
|
||||||
<Grid container className={classes.header}>
|
) : (
|
||||||
<Grid item xs={8}>
|
<div className={classes.pageWrapper}>
|
||||||
<Stack alignItems="center" direction="row" spacing={2}>
|
<Card className={classes.cardRoot}>
|
||||||
<CardMedia
|
<CardContent>
|
||||||
classes={{
|
<Grid container className={classes.header}>
|
||||||
root: classes.media,
|
<Grid item xs={8}>
|
||||||
img: classes.avatar
|
<Stack alignItems="center" direction="row" spacing={2}>
|
||||||
}}
|
<CardMedia
|
||||||
component="img"
|
classes={{
|
||||||
image={randomImage()}
|
root: classes.media,
|
||||||
alt="icon"
|
img: classes.avatar
|
||||||
/>
|
}}
|
||||||
<Typography variant="h3" className={classes.repoName}>
|
component="img"
|
||||||
{name}:{tag}
|
image={
|
||||||
</Typography>
|
// @ts-ignore
|
||||||
{/* {vulnerabilityCheck()}
|
// eslint-disable-next-line prettier/prettier
|
||||||
|
!isEmpty(imageDetailData?.logo) ? `data:image/ png;base64, ${imageDetailData?.logo}` : randomImage()
|
||||||
|
}
|
||||||
|
alt="icon"
|
||||||
|
/>
|
||||||
|
<Typography variant="h3" className={classes.repoName}>
|
||||||
|
{name}:{tag}
|
||||||
|
</Typography>
|
||||||
|
{/* {vulnerabilityCheck()}
|
||||||
{signatureCheck()} */}
|
{signatureCheck()} */}
|
||||||
{/* <BookmarkIcon sx={{color:"#52637A"}}/> */}
|
{/* <BookmarkIcon sx={{color:"#52637A"}}/> */}
|
||||||
</Stack>
|
</Stack>
|
||||||
<Typography
|
<Typography
|
||||||
pt={1}
|
pt={1}
|
||||||
sx={{ fontSize: 16, lineHeight: '1.5rem', color: 'rgba(0, 0, 0, 0.6)', paddingLeft: '4rem' }}
|
sx={{ fontSize: 16, lineHeight: '1.5rem', color: 'rgba(0, 0, 0, 0.6)', paddingLeft: '4rem' }}
|
||||||
gutterBottom
|
gutterBottom
|
||||||
align="left"
|
align="left"
|
||||||
>
|
>
|
||||||
DIGEST:{' '}
|
DIGEST:{' '}
|
||||||
{
|
{
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
imageDetailData?.digest
|
imageDetailData?.digest
|
||||||
}
|
}
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<Stack direction="row">
|
|
||||||
<Grid item xs={10}>
|
|
||||||
<Typography variant="body1" sx={{ color: '#52637A', fontSize: '1rem', paddingTop: '0.75rem' }}>
|
|
||||||
Pull this image
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={2}>
|
<Grid item xs={4} justifyContent="flex-start">
|
||||||
<IconButton
|
<Stack direction="row">
|
||||||
aria-label="copy"
|
<Grid item xs={10}>
|
||||||
onClick={() => navigator.clipboard.writeText(pullString)}
|
<Typography
|
||||||
data-testid="pullcopy-btn"
|
variant="body1"
|
||||||
>
|
sx={{ color: '#52637A', fontSize: '1rem', paddingTop: '0.75rem', textAlign: 'left' }}
|
||||||
<ContentCopyIcon />
|
>
|
||||||
</IconButton>
|
Pull this image
|
||||||
</Grid>
|
</Typography>
|
||||||
</Stack>
|
|
||||||
<FormControl sx={{ m: 1, paddingLeft: '1.5rem' }} variant="outlined">
|
|
||||||
<Select
|
|
||||||
className={classes.inputForm}
|
|
||||||
value={pullString}
|
|
||||||
onChange={handleSelectionChange}
|
|
||||||
inputProps={{ 'aria-label': 'Without label' }}
|
|
||||||
sx={{ m: 1, width: '20.625rem', borderRadius: '0.5rem', color: '#14191F', alignContent: 'left' }}
|
|
||||||
>
|
|
||||||
<MenuItem value={`docker pull ${hostRoot()}/${fullName}`}>
|
|
||||||
docker pull {hostRoot()}/{fullName}
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={`podman pull ${hostRoot()}/${fullName}`}>
|
|
||||||
podman pull {hostRoot()}/{fullName}
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem value={`skopeo copy docker://${hostRoot()}/${fullName}`}>
|
|
||||||
skopeo copy docker://{hostRoot()}/{fullName}
|
|
||||||
</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
<Grid container>
|
|
||||||
<Grid item xs={8} className={classes.tabs}>
|
|
||||||
<TabContext value={selectedTab}>
|
|
||||||
<Box>
|
|
||||||
<TabList
|
|
||||||
onChange={handleTabChange}
|
|
||||||
TabIndicatorProps={{ className: classes.selectedTab }}
|
|
||||||
sx={{ '& button.Mui-selected': { color: '#14191F', fontWeight: '600' } }}
|
|
||||||
>
|
|
||||||
<Tab value="Layers" label="Layers" className={classes.tabContent} />
|
|
||||||
<Tab value="DependsOn" label="Uses" className={classes.tabContent} data-testid="dependencies-tab" />
|
|
||||||
<Tab value="IsDependentOn" label="Used by" className={classes.tabContent} />
|
|
||||||
<Tab value="Vulnerabilities" label="Vulnerabilities" className={classes.tabContent} />
|
|
||||||
</TabList>
|
|
||||||
<Grid container>
|
|
||||||
<Grid item xs={12}>
|
|
||||||
<TabPanel value="Layers" className={classes.tabPanel}>
|
|
||||||
<HistoryLayers
|
|
||||||
name={fullName}
|
|
||||||
history={
|
|
||||||
// @ts-ignore
|
|
||||||
imageDetailData.history
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel value="DependsOn" className={classes.tabPanel}>
|
|
||||||
<DependsOn name={fullName} />
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel value="IsDependentOn" className={classes.tabPanel}>
|
|
||||||
<IsDependentOn name={fullName} />
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel value="Vulnerabilities" className={classes.tabPanel}>
|
|
||||||
<VulnerabilitiesDetails name={name} tag={tag} />
|
|
||||||
</TabPanel>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
<Grid item xs={2}>
|
||||||
</Box>
|
<IconButton
|
||||||
</TabContext>
|
aria-label="copy"
|
||||||
</Grid>
|
onClick={() => navigator.clipboard.writeText(pullString)}
|
||||||
<Grid item xs={4} className={classes.metadata}>
|
data-testid="pullcopy-btn"
|
||||||
<TagDetailsMetadata
|
>
|
||||||
// @ts-ignore
|
<ContentCopyIcon />
|
||||||
platform={getPlatform()}
|
</IconButton>
|
||||||
// @ts-ignore
|
</Grid>
|
||||||
size={imageDetailData?.size}
|
</Stack>
|
||||||
// @ts-ignore
|
<FormControl sx={{ m: 1 }} variant="outlined">
|
||||||
lastUpdated={imageDetailData?.lastUpdated}
|
<Select
|
||||||
// @ts-ignore
|
className={classes.inputForm}
|
||||||
license={imageDetailData?.license}
|
value={pullString}
|
||||||
/>
|
onChange={handleSelectionChange}
|
||||||
</Grid>
|
inputProps={{ 'aria-label': 'Without label' }}
|
||||||
</Grid>
|
sx={{ m: 1, width: '20.625rem', borderRadius: '0.5rem', color: '#14191F', alignContent: 'left' }}
|
||||||
</CardContent>
|
>
|
||||||
</Card>
|
<MenuItem value={`docker pull ${hostRoot()}/${fullName}`}>
|
||||||
</div>
|
docker pull {hostRoot()}/{fullName}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={`podman pull ${hostRoot()}/${fullName}`}>
|
||||||
|
podman pull {hostRoot()}/{fullName}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={`skopeo copy docker://${hostRoot()}/${fullName}`}>
|
||||||
|
skopeo copy docker://{hostRoot()}/{fullName}
|
||||||
|
</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={8} className={classes.tabs}>
|
||||||
|
<TabContext value={selectedTab}>
|
||||||
|
<Box>
|
||||||
|
<TabList
|
||||||
|
onChange={handleTabChange}
|
||||||
|
TabIndicatorProps={{ className: classes.selectedTab }}
|
||||||
|
sx={{ '& button.Mui-selected': { color: '#14191F', fontWeight: '600' } }}
|
||||||
|
>
|
||||||
|
<Tab value="Layers" label="Layers" className={classes.tabContent} />
|
||||||
|
<Tab
|
||||||
|
value="DependsOn"
|
||||||
|
label="Uses"
|
||||||
|
className={classes.tabContent}
|
||||||
|
data-testid="dependencies-tab"
|
||||||
|
/>
|
||||||
|
<Tab value="IsDependentOn" label="Used by" className={classes.tabContent} />
|
||||||
|
<Tab value="Vulnerabilities" label="Vulnerabilities" className={classes.tabContent} />
|
||||||
|
</TabList>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<TabPanel value="Layers" className={classes.tabPanel}>
|
||||||
|
<HistoryLayers
|
||||||
|
name={fullName}
|
||||||
|
history={
|
||||||
|
// @ts-ignore
|
||||||
|
imageDetailData.history
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel value="DependsOn" className={classes.tabPanel}>
|
||||||
|
<DependsOn name={fullName} />
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel value="IsDependentOn" className={classes.tabPanel}>
|
||||||
|
<IsDependentOn name={fullName} />
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel value="Vulnerabilities" className={classes.tabPanel}>
|
||||||
|
<VulnerabilitiesDetails name={name} tag={tag} />
|
||||||
|
</TabPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</TabContext>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4} className={classes.metadata}>
|
||||||
|
<TagDetailsMetadata
|
||||||
|
// @ts-ignore
|
||||||
|
platform={getPlatform()}
|
||||||
|
// @ts-ignore
|
||||||
|
size={imageDetailData?.size}
|
||||||
|
// @ts-ignore
|
||||||
|
lastUpdated={imageDetailData?.lastUpdated}
|
||||||
|
// @ts-ignore
|
||||||
|
license={imageDetailData?.license}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ const mapToRepo = (responseRepo) => {
|
|||||||
licenses: responseRepo.NewestImage?.Licenses,
|
licenses: responseRepo.NewestImage?.Licenses,
|
||||||
size: responseRepo.Size,
|
size: responseRepo.Size,
|
||||||
vendor: responseRepo.NewestImage?.Vendor,
|
vendor: responseRepo.NewestImage?.Vendor,
|
||||||
|
logo: responseRepo.NewestImage?.Logo,
|
||||||
lastUpdated: responseRepo.LastUpdated,
|
lastUpdated: responseRepo.LastUpdated,
|
||||||
downloads: responseRepo.DownloadCount
|
downloads: responseRepo.DownloadCount
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user