renamed dependencies tabs, renamed to total counts, cut out official from prev cards and added dropdown for pull image command. resigned commit
Signed-off-by: Amelia-Maria Breda <ambreda@cisco.com>
This commit is contained in:
parent
0f50e5c209
commit
c6d4d28367
@ -22,14 +22,6 @@ jest.mock('react-router-dom', () => ({
|
||||
}
|
||||
}));
|
||||
|
||||
// mock clipboard copy fn
|
||||
const mockCopyToClipboard = jest.fn();
|
||||
Object.assign(navigator, {
|
||||
clipboard: {
|
||||
writeText: mockCopyToClipboard
|
||||
}
|
||||
});
|
||||
|
||||
const mockRepoDetailsData = {
|
||||
ExpandedRepoInfo: {
|
||||
Manifests: [
|
||||
@ -76,12 +68,4 @@ describe('Repo details component', () => {
|
||||
expect(await screen.findByTestId('tags-container')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('overview-container')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should copy the pull string to clipboard', async () => {
|
||||
// @ts-ignore
|
||||
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockRepoDetailsData } });
|
||||
render(<RepoDetails />);
|
||||
fireEvent.click(await screen.findByTestId('pullcopy-btn'));
|
||||
await waitFor(() => expect(mockCopyToClipboard).toHaveBeenCalledWith('Pull test'));
|
||||
});
|
||||
});
|
||||
|
@ -57,11 +57,19 @@ const mockImage = {
|
||||
}
|
||||
};
|
||||
|
||||
// mock clipboard copy fn
|
||||
const mockCopyToClipboard = jest.fn();
|
||||
Object.assign(navigator, {
|
||||
clipboard: {
|
||||
writeText: mockCopyToClipboard
|
||||
}
|
||||
});
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
// @ts-ignore
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useParams: () => {
|
||||
return { name: 'test' };
|
||||
return { name: 'test', tag: '1.0.1' };
|
||||
}
|
||||
}));
|
||||
|
||||
@ -97,4 +105,12 @@ describe('Tags details', () => {
|
||||
render(<TagDetails />);
|
||||
expect(await screen.findByTestId('tagDetailsMetadata-container')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should copy the pull string to clipboard', async () => {
|
||||
// @ts-ignore
|
||||
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImage } });
|
||||
render(<TagDetails />);
|
||||
fireEvent.click(await screen.findByTestId('pullcopy-btn'));
|
||||
await waitFor(() => expect(mockCopyToClipboard).toHaveBeenCalledWith('docker pull http://localhost/test:1.0.1'));
|
||||
});
|
||||
});
|
||||
|
@ -215,30 +215,7 @@ function HistoryLayers(props) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isLoaded && historyData && (
|
||||
<Card className={classes.card} raised>
|
||||
<CardContent className={classes.content}>
|
||||
<Grid item xs={11}>
|
||||
<Stack sx={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||
<Typography variant="body1" align="left" className={classes.title}>
|
||||
Command
|
||||
</Typography>
|
||||
<Typography variant="body1" align="left" className={classes.values}>
|
||||
{transform.formatBytes(historyData[selectedIndex].Layer?.Size)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Typography variant="body1" align="left" className={classes.title} sx={{ backgroundColor: '#F7F7F7' }}>
|
||||
{historyData[selectedIndex].HistoryDescription?.CreatedBy}
|
||||
</Typography>
|
||||
{!historyData[selectedIndex].HistoryDescription?.EmptyLayer ? (
|
||||
<Typography data-testid="hash-typography">#: {historyData[selectedIndex].Layer?.Digest}</Typography>
|
||||
) : (
|
||||
<Typography data-testid="no-hash-typography"></Typography>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
{!isLoaded ? <Loading /> : renderHistoryData()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -130,17 +130,7 @@ function PreviewCard(props) {
|
||||
{signatureCheck()} */}
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Stack alignItems="flex-end" justifyContent="space-between" direction="row">
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ fontSize: '0.875rem', lineHeight: '143%', letterSpacing: '0.010625rem' }}
|
||||
>
|
||||
Official
|
||||
</Typography>
|
||||
{/* <BookmarkBorderOutlinedIcon/> */}
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} mt={2}></Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
|
@ -7,24 +7,9 @@ import { api, endpoints } from '../api';
|
||||
|
||||
// components
|
||||
import Tags from './Tags.jsx';
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
CardContent,
|
||||
CardMedia,
|
||||
Chip,
|
||||
FormControl,
|
||||
Grid,
|
||||
IconButton,
|
||||
InputAdornment,
|
||||
OutlinedInput,
|
||||
Stack,
|
||||
Tab,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
import { Box, Card, CardContent, CardMedia, Chip, Grid, Stack, Tab, Typography } from '@mui/material';
|
||||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import { host } from '../host';
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
|
||||
// placeholder images
|
||||
import repocube1 from '../assets/repocube-1.png';
|
||||
@ -108,6 +93,7 @@ const useStyles = makeStyles(() => ({
|
||||
letterSpacing: '0.01rem'
|
||||
},
|
||||
inputForm: {
|
||||
textAlign: 'left',
|
||||
'& fieldset': {
|
||||
border: '0.125rem solid #52637A'
|
||||
}
|
||||
@ -135,7 +121,6 @@ function RepoDetails() {
|
||||
// @ts-ignore
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [selectedTab, setSelectedTab] = useState('Overview');
|
||||
|
||||
// get url param from <Route here (i.e. image name)
|
||||
const { name } = useParams();
|
||||
const abortController = useMemo(() => new AbortController(), []);
|
||||
@ -306,35 +291,6 @@ function RepoDetails() {
|
||||
{platformChips()}
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<Typography variant="body1" sx={{ color: '#52637A', fontSize: '1rem' }}>
|
||||
Copy and pull to pull this image
|
||||
</Typography>
|
||||
<FormControl sx={{ m: 1, paddingLeft: '1.5rem' }} variant="outlined">
|
||||
<OutlinedInput
|
||||
// value={`Pull ${name}`}
|
||||
value="N/A"
|
||||
className={classes.inputForm}
|
||||
sx={{ m: 1, width: '20.625rem', borderRadius: '0.5rem', color: '#14191F' }}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
aria-label="copy"
|
||||
edge="end"
|
||||
onClick={() => navigator.clipboard.writeText(`Pull ${name}`)}
|
||||
data-testid="pullcopy-btn"
|
||||
>
|
||||
<ContentCopyIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
aria-describedby="outlined-weight-helper-text"
|
||||
inputProps={{
|
||||
'aria-label': 'weight'
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container>
|
||||
<Grid item xs={8} className={classes.tabs}>
|
||||
@ -379,7 +335,7 @@ function RepoDetails() {
|
||||
<Grid item xs={4} className={classes.metadata}>
|
||||
<RepoDetailsMetadata
|
||||
// @ts-ignore
|
||||
weeklyDownloads={repoDetailData?.downloads}
|
||||
totalDownloads={repoDetailData?.downloads}
|
||||
// @ts-ignore
|
||||
repoURL={repoDetailData?.source}
|
||||
// @ts-ignore
|
||||
@ -398,5 +354,4 @@ function RepoDetails() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default RepoDetails;
|
||||
|
@ -35,7 +35,7 @@ const useStyles = makeStyles(() => ({
|
||||
|
||||
function RepoDetailsMetadata(props) {
|
||||
const classes = useStyles();
|
||||
const { repoURL, weeklyDownloads, lastUpdated, size } = props;
|
||||
const { repoURL, totalDownloads, lastUpdated, size } = props;
|
||||
// @ts-ignore
|
||||
const lastDate = (lastUpdated ? DateTime.fromISO(lastUpdated) : DateTime.now().minus({ days: 1 })).toRelative({
|
||||
unit: 'days'
|
||||
@ -58,10 +58,10 @@ function RepoDetailsMetadata(props) {
|
||||
<Card variant="outlined" className={classes.card}>
|
||||
<CardContent>
|
||||
<Typography variant="body2" align="left" className={classes.metadataHeader}>
|
||||
Weekly downloads
|
||||
Total downloads
|
||||
</Typography>
|
||||
<Typography variant="body1" align="left" className={classes.metadataBody}>
|
||||
{weeklyDownloads || `N/A`}
|
||||
{totalDownloads || `N/A`}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
@ -6,7 +6,21 @@ import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { api, endpoints } from '../api';
|
||||
|
||||
// components
|
||||
import { Box, Card, CardContent, CardMedia, Grid, Stack, Tab, Typography } from '@mui/material';
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
CardContent,
|
||||
CardMedia,
|
||||
Grid,
|
||||
FormControl,
|
||||
IconButton,
|
||||
Stack,
|
||||
Select,
|
||||
MenuItem,
|
||||
Tab,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import { host } from '../host';
|
||||
|
||||
@ -122,11 +136,12 @@ function TagDetails() {
|
||||
// @ts-ignore
|
||||
//const [isLoading, setIsLoading] = useState(false);
|
||||
const [selectedTab, setSelectedTab] = useState('Layers');
|
||||
const [fullName, setFullName] = useState('');
|
||||
const abortController = useMemo(() => new AbortController(), []);
|
||||
|
||||
// get url param from <Route here (i.e. image name)
|
||||
const { name, tag } = useParams();
|
||||
const [fullName, setFullName] = useState(name + ':' + tag);
|
||||
const [pullString, setPullString] = useState(`docker pull ${host()}/${fullName}`);
|
||||
const classes = useStyles();
|
||||
// const { description, overviewTitle, dependencies, dependents } = props;
|
||||
|
||||
@ -151,7 +166,6 @@ function TagDetails() {
|
||||
};
|
||||
setImageDetailData(imageData);
|
||||
setFullName(imageData.name + ':' + imageData.tag);
|
||||
|
||||
//setIsLoading(false);
|
||||
}
|
||||
})
|
||||
@ -187,6 +201,10 @@ function TagDetails() {
|
||||
setSelectedTab(newValue);
|
||||
};
|
||||
|
||||
const handleSelectionChange = (event) => {
|
||||
setPullString(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.pageWrapper}>
|
||||
<Card className={classes.cardRoot}>
|
||||
@ -227,6 +245,43 @@ function TagDetails() {
|
||||
}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<Stack direction="row">
|
||||
<Grid item xs={10}>
|
||||
<Typography variant="body1" sx={{ color: '#52637A', fontSize: '1rem', paddingTop: '0.5rem' }}>
|
||||
Copy and pull to pull this image
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<IconButton
|
||||
aria-label="copy"
|
||||
onClick={() => navigator.clipboard.writeText(pullString)}
|
||||
data-testid="pullcopy-btn"
|
||||
>
|
||||
<ContentCopyIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
</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 ${host()}/${fullName}`}>
|
||||
docker pull {host()}/{fullName}
|
||||
</MenuItem>
|
||||
<MenuItem value={`podman pull ${host()}/${fullName}`}>
|
||||
podman pull {host()}/{fullName}
|
||||
</MenuItem>
|
||||
<MenuItem value={`skopeo copy docker://${host()}/${fullName}`}>
|
||||
skopeo copy docker://{host()}/{fullName}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container>
|
||||
<Grid item xs={8} className={classes.tabs}>
|
||||
@ -238,13 +293,8 @@ function TagDetails() {
|
||||
sx={{ '& button.Mui-selected': { color: '#14191F', fontWeight: '600' } }}
|
||||
>
|
||||
<Tab value="Layers" label="Layers" className={classes.tabContent} />
|
||||
<Tab
|
||||
value="DependsOn"
|
||||
label="Dependencies"
|
||||
className={classes.tabContent}
|
||||
data-testid="dependencies-tab"
|
||||
/>
|
||||
<Tab value="IsDependentOn" label="Dependants" 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>
|
||||
|
Loading…
Reference in New Issue
Block a user