Fixed the bug regarding published date for images in Tag Page

Signed-off-by: Amelia-Maria Breda <ambreda@cisco.com>
This commit is contained in:
Amelia-Maria Breda 2022-10-13 15:41:19 +01:00 committed by Raul Kele
parent eca62511b9
commit 5c0e594d06
5 changed files with 68 additions and 81 deletions

View File

@ -20,7 +20,7 @@
.App-logo {
animation: bounce 1s;
animation-direction: alternate;
animation-timing-function: cubic-bezier(.5, 0.05, 1, .5);
animation-timing-function: cubic-bezier(0.5, 0.05, 1, 0.5);
animation-iteration-count: infinite;
}
}
@ -49,25 +49,25 @@
}
}
@-webkit-keyframes bounce {
@-webkit-keyframes bounce {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 50px, 0);
transform: translate3d(0, 50px, 0);
}
}
@keyframes bounce {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 50px, 0);
}
}
.bounce {
-webkit-animation-name: bounce;
animation-name: bounce;
}
@keyframes bounce {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 50px, 0);
}
}
.bounce {
-webkit-animation-name: bounce;
animation-name: bounce;
}

View File

@ -9,42 +9,30 @@ jest.mock('react-router-dom', () => ({
useNavigate: () => mockedUsedNavigate
}));
const mockedTagsData = {
name: 'alpine',
images: [
{
Digest: '59118d0816d2e8e05cb04c328224056b3ce07d7afc2ad59e2f1f08bb0ba2ff3c',
Tag: 'latest',
Layers: [
{
Size: '2806054',
Digest: '213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49'
}
]
}
],
lastUpdated: '2022-08-09T17:19:53.274069586Z',
size: '2806985',
platforms: [
{
const mockedTagsData = [
{
Digest: 'sha256:adca4815c494becc1bf053af0c4640b2d81ab1a779e6d649e1b8b92a75f1d559',
Tag: 'latest',
LastUpdated: '2022-07-19T18:06:18.818788283Z',
Vendor: 'test1',
Size: '569130088',
Platform: {
Os: 'linux',
Arch: 'amd64'
}
],
vendors: [''],
newestTag: null
};
}
];
describe('Tags component', () => {
it('should open and close details dropdown for tags', () => {
render(<Tags data={mockedTagsData} />);
render(<Tags tags={mockedTagsData} />);
const openBtn = screen.getByText(/see digest/i);
fireEvent.click(openBtn);
expect(screen.queryByText(/see digest/i)).not.toBeInTheDocument();
expect(screen.getByText(/hide digest/i)).toBeInTheDocument();
});
it('should navigate to tag page details when tag is clicked', async () => {
render(<Tags data={mockedTagsData} />);
render(<Tags tags={mockedTagsData} />);
const tagLink = await screen.findByText('latest');
fireEvent.click(tagLink);
await waitFor(() => {

View File

@ -65,7 +65,7 @@ const endpoints = {
(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}}`,
detailedRepoInfo: (name) =>
`/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Tag Layers {Size Digest}} Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestImage {RepoName Layers {Size Digest} Digest Tag Title Documentation DownloadCount Source Description 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 Title Documentation DownloadCount Source Description History {Layer {Size Digest} HistoryDescription {Created CreatedBy Author Comment EmptyLayer}}}}}}`,
detailedImageInfo: (name, tag) =>
`/v2/_zot/ext/search?query={Image(image: "${name}:${tag}"){RepoName Tag Digest LastUpdated Size ConfigDigest Platform {Os Arch} Vendor History {Layer {Size Digest Score} HistoryDescription {Created CreatedBy Author Comment EmptyLayer} }}}`,
vulnerabilitiesForRepo: (name) =>

View File

@ -118,6 +118,7 @@ const randomImage = () => {
function RepoDetails() {
const [repoDetailData, setRepoDetailData] = useState({});
const [tags, setTags] = useState([]);
// @ts-ignore
const [isLoading, setIsLoading] = useState(true);
const [selectedTab, setSelectedTab] = useState('Overview');
@ -147,6 +148,7 @@ function RepoDetails() {
overview: repoInfo.Summary?.NewestImage.Documentation
};
setRepoDetailData(imageData);
setTags(imageData.images);
}
setIsLoading(false);
})
@ -154,6 +156,7 @@ function RepoDetails() {
console.error(e);
setRepoDetailData({});
setIsLoading(false);
setTags([]);
});
return () => {
abortController.abort();
@ -313,7 +316,7 @@ function RepoDetails() {
{renderOverview()}
</TabPanel>
<TabPanel value="Tags" className={classes.tabPanel}>
<Tags data={repoDetailData} />
<Tags tags={tags} />
</TabPanel>
{/* <TabPanel value="Dependencies" className={classes.tabPanel}>
{renderDependencies()}

View File

@ -15,7 +15,6 @@ import Typography from '@mui/material/Typography';
import transform from 'utilities/transform';
import { Card, CardContent, Divider, Stack } from '@mui/material';
import { makeStyles } from '@mui/styles';
import { useEffect } from 'react';
const useStyles = makeStyles(() => ({
tagCard: {
@ -55,24 +54,17 @@ const useStyles = makeStyles(() => ({
}));
function TagCard(props) {
const { row, lastUpdated, vendors, size, platform } = props;
const { tag, lastUpdated, vendors, digest, size, platform } = props;
//const tags = data && data.tags;
const [open, setOpen] = React.useState(false);
const [digests, setDigests] = React.useState([]);
const classes = useStyles();
const tagRow = row;
// @ts-ignore
const lastDate = (lastUpdated ? DateTime.fromISO(lastUpdated) : DateTime.now().minus({ days: 1 })).toRelative({
unit: 'days'
});
const navigate = useNavigate();
useEffect(() => {
const tagDigest = [{ digest: tagRow.Digest, osArch: platform[0], size: size }];
setDigests(tagDigest);
}, []);
const goToTags = (tag) => {
navigate(`tag/${tag}`);
};
@ -87,9 +79,9 @@ function TagCard(props) {
variant="body1"
align="left"
sx={{ color: '#1479FF', fontSize: '1rem', textDecorationLine: 'underline', cursor: 'pointer' }}
onClick={() => goToTags(tagRow.Tag)}
onClick={() => goToTags(tag)}
>
{tagRow?.Tag}
{tag}
</Typography>
<Stack sx={{ display: 'inline' }} direction="row" spacing={0.5}>
@ -97,7 +89,7 @@ function TagCard(props) {
Last pushed
</Typography>
<Typography variant="caption" sx={{ fontWeight: '600', fontSize: '0.8125rem' }}>
{lastDate || 'Date not available'} by {vendors[0] || 'Vendor not available'}
{lastDate || 'Date not available'} by {vendors || 'Vendor not available'}
</Typography>
</Stack>
@ -130,27 +122,24 @@ function TagCard(props) {
</TableRow>
</TableHead>
<TableBody>
{digests.map((layer) => (
<TableRow
key={layer.digest}
onClick={() => {
navigator.clipboard.writeText(layer.digest);
}}
>
<TableCell style={{ color: '#696969' }}>
<Typography variant="body1">{layer.digest?.substr(0, 12)}</Typography>
</TableCell>
<TableCell style={{ color: '#696969' }}>
<Typography variant="body1">
{' '}
{layer.osArch?.Os}/{layer.osArch?.Arch}{' '}
</Typography>
</TableCell>
<TableCell component="th" scope="row" style={{ color: '#696969' }}>
<Typography variant="body1">{transform.formatBytes(layer.size)}</Typography>
</TableCell>
</TableRow>
))}
<TableRow
key={digest}
onClick={() => {
navigator.clipboard.writeText(digest);
}}
>
<TableCell style={{ color: '#696969' }}>
<Typography variant="body1">{digest?.substr(0, 12)}</Typography>
</TableCell>
<TableCell style={{ color: '#696969' }}>
<Typography variant="body1">
{platform.Os}/{platform.Arch}
</Typography>
</TableCell>
<TableCell component="th" scope="row" style={{ color: '#696969' }}>
<Typography variant="body1">{transform.formatBytes(size)}</Typography>
</TableCell>
</TableRow>
</TableBody>
</Table>
</Box>
@ -172,12 +161,20 @@ function TagCard(props) {
// }).isRequired,
// };
const renderTags = (tags, lastUpdated, vendors, size, platform) => {
const renderTags = (tags) => {
const cmp =
tags &&
tags.map((tag) => {
return (
<TagCard key={tag.Tag} row={tag} lastUpdated={lastUpdated} vendors={vendors} size={size} platform={platform} />
<TagCard
key={tag.Tag}
tag={tag.Tag}
lastUpdated={tag.LastUpdated}
digest={tag.Digest}
vendors={tag.Vendors}
size={tag.Size}
platform={tag.Platform}
/>
);
});
return cmp;
@ -185,9 +182,8 @@ const renderTags = (tags, lastUpdated, vendors, size, platform) => {
export default function Tags(props) {
const classes = useStyles();
const { data } = props;
const { images, lastUpdated, vendors, size, platforms } = data;
const { tags } = props;
console.log(JSON.stringify(tags));
return (
<Card className={classes.tagCard} data-testid="tags-container">
<CardContent className={classes.content}>
@ -209,7 +205,7 @@ export default function Tags(props) {
width: '100%'
}}
/>
{renderTags(images, lastUpdated, vendors, size, platforms)}
{renderTags(tags)}
</CardContent>
</Card>
);