Implemented loading screen state accross app.
Signed-off-by: Raul Kele <raulkeleblk@gmail.com>
This commit is contained in:
parent
2a3320fb64
commit
dce87afba9
28
src/App.css
28
src/App.css
@ -18,7 +18,10 @@
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
animation: bounce 1s;
|
||||
animation-direction: alternate;
|
||||
animation-timing-function: cubic-bezier(.5, 0.05, 1, .5);
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,3 +48,26 @@
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes bounce {
|
||||
from {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
to {
|
||||
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;
|
||||
}
|
@ -9,6 +9,7 @@ import makeStyles from '@mui/styles/makeStyles';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { host } from '../host';
|
||||
import Monitor from '../assets/Monitor.png';
|
||||
import Loading from './Loading';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
card: {
|
||||
@ -69,9 +70,10 @@ function DependsOn(props) {
|
||||
const [images, setImages] = useState([]);
|
||||
const { name } = props;
|
||||
const classes = useStyles();
|
||||
// const [isLoaded, setIsLoaded] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
api
|
||||
.get(`${host()}${endpoints.dependsOnForImage(name)}`)
|
||||
.then((response) => {
|
||||
@ -79,12 +81,37 @@ function DependsOn(props) {
|
||||
let images = response.data.data.BaseImageList;
|
||||
setImages(images);
|
||||
}
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const renderDependencies = () => {
|
||||
return images?.length ? (
|
||||
<Card className={classes.card} raised>
|
||||
<CardContent>
|
||||
<Typography className={classes.content}>
|
||||
{images.map((dependence, index) => {
|
||||
return (
|
||||
<Link key={index} className={classes.link} to={`/image/${encodeURIComponent(dependence.RepoName)}`}>
|
||||
{dependence.RepoName}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div>
|
||||
<img src={Monitor} alt="Monitor" className={classes.monitor}></img>
|
||||
<Typography className={classes.none}> Nothing found </Typography>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div data-testid="depends-on-container">
|
||||
<Typography
|
||||
@ -101,26 +128,7 @@ function DependsOn(props) {
|
||||
variant="fullWidth"
|
||||
sx={{ margin: '5% 0% 5% 0%', background: 'rgba(0, 0, 0, 0.38)', height: '0.00625rem', width: '100%' }}
|
||||
/>
|
||||
{images?.length ? (
|
||||
<Card className={classes.card} raised>
|
||||
<CardContent>
|
||||
<Typography className={classes.content}>
|
||||
{images.map((dependence, index) => {
|
||||
return (
|
||||
<Link key={index} className={classes.link} to={`/image/${encodeURIComponent(dependence.RepoName)}`}>
|
||||
{dependence.RepoName}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div>
|
||||
<img src={Monitor} alt="Monitor" className={classes.monitor}></img>
|
||||
<Typography className={classes.none}> Nothing found </Typography>
|
||||
</div>
|
||||
)}
|
||||
{isLoading ? <Loading /> : renderDependencies()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ function Explore() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
api
|
||||
.get(`${host()}${endpoints.globalSearch({ searchQuery: search, filter: buildFilterQuery() })}`)
|
||||
.then((response) => {
|
||||
@ -89,10 +90,6 @@ function Explore() {
|
||||
});
|
||||
}, [search, queryParams, imageFilters, osFilters, archFilters]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
||||
const renderRepoCards = () => {
|
||||
return (
|
||||
exploreData &&
|
||||
@ -148,47 +145,50 @@ function Explore() {
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg">
|
||||
{isLoading && <Loading />}
|
||||
<Grid container className={classes.gridWrapper}>
|
||||
<Grid container item xs={12}>
|
||||
<Grid item xs={0}></Grid>
|
||||
<Grid item xs={12}>
|
||||
<Stack direction="row" className={classes.resultsRow}>
|
||||
<Typography variant="body2" className={classes.results}>
|
||||
Results {exploreData.length}
|
||||
</Typography>
|
||||
{/* <FormControl sx={{m:'1', minWidth:"4.6875rem"}} className={classes.sortForm} size="small">
|
||||
{isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<Grid container className={classes.gridWrapper}>
|
||||
<Grid container item xs={12}>
|
||||
<Grid item xs={0}></Grid>
|
||||
<Grid item xs={12}>
|
||||
<Stack direction="row" className={classes.resultsRow}>
|
||||
<Typography variant="body2" className={classes.results}>
|
||||
Results {exploreData.length}
|
||||
</Typography>
|
||||
{/* <FormControl sx={{m:'1', minWidth:"4.6875rem"}} className={classes.sortForm} size="small">
|
||||
<InputLabel>Sort</InputLabel>
|
||||
<Select label="Sort" value={sortFilter} onChange={handleSortChange} MenuProps={{disableScrollLock: true}}>
|
||||
<MenuItem value='relevance'>Relevance</MenuItem>
|
||||
</Select>
|
||||
</FormControl> */}
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container item xs={12} spacing={5} pt={1}>
|
||||
<Grid item xs={3}>
|
||||
{renderFilterCards()}
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
{!(exploreData && exploreData.length) ? (
|
||||
<Grid container className={classes.nodataWrapper}>
|
||||
<div style={{ marginTop: 20 }}>
|
||||
<div style={{}}>
|
||||
<Alert style={{ marginTop: 10, width: '100%' }} variant="outlined" severity="warning">
|
||||
Looks like we don't have anything matching that search. Try searching something else.
|
||||
</Alert>
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
) : (
|
||||
<Stack direction="column" spacing={2}>
|
||||
{renderRepoCards()}
|
||||
</Stack>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container item xs={12} spacing={5} pt={1}>
|
||||
<Grid item xs={3}>
|
||||
{renderFilterCards()}
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
{!(exploreData && exploreData.length) ? (
|
||||
<Grid container className={classes.nodataWrapper}>
|
||||
<div style={{ marginTop: 20 }}>
|
||||
<div style={{}}>
|
||||
<Alert style={{ marginTop: 10, width: '100%' }} variant="outlined" severity="warning">
|
||||
Looks like we don't have anything matching that search. Try searching something else.
|
||||
</Alert>
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
) : (
|
||||
<Stack direction="column" spacing={2}>
|
||||
{renderRepoCards()}
|
||||
</Stack>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import makeStyles from '@mui/styles/makeStyles';
|
||||
import { host } from '../host';
|
||||
import Monitor from '../assets/Monitor.png';
|
||||
import { isEmpty } from 'lodash';
|
||||
import Loading from './Loading';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
card: {
|
||||
@ -141,6 +142,35 @@ function HistoryLayers(props) {
|
||||
}
|
||||
}, [name]);
|
||||
|
||||
const renderHistoryData = () => {
|
||||
return (
|
||||
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>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography
|
||||
@ -181,30 +211,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>
|
||||
);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import React, { useEffect, useState } from 'react';
|
||||
import PreviewCard from './PreviewCard';
|
||||
import RepoCard from './RepoCard';
|
||||
import { mapToRepo } from 'utilities/objectModels';
|
||||
import Loading from './Loading';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
gridWrapper: {
|
||||
@ -61,11 +62,13 @@ const useStyles = makeStyles(() => ({
|
||||
}));
|
||||
|
||||
function Home({ data, updateData }) {
|
||||
// const [isLoading, setIsLoading] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [homeData, setHomeData] = useState([]);
|
||||
const classes = useStyles();
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
setIsLoading(true);
|
||||
api
|
||||
.get(`${host()}${endpoints.repoList}`)
|
||||
.then((response) => {
|
||||
@ -75,7 +78,7 @@ function Home({ data, updateData }) {
|
||||
return mapToRepo(responseRepo);
|
||||
});
|
||||
updateData(repoData);
|
||||
// setIsLoading(false);
|
||||
setIsLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
@ -149,31 +152,37 @@ function Home({ data, updateData }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack spacing={4} alignItems="center" className={classes.gridWrapper}>
|
||||
<Grid container item xs={12} sx={{ mt: 2, mb: 1 }} justifyContent="center">
|
||||
<Stack sx={{ display: 'inline' }} direction="row" justifyContent="center" spacing={1}>
|
||||
<Typography variant="h3" className={classes.title}>
|
||||
Most popular
|
||||
</Typography>
|
||||
<Typography variant="h3" className={classes.titleRed}>
|
||||
images
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid container spacing={1}>
|
||||
{renderPreviewCards()}
|
||||
</Grid>{' '}
|
||||
<Grid></Grid>
|
||||
{/* <Typography variant="h4" align="left" className={classes.sectionTitle}>
|
||||
<>
|
||||
{isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<Stack spacing={4} alignItems="center" className={classes.gridWrapper}>
|
||||
<Grid container item xs={12} sx={{ mt: 2, mb: 1 }} justifyContent="center">
|
||||
<Stack sx={{ display: 'inline' }} direction="row" justifyContent="center" spacing={1}>
|
||||
<Typography variant="h3" className={classes.title}>
|
||||
Most popular
|
||||
</Typography>
|
||||
<Typography variant="h3" className={classes.titleRed}>
|
||||
images
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid container spacing={1}>
|
||||
{renderPreviewCards()}
|
||||
</Grid>{' '}
|
||||
<Grid></Grid>
|
||||
{/* <Typography variant="h4" align="left" className={classes.sectionTitle}>
|
||||
Bookmarks
|
||||
</Typography>
|
||||
{renderBookmarks()} */}
|
||||
<Stack></Stack>
|
||||
<Typography variant="h4" align="left" className={classes.sectionTitle}>
|
||||
Recently updated repositories
|
||||
</Typography>
|
||||
{renderRecentlyUpdated()}
|
||||
</Stack>
|
||||
<Stack></Stack>
|
||||
<Typography variant="h4" align="left" className={classes.sectionTitle}>
|
||||
Recently updated repositories
|
||||
</Typography>
|
||||
{renderRecentlyUpdated()}
|
||||
</Stack>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import makeStyles from '@mui/styles/makeStyles';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { host } from '../host';
|
||||
import Monitor from '../assets/Monitor.png';
|
||||
import Loading from './Loading';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
card: {
|
||||
@ -69,9 +70,10 @@ function IsDependentOn(props) {
|
||||
const [images, setImages] = useState([]);
|
||||
const { name } = props;
|
||||
const classes = useStyles();
|
||||
//const [isLoaded, setIsLoaded] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
api
|
||||
.get(`${host()}${endpoints.isDependentOnForImage(name)}`)
|
||||
.then((response) => {
|
||||
@ -79,14 +81,37 @@ function IsDependentOn(props) {
|
||||
let images = response.data.data.DerivedImageList;
|
||||
setImages(images);
|
||||
}
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
//setImages([]);
|
||||
setIsLoading(false);
|
||||
});
|
||||
//setIsLoaded(true);
|
||||
}, []);
|
||||
|
||||
const renderDependents = () => {
|
||||
return images?.length ? (
|
||||
<Card className={classes.card} raised>
|
||||
<CardContent>
|
||||
<Typography className={classes.content}>
|
||||
{images.map((dependence, index) => {
|
||||
return (
|
||||
<Link key={index} to={`/image/${encodeURIComponent(dependence.RepoName)}`} className={classes.link}>
|
||||
{dependence.RepoName}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div>
|
||||
<img src={Monitor} alt="Monitor" className={classes.monitor}></img>
|
||||
<Typography className={classes.none}> Nothing found </Typography>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Typography
|
||||
@ -103,27 +128,7 @@ function IsDependentOn(props) {
|
||||
variant="fullWidth"
|
||||
sx={{ margin: '5% 0% 5% 0%', background: 'rgba(0, 0, 0, 0.38)', height: '0.00625rem', width: '100%' }}
|
||||
/>
|
||||
|
||||
{images?.length ? (
|
||||
<Card className={classes.card} raised>
|
||||
<CardContent>
|
||||
<Typography className={classes.content}>
|
||||
{images.map((dependence, index) => {
|
||||
return (
|
||||
<Link key={index} to={`/image/${encodeURIComponent(dependence.RepoName)}`} className={classes.link}>
|
||||
{dependence.RepoName}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div>
|
||||
<img src={Monitor} alt="Monitor" className={classes.monitor}></img>
|
||||
<Typography className={classes.none}> Nothing found </Typography>
|
||||
</div>
|
||||
)}
|
||||
{isLoading ? <Loading /> : renderDependents()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import logo from '../assets/Zot2.svg';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
wrapper: {
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
position: 'relative',
|
||||
top: '10%',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
@ -13,9 +13,8 @@ const useStyles = makeStyles(() => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 6,
|
||||
paddingRight: 20,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.3)'
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -33,6 +33,7 @@ import repocube3 from '../assets/repocube-3.png';
|
||||
import repocube4 from '../assets/repocube-4.png';
|
||||
import { TabContext, TabList, TabPanel } from '@mui/lab';
|
||||
import RepoDetailsMetadata from './RepoDetailsMetadata';
|
||||
import Loading from './Loading';
|
||||
|
||||
// @ts-ignore
|
||||
const useStyles = makeStyles(() => ({
|
||||
@ -132,7 +133,7 @@ const randomImage = () => {
|
||||
function RepoDetails() {
|
||||
const [repoDetailData, setRepoDetailData] = useState({});
|
||||
// @ts-ignore
|
||||
//const [isLoading, setIsLoading] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [selectedTab, setSelectedTab] = useState('Overview');
|
||||
|
||||
// get url param from <Route here (i.e. image name)
|
||||
@ -150,8 +151,6 @@ function RepoDetails() {
|
||||
images: repoInfo.Images,
|
||||
lastUpdated: repoInfo.Summary?.LastUpdated,
|
||||
size: repoInfo.Summary?.Size,
|
||||
//latestDigest: repoInfo.Summary?.NewestImage.Digest,
|
||||
//layers: repoInfo.Summary?.NewestImage.Layers,
|
||||
platforms: repoInfo.Summary?.Platforms,
|
||||
vendors: repoInfo.Summary?.Vendors,
|
||||
newestTag: repoInfo.Summary?.NewestImage,
|
||||
@ -162,12 +161,13 @@ function RepoDetails() {
|
||||
overview: repoInfo.Summary?.NewestImage.Documentation
|
||||
};
|
||||
setRepoDetailData(imageData);
|
||||
//setIsLoading(false);
|
||||
}
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
setRepoDetailData({});
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, [name]);
|
||||
//function that returns a random element from an array
|
||||
@ -261,100 +261,104 @@ function RepoDetails() {
|
||||
// };
|
||||
|
||||
return (
|
||||
<div className={classes.pageWrapper}>
|
||||
<Card className={classes.cardRoot}>
|
||||
<CardContent>
|
||||
<Grid container className={classes.header}>
|
||||
<Grid item xs={8}>
|
||||
<Stack alignItems="center" direction="row" spacing={2}>
|
||||
<CardMedia
|
||||
classes={{
|
||||
root: classes.media,
|
||||
img: classes.avatar
|
||||
}}
|
||||
component="img"
|
||||
image={randomImage()}
|
||||
alt="icon"
|
||||
/>
|
||||
<Typography variant="h3" className={classes.repoName}>
|
||||
{name}
|
||||
</Typography>
|
||||
{/* {vulnerabilityCheck()}
|
||||
<>
|
||||
{isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<div className={classes.pageWrapper}>
|
||||
<Card className={classes.cardRoot}>
|
||||
<CardContent>
|
||||
<Grid container className={classes.header}>
|
||||
<Grid item xs={8}>
|
||||
<Stack alignItems="center" direction="row" spacing={2}>
|
||||
<CardMedia
|
||||
classes={{
|
||||
root: classes.media,
|
||||
img: classes.avatar
|
||||
}}
|
||||
component="img"
|
||||
image={randomImage()}
|
||||
alt="icon"
|
||||
/>
|
||||
<Typography variant="h3" className={classes.repoName}>
|
||||
{name}
|
||||
</Typography>
|
||||
{/* {vulnerabilityCheck()}
|
||||
{signatureCheck()} */}
|
||||
{/* <BookmarkIcon sx={{color:"#52637A"}}/> */}
|
||||
</Stack>
|
||||
<Typography
|
||||
pt={1}
|
||||
sx={{ fontSize: 16, lineHeight: '1.5rem', color: 'rgba(0, 0, 0, 0.6)', paddingLeft: '4rem' }}
|
||||
gutterBottom
|
||||
align="left"
|
||||
>
|
||||
{
|
||||
// @ts-ignore
|
||||
repoDetailData?.title || 'N/A'
|
||||
}
|
||||
</Typography>
|
||||
<Stack alignItems="center" sx={{ paddingLeft: '4rem' }} direction="row" spacing={2} pt={1}>
|
||||
{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}>
|
||||
<TabContext value={selectedTab}>
|
||||
<Box>
|
||||
<TabList
|
||||
onChange={handleTabChange}
|
||||
TabIndicatorProps={{ className: classes.selectedTab }}
|
||||
sx={{ '& button.Mui-selected': { color: '#14191F', fontWeight: '600' } }}
|
||||
{/* <BookmarkIcon sx={{color:"#52637A"}}/> */}
|
||||
</Stack>
|
||||
<Typography
|
||||
pt={1}
|
||||
sx={{ fontSize: 16, lineHeight: '1.5rem', color: 'rgba(0, 0, 0, 0.6)', paddingLeft: '4rem' }}
|
||||
gutterBottom
|
||||
align="left"
|
||||
>
|
||||
<Tab value="Overview" label="Overview" className={classes.tabContent} />
|
||||
<Tab value="Tags" label="Tags" className={classes.tabContent} />
|
||||
{/* <Tab value="Dependencies" label={`${dependencies || 0} Dependencies`} className={classes.tabContent}/>
|
||||
{
|
||||
// @ts-ignore
|
||||
repoDetailData?.title || 'N/A'
|
||||
}
|
||||
</Typography>
|
||||
<Stack alignItems="center" sx={{ paddingLeft: '4rem' }} direction="row" spacing={2} pt={1}>
|
||||
{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}>
|
||||
<TabContext value={selectedTab}>
|
||||
<Box>
|
||||
<TabList
|
||||
onChange={handleTabChange}
|
||||
TabIndicatorProps={{ className: classes.selectedTab }}
|
||||
sx={{ '& button.Mui-selected': { color: '#14191F', fontWeight: '600' } }}
|
||||
>
|
||||
<Tab value="Overview" label="Overview" 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>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<TabPanel value="Overview" className={classes.tabPanel}>
|
||||
{renderOverview()}
|
||||
</TabPanel>
|
||||
<TabPanel value="Tags" className={classes.tabPanel}>
|
||||
<Tags data={repoDetailData} />
|
||||
</TabPanel>
|
||||
{/* <TabPanel value="Dependencies" className={classes.tabPanel}>
|
||||
</TabList>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<TabPanel value="Overview" className={classes.tabPanel}>
|
||||
{renderOverview()}
|
||||
</TabPanel>
|
||||
<TabPanel value="Tags" className={classes.tabPanel}>
|
||||
<Tags data={repoDetailData} />
|
||||
</TabPanel>
|
||||
{/* <TabPanel value="Dependencies" className={classes.tabPanel}>
|
||||
{renderDependencies()}
|
||||
</TabPanel>
|
||||
<TabPanel value="Dependents" className={classes.tabPanel}>
|
||||
@ -363,29 +367,31 @@ function RepoDetails() {
|
||||
<TabPanel value="Vulnerabilities" className={classes.tabPanel}>
|
||||
{renderVulnerabilities()}
|
||||
</TabPanel> */}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</TabContext>
|
||||
</Grid>
|
||||
<Grid item xs={4} className={classes.metadata}>
|
||||
<RepoDetailsMetadata
|
||||
// @ts-ignore
|
||||
weeklyDownloads={repoDetailData?.downloads}
|
||||
// @ts-ignore
|
||||
repoURL={repoDetailData?.source}
|
||||
// @ts-ignore
|
||||
lastUpdated={repoDetailData?.lastUpdated}
|
||||
// @ts-ignore
|
||||
size={repoDetailData?.size}
|
||||
// @ts-ignore
|
||||
latestTag={repoDetailData?.newestTag}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</TabContext>
|
||||
</Grid>
|
||||
<Grid item xs={4} className={classes.metadata}>
|
||||
<RepoDetailsMetadata
|
||||
// @ts-ignore
|
||||
weeklyDownloads={repoDetailData?.downloads}
|
||||
// @ts-ignore
|
||||
repoURL={repoDetailData?.source}
|
||||
// @ts-ignore
|
||||
lastUpdated={repoDetailData?.lastUpdated}
|
||||
// @ts-ignore
|
||||
size={repoDetailData?.size}
|
||||
// @ts-ignore
|
||||
latestTag={repoDetailData?.newestTag}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import git from '../assets/Git.png';
|
||||
// styling
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Card, CardContent } from '@mui/material';
|
||||
import Loading from './Loading';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
cardContainer: {
|
||||
@ -105,11 +106,14 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
|
||||
const [password, setPassword] = useState(null);
|
||||
const [requestProcessing, setRequestProcessing] = useState(false);
|
||||
const [requestError, setRequestError] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
const classes = useStyles();
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
if (isAuthEnabled && isLoggedIn) {
|
||||
setIsLoading(false);
|
||||
navigate('/home');
|
||||
} else {
|
||||
api
|
||||
@ -118,11 +122,13 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
|
||||
if (response.status === 200) {
|
||||
setIsAuthEnabled(false);
|
||||
setIsLoggedIn(true);
|
||||
setIsLoading(false);
|
||||
navigate('/home');
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setIsAuthEnabled(true);
|
||||
setIsLoading(false);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
@ -190,132 +196,136 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se
|
||||
|
||||
return (
|
||||
<Box className={classes.cardContainer} data-testid="signin-container">
|
||||
<Card className={classes.loginCard}>
|
||||
<CardContent className={classes.loginCardContent}>
|
||||
<CssBaseline />
|
||||
<Typography align="left" className={classes.text} component="h1" variant="h4">
|
||||
Sign in
|
||||
</Typography>
|
||||
<Typography align="left" className={classes.subtext} variant="body1" gutterBottom>
|
||||
Welcome back! Please enter your details.
|
||||
</Typography>
|
||||
{isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<Card className={classes.loginCard}>
|
||||
<CardContent className={classes.loginCardContent}>
|
||||
<CssBaseline />
|
||||
<Typography align="left" className={classes.text} component="h1" variant="h4">
|
||||
Sign in
|
||||
</Typography>
|
||||
<Typography align="left" className={classes.subtext} variant="body1" gutterBottom>
|
||||
Welcome back! Please enter your details.
|
||||
</Typography>
|
||||
|
||||
<Box component="form" onSubmit={null} noValidate autoComplete="off" sx={{ mt: 1 }}>
|
||||
<div>
|
||||
<Button
|
||||
<Box component="form" onSubmit={null} noValidate autoComplete="off" sx={{ mt: 1 }}>
|
||||
<div>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 3,
|
||||
mb: 1,
|
||||
background: '#161614',
|
||||
'&:hover': {
|
||||
backgroundColor: '#1565C0',
|
||||
color: '#FFFFFF'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
Continue with GitHub
|
||||
<img src={git} alt="git logo" className={classes.gitLogo}></img>
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 1,
|
||||
mb: 1,
|
||||
background: 'transparent',
|
||||
color: '#52637A',
|
||||
'&:hover': {
|
||||
backgroundColor: '#1565C0',
|
||||
color: '#FFFFFF'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
Continue with Google
|
||||
<img src={google} alt="google logo" className={classes.gitLogo}></img>
|
||||
</Button>
|
||||
</div>
|
||||
<br></br>
|
||||
<h2 className={classes.line}>
|
||||
<span className={classes.lineSpan}>or</span>
|
||||
</h2>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 3,
|
||||
mb: 1,
|
||||
background: '#161614',
|
||||
'&:hover': {
|
||||
backgroundColor: '#1565C0',
|
||||
color: '#FFFFFF'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
Continue with GitHub
|
||||
<img src={git} alt="git logo" className={classes.gitLogo}></img>
|
||||
</Button>
|
||||
<Button
|
||||
id="username"
|
||||
label="Username"
|
||||
name="username"
|
||||
className={classes.textField}
|
||||
onInput={(e) => handleChange(e, 'username')}
|
||||
error={usernameError != null}
|
||||
helperText={usernameError}
|
||||
/>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 1,
|
||||
mb: 1,
|
||||
background: 'transparent',
|
||||
color: '#52637A',
|
||||
'&:hover': {
|
||||
backgroundColor: '#1565C0',
|
||||
color: '#FFFFFF'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
Continue with Google
|
||||
<img src={google} alt="google logo" className={classes.gitLogo}></img>
|
||||
</Button>
|
||||
</div>
|
||||
<br></br>
|
||||
<h2 className={classes.line}>
|
||||
<span className={classes.lineSpan}>or</span>
|
||||
</h2>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
id="username"
|
||||
label="Username"
|
||||
name="username"
|
||||
className={classes.textField}
|
||||
onInput={(e) => handleChange(e, 'username')}
|
||||
error={usernameError != null}
|
||||
helperText={usernameError}
|
||||
/>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
name="password"
|
||||
label="Enter password"
|
||||
type="password"
|
||||
id="password"
|
||||
className={classes.textField}
|
||||
onInput={(e) => handleChange(e, 'password')}
|
||||
error={passwordError != null}
|
||||
helperText={passwordError}
|
||||
/>
|
||||
{requestProcessing && <CircularProgress style={{ marginTop: 20 }} color="secondary" />}
|
||||
{requestError && (
|
||||
<Alert style={{ marginTop: 20 }} severity="error">
|
||||
Authentication Failed. Please try again.
|
||||
</Alert>
|
||||
)}
|
||||
<div>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 3,
|
||||
mb: 1,
|
||||
background: '#1479FF',
|
||||
'&:hover': {
|
||||
backgroundColor: '#1565C0'
|
||||
}
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{' '}
|
||||
Continue
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 1,
|
||||
mb: 1,
|
||||
background: 'transparent',
|
||||
color: '#52637A',
|
||||
'&:hover': {
|
||||
backgroundColor: '#EFEFEF',
|
||||
color: '#52637A'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
Continue as guest
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
<TermsOfService sx={{ mt: 2, mb: 4 }} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
name="password"
|
||||
label="Enter password"
|
||||
type="password"
|
||||
id="password"
|
||||
className={classes.textField}
|
||||
onInput={(e) => handleChange(e, 'password')}
|
||||
error={passwordError != null}
|
||||
helperText={passwordError}
|
||||
/>
|
||||
{requestProcessing && <CircularProgress style={{ marginTop: 20 }} color="secondary" />}
|
||||
{requestError && (
|
||||
<Alert style={{ marginTop: 20 }} severity="error">
|
||||
Authentication Failed. Please try again.
|
||||
</Alert>
|
||||
)}
|
||||
<div>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 3,
|
||||
mb: 1,
|
||||
background: '#1479FF',
|
||||
'&:hover': {
|
||||
backgroundColor: '#1565C0'
|
||||
}
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{' '}
|
||||
Continue
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
className={classes.button}
|
||||
sx={{
|
||||
mt: 1,
|
||||
mb: 1,
|
||||
background: 'transparent',
|
||||
color: '#52637A',
|
||||
'&:hover': {
|
||||
backgroundColor: '#EFEFEF',
|
||||
color: '#52637A'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
Continue as guest
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
<TermsOfService sx={{ mt: 2, mb: 4 }} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import PestControlIcon from '@mui/icons-material/PestControl';
|
||||
import Monitor from '../assets/Monitor.png';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Loading from './Loading';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
card: {
|
||||
@ -258,10 +259,11 @@ function VulnerabilitiyCard(props) {
|
||||
function VulnerabilitiesDetails(props) {
|
||||
const classes = useStyles();
|
||||
const [cveData, setCveData] = useState({});
|
||||
// const [isLoading, setIsLoading] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const { name } = props;
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
api
|
||||
.get(`${host()}${endpoints.vulnerabilitiesForRepo(name)}`)
|
||||
.then((response) => {
|
||||
@ -271,7 +273,7 @@ function VulnerabilitiesDetails(props) {
|
||||
cveList: cveInfo?.CVEList
|
||||
};
|
||||
setCveData(cveListData);
|
||||
// setIsLoading(false);
|
||||
setIsLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
@ -323,9 +325,13 @@ function VulnerabilitiesDetails(props) {
|
||||
width: '100%'
|
||||
}}
|
||||
/>
|
||||
{renderCVEs(
|
||||
// @ts-ignore
|
||||
cveData?.cveList
|
||||
{isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
renderCVEs(
|
||||
// @ts-ignore
|
||||
cveData?.cveList
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user