diff --git a/src/__tests__/LoginPage/SignIn.test.js b/src/__tests__/LoginPage/SignIn.test.js index 8791008e..901251dd 100644 --- a/src/__tests__/LoginPage/SignIn.test.js +++ b/src/__tests__/LoginPage/SignIn.test.js @@ -71,7 +71,7 @@ describe('Sign in form', () => { it('should log in the user and navigate to homepage if login is successful',async () => { render( { }} isLoggedIn={false} setIsLoggedIn={() => { }} />); - const submitButton = await screen.findByText(/^Continue/i); + const submitButton = await screen.findByText('Continue'); // @ts-ignore jest.spyOn(api,"get").mockResolvedValue({status:200, data:{data:{}}}); fireEvent.click(submitButton); @@ -82,7 +82,7 @@ describe('Sign in form', () => { it('should should display login error if login not successful',async () => { render( { }} isLoggedIn={false} setIsLoggedIn={() => { }} />); - const submitButton = await screen.findByText(/^Continue/i); + const submitButton = await screen.findByText('Continue'); jest.spyOn(api,"get").mockRejectedValue();; fireEvent.click(submitButton); const errorDisplay = await screen.findByText(/Authentication Failed/i); diff --git a/src/__tests__/RepoPage/Tags.test.js b/src/__tests__/RepoPage/Tags.test.js index 05875e42..c7897598 100644 --- a/src/__tests__/RepoPage/Tags.test.js +++ b/src/__tests__/RepoPage/Tags.test.js @@ -2,6 +2,13 @@ import { fireEvent, render, screen } from '@testing-library/react'; import Tags from 'components/Tags'; import React from 'react'; +const mockedUsedNavigate = jest.fn(); +jest.mock('react-router-dom', () => ({ + // @ts-ignore + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockedUsedNavigate, +})); + const mockedTagsData = { name: 'test', tags: [ diff --git a/src/api.js b/src/api.js index 35c6fa3a..1215585a 100644 --- a/src/api.js +++ b/src/api.js @@ -61,8 +61,8 @@ const api = { }; const endpoints = { - imageList: '/v2/_zot/ext/search?query={RepoListWithNewestImage () { NewestImage {RepoName Tag LastUpdated Description Licenses Vendor Size Labels} }}', - detailedRepoInfo: (name) => `/v2/_zot/ext/search?query={ExpandedRepoInfo(repo:"${name}"){Images {Digest Tag Layers {Size Digest}} Summary {Name LastUpdated Size Platforms {Os Arch} Vendors NewestTag {Tag}}}}` + imageList: '/v2/_zot/ext/search?query={RepoListWithNewestImage(){ NewestImage {RepoName Tag LastUpdated Description Licenses Vendor Size Labels} }}', + 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 {Tag}}}}` } export {api, endpoints}; diff --git a/src/assets/Git.png b/src/assets/Git.png new file mode 100644 index 00000000..b6fa4639 Binary files /dev/null and b/src/assets/Git.png differ diff --git a/src/assets/Google.png b/src/assets/Google.png new file mode 100644 index 00000000..f9eb8bf3 Binary files /dev/null and b/src/assets/Google.png differ diff --git a/src/assets/Zot-white-text.png b/src/assets/Zot-white-text.png new file mode 100644 index 00000000..87ded54c Binary files /dev/null and b/src/assets/Zot-white-text.png differ diff --git a/src/assets/Zot-white-text.svg b/src/assets/Zot-white-text.svg new file mode 100644 index 00000000..94ce6425 --- /dev/null +++ b/src/assets/Zot-white-text.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/Zot-white.svg b/src/assets/Zot-white.svg new file mode 100644 index 00000000..62517ec7 --- /dev/null +++ b/src/assets/Zot-white.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/backgroundSignIn.png b/src/assets/backgroundSignIn.png new file mode 100644 index 00000000..60f435dd Binary files /dev/null and b/src/assets/backgroundSignIn.png differ diff --git a/src/assets/codeReviewSignIn.png b/src/assets/codeReviewSignIn.png new file mode 100644 index 00000000..28d3b2df Binary files /dev/null and b/src/assets/codeReviewSignIn.png differ diff --git a/src/assets/zot-white.png b/src/assets/zot-white.png index 6c553137..d5761c7f 100644 Binary files a/src/assets/zot-white.png and b/src/assets/zot-white.png differ diff --git a/src/components/Explore.jsx b/src/components/Explore.jsx index f6227846..cbcfec7a 100644 --- a/src/components/Explore.jsx +++ b/src/components/Explore.jsx @@ -19,7 +19,7 @@ import FilterCard from './FilterCard.jsx'; const useStyles = makeStyles(() => ({ gridWrapper: { - // backgroundColor: "#fff", + paddingTop:"2rem", }, nodataWrapper: { backgroundColor: "#fff", @@ -34,7 +34,15 @@ const useStyles = makeStyles(() => ({ justifyContent:"space-between", alignItems:"center", color:"#00000099" - } + }, + results:{ + marginLeft: '1rem' + }, + sortForm:{ + backgroundColor: '#ffffff', + borderColor: "#E0E0E0", + borderRadius: "6px", + }, })); function Explore ({ keywords, data, updateData }) { @@ -141,10 +149,10 @@ function Explore ({ keywords, data, updateData }) { - Results {filteredData.length} - + Results {filteredData.length} + Sort - Relevance diff --git a/src/components/ExploreHeader.jsx b/src/components/ExploreHeader.jsx index c70abcd8..05cc3fe4 100644 --- a/src/components/ExploreHeader.jsx +++ b/src/components/ExploreHeader.jsx @@ -1,9 +1,10 @@ // react global -import {Link, useLocation} from "react-router-dom"; +import {Link, useLocation, useNavigate} from "react-router-dom"; // components import {Typography, Breadcrumbs} from '@mui/material'; import NavigateNextIcon from '@mui/icons-material/NavigateNext'; +import ArrowBackIcon from '@mui/icons-material/ArrowBack'; // styling @@ -15,13 +16,16 @@ const useStyles = makeStyles((theme) => { exploreHeader: { backgroundColor: "#FFFFFF", minHeight: 50, - paddingLeft: 5, + paddingLeft: "3rem", display: "flex", + flexDirection: "row", alignItems: "center", - justifyContent: "center" + justifyContent: "space-between", + padding: "2rem" }, explore: { - color: '#00000099', + color: '#52637A', + fontSize: "1rem", letterSpacing: "0.009375rem" } } @@ -29,15 +33,18 @@ const useStyles = makeStyles((theme) => { function ExploreHeader() { const classes = useStyles(); + const navigate = useNavigate(); const location = useLocation(); const path = location.pathname; return (
+ navigate(-1)}/> Home { path.includes('/image/') && {path.replace('/image/', '')} } +
); } diff --git a/src/components/FilterCard.jsx b/src/components/FilterCard.jsx index c8317610..ee7b7fd0 100644 --- a/src/components/FilterCard.jsx +++ b/src/components/FilterCard.jsx @@ -9,7 +9,9 @@ const useStyles = makeStyles(() => ({ alignItems:'flex-start', background:"#FFFFFF", boxShadow:"0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)", - borderRadius: "1.5rem" + borderColor: "#FFFFFF", + borderRadius: "1.5rem", + color: "#14191F", } })); diff --git a/src/components/Header.jsx b/src/components/Header.jsx index 67dfb9d1..67dc98f3 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -9,7 +9,7 @@ import Avatar from '@mui/material/Avatar'; // styling import makeStyles from '@mui/styles/makeStyles'; -import logo from '../assets/Zot2.svg'; +import logo from '../assets/Zot-white-text.svg'; import placeholderProfileButton from '../assets/Profile_button_placeholder.svg'; @@ -38,7 +38,7 @@ const useStyles = makeStyles((theme) => ({ flexDirection: "row" }, searchIcon: { - color: "#A53692", + color: "#52637A", paddingRight: "3%" }, input: { @@ -57,12 +57,12 @@ const useStyles = makeStyles((theme) => ({ logoWrapper: { }, logo: { - height: 64, - width: 64, + width: "143px", + }, userAvatar:{ height:46, - width:46 + width:46, }, link: { color: "#000", diff --git a/src/components/Home.jsx b/src/components/Home.jsx index 85d78505..139085ec 100644 --- a/src/components/Home.jsx +++ b/src/components/Home.jsx @@ -1,162 +1,204 @@ -import { Grid, Stack, Typography } from '@mui/material'; -import { makeStyles } from '@mui/styles'; -import { api, endpoints } from 'api'; -import { host } from '../host'; -import {isEmpty} from 'lodash'; -import React, { useEffect, useState } from 'react'; -import PreviewCard from './PreviewCard'; -import RepoCard from './RepoCard'; - +import { Grid, Stack, Typography } from "@mui/material"; +import { makeStyles } from "@mui/styles"; +import { api, endpoints } from "api"; +import { host } from "../host"; +import { isEmpty } from "lodash"; +import React, { useEffect, useState } from "react"; +import PreviewCard from "./PreviewCard"; +import RepoCard from "./RepoCard"; const useStyles = makeStyles(() => ({ gridWrapper: { - marginTop:10 + marginTop: 10, }, nodataWrapper: { backgroundColor: "#fff", - height: '100vh', + height: "100vh", }, exploreText: { - color: '#C0C0C0', + color: "#C0C0C0", display: "flex", alignItems: "left", }, resultsRow: { - justifyContent:"space-between", - alignItems:"center", - color:"#00000099" + justifyContent: "space-between", + alignItems: "center", + color: "#00000099", }, title: { - fontWeight:"700", - color:"#000000DE", - width:"100%", + fontWeight: "700", + color: "#0F2139", + width: "100%", + display: "inline", + fontSize: "2.5rem", + textAlign: "center", + letterSpacing: "-0.02rem", }, - sectionTitle:{ - fontWeight:"700", - color:"#000000DE", - width:"100%" + titleRed: { + fontWeight: "700", + color: "#D83C0E", + width: "100%", + display: "inline", + fontSize: "2.5rem", + textAlign: "center", + letterSpacing: "-0.02rem", + }, + sectionTitle: { + fontWeight: "700", + color: "#000000DE", + width: "100%", }, subtitle: { - color:"#00000099", - fontWeight:400, - fontSize:"1rem", - textAlign:"center", - lineHeight:"150%", - letterSpacing:"0.009375rem", - width:"65%", - } + color: "#00000099", + fontWeight: 400, + fontSize: "1rem", + textAlign: "center", + lineHeight: "150%", + letterSpacing: "0.009375rem", + width: "65%", + }, })); -function Home ({ keywords, data, updateData }) { +function Home({ keywords, data, updateData }) { const [isLoading, setIsLoading] = useState(true); const [homeData, setHomeData] = useState([]); const filterStr = keywords && keywords.toLocaleLowerCase(); const classes = useStyles(); useEffect(() => { - api.get(`${host()}${endpoints.imageList}`) - .then(response => { + api + .get(`${host()}${endpoints.imageList}`) + .then((response) => { if (response.data && response.data.data) { - let imageList = response.data.data.RepoListWithNewestImage; - let imagesData = imageList.map((image) => { - return { - name: image.NewestImage.RepoName, - latestVersion: image.NewestImage.Tag, - tags: image.NewestImage.Labels, - description: image.NewestImage.Description, - licenses: image.NewestImage.Licenses, - size: image.NewestImage.Size, - vendor: image.NewestImage.Vendor, - lastUpdated: image.NewestImage.LastUpdated - }; - }); - updateData(imagesData); - setIsLoading(false); + let imageList = response.data.data.RepoListWithNewestImage; + let imagesData = imageList.map((image) => { + return { + name: image.NewestImage.RepoName, + latestVersion: image.NewestImage.Tag, + tags: image.NewestImage.Labels, + description: image.NewestImage.Description, + licenses: image.NewestImage.Licenses, + size: image.NewestImage.Size, + vendor: image.NewestImage.Vendor, + lastUpdated: image.NewestImage.LastUpdated, + }; + }); + updateData(imagesData); + setIsLoading(false); } }) .catch((e) => { console.error(e); - }) - },[]) + }); + }, []); useEffect(() => { setIsLoading(false); }, []); - + useEffect(() => { - const filtered = data && data.filter((item) => { + const filtered = + data && + data.filter((item) => { return ( - isEmpty(keywords) || - (item.name && item.name.toLocaleLowerCase().indexOf(filterStr) >= 0 ) || - (item.appID && item.appID.toLocaleLowerCase().indexOf(filterStr) >= 0) || - (item.appId && item.appId.toLocaleLowerCase().indexOf(filterStr) >= 0) - ) - }); + isEmpty(keywords) || + (item.name && + item.name.toLocaleLowerCase().indexOf(filterStr) >= 0) || + (item.appID && + item.appID.toLocaleLowerCase().indexOf(filterStr) >= 0) || + (item.appId && item.appId.toLocaleLowerCase().indexOf(filterStr) >= 0) + ); + }); setHomeData(filtered); }, [keywords, data]); const renderPreviewCards = () => { - return homeData && homeData.slice(0,4).map((item, index) => { - return ( - - ) - }); + return ( + homeData && + homeData.slice(0, 4).map((item, index) => { + return ( + + + + ); + }) + ); }; const renderBookmarks = () => { - return homeData && homeData.slice(0,2).map((item,index) => { - return ( - - ) - }); - } + return ( + homeData && + homeData.slice(0, 2).map((item, index) => { + return ( + + ); + }) + ); + }; const renderRecentlyUpdated = () => { - return homeData && homeData.slice(0,2).map((item,index) => { - return ( - - ) - }); - } + return ( + homeData && + homeData.slice(0, 2).map((item, index) => { + return ( + + ); + }) + ); + }; return ( - - - Most popular repositories - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Amet, dis pellentesque posuere nulla tortor ac eu arcu nunc. A potenti ridiculus vitae, ut venenatis in ut interdum eros. + + + + Most popular + + + images + - - {renderPreviewCards()} + + {renderPreviewCards()} + - Bookmarks + + Bookmarks + {renderBookmarks()} - Recently updated repositories + + + Recently updated repositories + {renderRecentlyUpdated()} ); } -export default Home; \ No newline at end of file +export default Home; diff --git a/src/components/PreviewCard.jsx b/src/components/PreviewCard.jsx index bf96ef1c..7b3d50e6 100644 --- a/src/components/PreviewCard.jsx +++ b/src/components/PreviewCard.jsx @@ -1,8 +1,13 @@ -import { Card, CardActionArea, CardContent, CardMedia, Grid, Stack, Typography } from '@mui/material'; +import { Card, CardActionArea, CardContent, CardMedia, Grid, Stack, Typography, Box } from '@mui/material'; import { makeStyles } from '@mui/styles'; import React from 'react'; import { useNavigate } from 'react-router-dom'; -import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined'; +import BookmarkBorderOutlinedIcon from '@mui/icons-material/BookmarkBorderOutlined'; +import PestControlOutlinedIcon from '@mui/icons-material/PestControlOutlined'; +import PestControlIcon from '@mui/icons-material/PestControl'; +import GppBadOutlinedIcon from '@mui/icons-material/GppBadOutlined'; +import GppGoodOutlinedIcon from '@mui/icons-material/GppGoodOutlined'; +import GppMaybeOutlinedIcon from '@mui/icons-material/GppMaybeOutlined'; // placeholder images import repocube1 from '../assets/repocube-1.png'; @@ -29,6 +34,7 @@ const useStyles = makeStyles(() => ({ background: "#FFFFFF", boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)", borderRadius: "1.5rem", + borderColor: "#FFFFFF", flex: "none", alignSelf: "stretch", flexGrow: 0, @@ -60,6 +66,11 @@ const useStyles = makeStyles(() => ({ } })); +//function that returns a random element from an array +function getRandom (list) { + return list[Math.floor((Math.random()*list.length))]; +} + function PreviewCard(props) { const classes = useStyles(); const navigate = useNavigate(); @@ -69,8 +80,25 @@ function PreviewCard(props) { navigate(`/image/${name}`); }; - const verifiedCheck = () => { - return (); + const vulnerabilityCheck = () => { + const noneVulnerability = ; + const unknownVulnerability = ; + const lowVulnerability = ; + const mediumVulnerability = ; + const highVulnerability = ; + const criticalVulnerability = ; + + const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability] + return(getRandom(arrVulnerability)); + } + + const signatureCheck = () => { + const unverifiedSignature = ; + const untrustedSignature = ; + const verifiedSignature = ; + + const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature] + return(getRandom(arrSignature)); } return ( @@ -91,17 +119,17 @@ function PreviewCard(props) { {name} - {verifiedCheck()} + {vulnerabilityCheck()} + {signatureCheck()}
- - Official*PH - - - - - Discover more + + + Official + + + diff --git a/src/components/RepoCard.jsx b/src/components/RepoCard.jsx index c3abca1d..eaacff0a 100644 --- a/src/components/RepoCard.jsx +++ b/src/components/RepoCard.jsx @@ -3,22 +3,35 @@ import React from "react"; import { useNavigate } from "react-router-dom"; // utility -import { DateTime } from 'luxon'; +import { DateTime } from "luxon"; // components -import { Card, CardActionArea, CardMedia, CardContent, Typography, Stack, Chip, Grid } from '@mui/material'; -import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined'; -import BookmarkIcon from '@mui/icons-material/Bookmark'; -import makeStyles from '@mui/styles/makeStyles'; +import { + Card, + CardActionArea, + CardMedia, + CardContent, + Typography, + Stack, + Chip, + Grid, +} from "@mui/material"; +import PestControlOutlinedIcon from "@mui/icons-material/PestControlOutlined"; +import PestControlIcon from "@mui/icons-material/PestControl"; +import GppBadOutlinedIcon from "@mui/icons-material/GppBadOutlined"; +import GppGoodOutlinedIcon from "@mui/icons-material/GppGoodOutlined"; +import GppMaybeOutlinedIcon from "@mui/icons-material/GppMaybeOutlined"; +import BookmarkIcon from "@mui/icons-material/Bookmark"; +import makeStyles from "@mui/styles/makeStyles"; // placeholder images -import repocube1 from '../assets/repocube-1.png'; -import repocube2 from '../assets/repocube-2.png'; -import repocube3 from '../assets/repocube-3.png'; -import repocube4 from '../assets/repocube-4.png'; +import repocube1 from "../assets/repocube-1.png"; +import repocube2 from "../assets/repocube-2.png"; +import repocube3 from "../assets/repocube-3.png"; +import repocube4 from "../assets/repocube-4.png"; // temporary utility to get image const randomIntFromInterval = (min, max) => { - return Math.floor(Math.random() * (max - min + 1) + min) + return Math.floor(Math.random() * (max - min + 1) + min); }; const randomImage = () => { @@ -33,67 +46,122 @@ const useStyles = makeStyles(() => ({ flexDirection: "row", alignItems: "center", background: "#FFFFFF", - boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)", + borderColor: "#FFFFFF", borderRadius: "1.5rem", flex: "none", alignSelf: "stretch", flexGrow: 0, order: 0, width: "100%", - maxWidth: "72rem" + maxWidth: "72rem", }, avatar: { height: "1.4375rem", - width: "1.4375rem" + width: "1.4375rem", }, cardBtn: { height: "100%", - width: "100%" + width: "100%", }, media: { - borderRadius: '3.125rem', + borderRadius: "3.125rem", }, content: { textAlign: "left", color: "#606060", - maxHeight: "9.25rem" + maxHeight: "9.25rem", }, contentRight: { - height: "100%" + height: "100%", }, signedBadge: { - color: '#9ccc65', - height: '1.375rem', - width: '1.375rem', + color: "#9ccc65", + height: "1.375rem", + width: "1.375rem", marginLeft: 10, - } + }, + vendor: { + color: "#14191F", + fontSize: "1rem", + }, + versionLast: { + color: "#52637A", + fontSize: "1rem", + }, })); function RepoCard(props) { const classes = useStyles(); const navigate = useNavigate(); - const { name, vendor, description, lastUpdated, downloads, rating, version } = props; + const { name, vendor, description, lastUpdated, downloads, rating, version } = + props; + + //function that returns a random element from an array + function getRandom(list) { + return list[Math.floor(Math.random() * list.length)]; + } const goToDetails = (repo) => { navigate(`/image/${name}`); - } + }; - const verifiedCheck = () => { - return (); + const vulnerabilityCheck = () => { + const noneVulnerability = { return; }} deleteIcon={ }/>; + const unknownVulnerability = { return; }} deleteIcon={ }/>; + const lowVulnerability = { return; }} deleteIcon={ }/>; + const mediumVulnerability = { return; }} deleteIcon={ }/>; + const highVulnerability = { return; }} deleteIcon={ }/>; + const criticalVulnerability = { return; }} deleteIcon={ }/>; + + const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability] + return(getRandom(arrVulnerability)); + }; + + const signatureCheck = () => { + const unverifiedSignature = { return; }} deleteIcon={ }/>; + const untrustedSignature = { return; }} deleteIcon={ }/>; + const verifiedSignature = { return; }} deleteIcon={ }/>; + + const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature] + return(getRandom(arrSignature)); } const platformChips = () => { // if platforms not received, mock data - const platforms = props.platforms || ["Windows", "PowerPC64LE", "IBM Z", "Linux"]; + const platforms = props.platforms || [ + "Windows", + "PowerPC64LE", + "IBM Z", + "Linux", + ]; return platforms.map((platform, index) => ( - + )); - } + }; - const getVendorLastPublish = () => { - const lastDate = lastUpdated ? DateTime.fromISO(lastUpdated) : DateTime.now().minus({ days: 1 }); - return `${vendor || 'andrewc'} • published ${version} • ${lastDate.toRelative({ unit: 'days' })}`; - } + const getVendor = () => { + return `${vendor || "andrewc"} •`; + }; + const getVersion = () => { + const lastDate = lastUpdated + ? DateTime.fromISO(lastUpdated) + : DateTime.now().minus({ days: 1 }); + return `published ${version} •`; + }; + const getLast = () => { + const lastDate = lastUpdated + ? DateTime.fromISO(lastUpdated) + : DateTime.now().minus({ days: 1 }); + return `${lastDate.toRelative({ unit: "days" })}`; + }; return ( @@ -102,10 +170,11 @@ function RepoCard(props) { - {name} - { return }} deleteIcon={verifiedCheck()} /> + {vulnerabilityCheck()} + {signatureCheck()} + {/* { return }} deleteIcon={vulnerabilityCheck()} /> */} - - {description || 'The complete solution for node.js command-line programs'} + + {description || + "The complete solution for node.js command-line programs"} {platformChips()} - - {getVendorLastPublish()} - + + + {getVendor()} + + + {getVersion()} + + + {getLast()} + + - - + + - Downloads • {downloads || '-'} - Rating • {rating || '-'} + + Downloads • {downloads || "-"} + + + Rating • {rating || "-"} + - + diff --git a/src/components/RepoDetails.jsx b/src/components/RepoDetails.jsx index dd5c9550..f3a36434 100644 --- a/src/components/RepoDetails.jsx +++ b/src/components/RepoDetails.jsx @@ -11,7 +11,11 @@ import Tags from './Tags.jsx' import {Box, Card, CardContent, CardMedia, Chip, FormControl, Grid, IconButton, InputAdornment, OutlinedInput, Stack, Tab, Typography} from '@mui/material'; import makeStyles from '@mui/styles/makeStyles'; import { host } from '../host'; -import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined'; +import PestControlOutlinedIcon from "@mui/icons-material/PestControlOutlined"; +import PestControlIcon from "@mui/icons-material/PestControl"; +import GppBadOutlinedIcon from "@mui/icons-material/GppBadOutlined"; +import GppGoodOutlinedIcon from "@mui/icons-material/GppGoodOutlined"; +import GppMaybeOutlinedIcon from "@mui/icons-material/GppMaybeOutlined"; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import BookmarkIcon from '@mui/icons-material/Bookmark'; @@ -22,6 +26,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 { padding } from '@mui/system'; // @ts-ignore const useStyles = makeStyles((theme) => ({ @@ -36,9 +41,9 @@ const useStyles = makeStyles((theme) => ({ backgroundColor: "#FFFFFF", }, repoName: { - fontWeight:"400", - fontSize:"3rem", - color:"#220052" + fontWeight:"700", + fontSize:"2.5rem", + color:"#0F2139" }, avatar: { height:"3rem", @@ -52,26 +57,24 @@ const useStyles = makeStyles((theme) => ({ borderRadius: '3.125em', }, tabs: { - marginTop: "5%", - border: 1, - borderColor: 'divider', + marginTop: "3rem", padding:"0.5rem", - boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)", - borderRadius:"2rem", height: "100%" }, tabContent:{ height:"100%" }, selectedTab: { - background:"#A53692", + background:"#D83C0E", borderRadius:"1.5rem" }, tabPanel: { - height:"100%" + height:"100%", + paddingLeft: "0rem!important" }, metadata: { - padding:"1.5rem" + marginTop: "8rem", + paddingLeft:"1.5rem", }, card: { marginBottom: 2, @@ -79,13 +82,14 @@ const useStyles = makeStyles((theme) => ({ flexDirection:"row", alignItems:"start", background:"#FFFFFF", - boxShadow:"0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)", - borderRadius:"1.5rem", + border: "1px solid #E0E5EB", + borderRadius:"2rem", flex:"none", alignSelf:"stretch", flexGrow:0, order:0, - width:"100%" + width:"100%", + boxShadow: "none!important" }, platformText:{ backgroundColor:"#EDE7F6", @@ -94,6 +98,18 @@ const useStyles = makeStyles((theme) => ({ fontSize:'0.8125rem', lineHeight:'1.125rem', letterSpacing:'0.01rem' + }, + inputForm:{ + '& fieldset':{ + border: "2px solid #52637A", + }, + + }, + cardRoot:{ + boxShadow: "none!important", + }, + header:{ + paddingLeft:"2rem" } })); @@ -142,9 +158,30 @@ function RepoDetails (props) { setRepoDetailData({}); }); }, [name]) + //function that returns a random element from an array + function getRandom(list) { + return list[Math.floor(Math.random() * list.length)]; + } - const verifiedCheck = () => { - return (); + const vulnerabilityCheck = () => { + const noneVulnerability = { return; }} deleteIcon={ }/>; + const unknownVulnerability = { return; }} deleteIcon={ }/>; + const lowVulnerability = { return; }} deleteIcon={ }/>; + const mediumVulnerability = { return; }} deleteIcon={ }/>; + const highVulnerability = { return; }} deleteIcon={ }/>; + const criticalVulnerability = { return; }} deleteIcon={ }/>; + + const arrVulnerability = [noneVulnerability, unknownVulnerability, lowVulnerability, mediumVulnerability, highVulnerability, criticalVulnerability] + return(getRandom(arrVulnerability)); + }; + + const signatureCheck = () => { + const unverifiedSignature = { return; }} deleteIcon={ }/>; + const untrustedSignature = { return; }} deleteIcon={ }/>; + const verifiedSignature = { return; }} deleteIcon={ }/>; + + const arrSignature = [unverifiedSignature, untrustedSignature, verifiedSignature] + return(getRandom(arrSignature)); } const platformChips = () => { @@ -152,7 +189,11 @@ function RepoDetails (props) { // @ts-ignore const platforms = repoDetailData.platforms || ["Windows","PowerPC64LE","IBM Z","Linux"]; return platforms.map((platform, index) => ( - + )); } @@ -166,7 +207,7 @@ function RepoDetails (props) { {overviewTitle || 'Quickstart'} - {description || mockData.loremIpsum} + {description || mockData.loremIpsum} ); @@ -199,10 +240,10 @@ function RepoDetails (props) { return (
- + - - + + {name} - {return}} deleteIcon={verifiedCheck()}/> - + {vulnerabilityCheck()} + {signatureCheck()} + - + {description || 'The complete solution for node.js command-line programs'} - + {platformChips()} - - Copy and pull to pull this image - + + Copy and pull to pull this image + + navigator.clipboard.writeText(`Pull ${name}`)} data-testid='pullcopy-btn'> @@ -245,53 +289,57 @@ function RepoDetails (props) { - - - - - - {/* - - - - - */} - - - - - {renderOverview()} - - - - - {/* - {renderDependencies()} - - - {renderDependents()} - - - {renderVulnerabilities()} - */} + + + + + + + + {/* + + + + + */} + + + + + {renderOverview()} + + + + + {/* + {renderDependencies()} + + + {renderDependents()} + + + {renderVulnerabilities()} + */} + - - - - - - + + + + + + +
diff --git a/src/components/SignIn.jsx b/src/components/SignIn.jsx index 5977b558..a8c375f1 100644 --- a/src/components/SignIn.jsx +++ b/src/components/SignIn.jsx @@ -1,65 +1,110 @@ // react global -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { host } from '../host'; +import { host } from "../host"; // utility -import { api, endpoints } from '../api'; +import { api, endpoints } from "../api"; // components -import Button from '@mui/material/Button'; -import CssBaseline from '@mui/material/CssBaseline'; -import TextField from '@mui/material/TextField'; -import Box from '@mui/material/Box'; -import Typography from '@mui/material/Typography'; -import Alert from '@mui/material/Alert'; -import CircularProgress from '@mui/material/CircularProgress'; -import TermsOfService from './TermsOfService'; +import Button from "@mui/material/Button"; +import CssBaseline from "@mui/material/CssBaseline"; +import TextField from "@mui/material/TextField"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import Alert from "@mui/material/Alert"; +import CircularProgress from "@mui/material/CircularProgress"; +import TermsOfService from "./TermsOfService"; +import google from '../assets/Google.png'; +import git from '../assets/Git.png'; + // styling -import { makeStyles } from '@mui/styles'; -import { Card, CardContent } from '@mui/material'; +import { makeStyles } from "@mui/styles"; +import { Card, CardContent } from "@mui/material"; const useStyles = makeStyles((theme) => ({ cardContainer: { display: "flex", alignItems: "center", - justifyContent: "center" + justifyContent: "center", + margin: "0 auto", + padding: "10px", + position: "relative", }, loginCard: { - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", marginTop: "20%", width: "60%", height: "60%", - background: '#FFFFFF', - gap: '0.625em', - boxShadow: '0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)', - borderRadius: '1.5rem' + background: "#FFFFFF", + gap: "0.625em", + boxShadow: "0rem 0.3125rem 0.625rem rgba(131, 131, 131, 0.08)", + borderRadius: "1.5rem", }, loginCardContent: { - alignItems: 'center', - justifyContent: 'center', - display: 'flex', - flexDirection: 'column', - border: '0.1875rem black', - maxWidth: '73%', - height: '90%' + alignItems: "center", + justifyContent: "center", + display: "flex", + flexDirection: "column", + border: "0.1875rem black", + maxWidth: "73%", + height: "90%", }, text: { - color: "#383838", - width: "100%" + color: "#14191F", + width: "100%", + fontSize: "1.5rem" }, subtext: { - color: "rgba(0, 0, 0, 0.6)", - width: "100%" - } + color: "#52637A", + width: "100%", + fontSize: "1rem" + + }, + textField: { + borderRadius: "4px", + }, + button: { + textTransform: "none", + color: "##FFFFFF", + fontSize: "1.4375rem", + fontWeight: "500", + height: "50px", + borderRadius: "4px", + letterSpacing:"0.01rem", + }, + gitLogo: { + height: "24px", + borderRadius: "4px", + paddingLeft: "1rem", + }, + line: { + width: "100%", + textAlign: "center", + borderBottom: "1px solid #C2CBD6", + lineHeight: "0.1rem", + margin: "10px 0 20px", + }, + lineSpan:{ + background: "#ffffff", + color: "#C2CBD6", + padding: "0 10px", + fontSize: "1rem", + fontWeight: "400", + paddingLeft: "1rem", + paddingRight: "1rem" + } })); - - -export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, setIsLoggedIn }) { +export default function SignIn({ + isAuthEnabled, + setIsAuthEnabled, + isLoggedIn, + setIsLoggedIn, +}) { const [usernameError, setUsernameError] = useState(null); const [passwordError, setPasswordError] = useState(null); const [username, setUsername] = useState(null); @@ -73,17 +118,18 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se if (isAuthEnabled && isLoggedIn) { navigate("/home"); } else { - api.get(`${host()}/v2/`) - .then(response => { + api + .get(`${host()}/v2/`) + .then((response) => { if (response.status === 200) { setIsAuthEnabled(false); setIsLoggedIn(true); navigate("/home"); } }) - .catch(e => { + .catch((e) => { setIsAuthEnabled(true); - }) + }); } }, []); @@ -92,19 +138,20 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se setRequestProcessing(true); let cfg = {}; if (isAuthEnabled) { - const token = btoa(username + ':' + password); + const token = btoa(username + ":" + password); cfg = { headers: { - 'Authorization': `Basic ${token}`, - } + Authorization: `Basic ${token}`, + }, }; } - api.get(`${host()}${endpoints.imageList}`, cfg) - .then(response => { + api + .get(`${host()}${endpoints.imageList}`, cfg) + .then((response) => { if (response.data && response.data.data) { if (isAuthEnabled) { - const token = btoa(username + ':' + password); - localStorage.setItem('token', token); + const token = btoa(username + ":" + password); + localStorage.setItem("token", token); setRequestProcessing(false); setRequestError(false); } @@ -112,32 +159,32 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se navigate("/home"); } }) - .catch(e => { + .catch((e) => { setRequestError(true); setRequestProcessing(false); }); - } + }; const handleChange = (event, type) => { event.preventDefault(); setRequestError(false); const val = event.target.value; - const isEmpty = val === ''; + const isEmpty = val === ""; switch (type) { - case 'username': + case "username": setUsername(val); if (isEmpty) { - setUsernameError('Please enter a username'); + setUsernameError("Please enter a username"); } else { setUsernameError(null); } break; - case 'password': + case "password": setPassword(val); if (isEmpty) { - setPasswordError('Please enter a password'); + setPasswordError("Please enter a password"); } else { setPasswordError(null); } @@ -145,20 +192,78 @@ export default function SignIn({ isAuthEnabled, setIsAuthEnabled, isLoggedIn, se default: break; } - } - + }; return ( - + - + Sign in - + Welcome back! Please enter your details. - + + + +
+ + +
+

+

or

handleChange(e, 'username')} + className={classes.textField} + onInput={(e) => handleChange(e, "username")} error={usernameError != null} - helperText={usernameError} /> + helperText={usernameError} + /> handleChange(e, 'password')} + className={classes.textField} + onInput={(e) => handleChange(e, "password")} error={passwordError != null} - helperText={passwordError} /> - {requestProcessing && } - {requestError && Authentication Failed. Please try again.} + helperText={passwordError} + /> + {requestProcessing && ( + + )} + {requestError && ( + + Authentication Failed. Please try again. + + )}
+
diff --git a/src/components/SignInPresentation.jsx b/src/components/SignInPresentation.jsx index 2d2852b9..eccd98b6 100644 --- a/src/components/SignInPresentation.jsx +++ b/src/components/SignInPresentation.jsx @@ -1,9 +1,9 @@ import {Stack, Typography } from '@mui/material'; import {makeStyles} from '@mui/styles'; import React from 'react'; -import logoWhite from '../assets/Zot1.png'; -import loginDrawing from '../assets/login-drawing.svg'; -import backgroundImage from '../assets/presentation-background.png'; +import logoWhite from '../assets/Zot-white.svg'; +import loginDrawing from '../assets/codeReviewSignIn.png'; +import backgroundImage from '../assets/backgroundSignIn.png'; const useStyles = makeStyles(() => ({ container: { @@ -13,8 +13,8 @@ const useStyles = makeStyles(() => ({ alignItems:"center", }, logo: { - maxHeight:120, - maxWidth: 120, + maxHeight:96, + maxWidth: 320, marginTop:"17%" }, loginDrawing: { @@ -26,12 +26,14 @@ const useStyles = makeStyles(() => ({ color: "#FFFFFF", fontWeight: 700, maxWidth:"45%", - marginTop:"4%" + marginTop:"4%", + fontSize: "2.5rem" }, captionText: { color: "rgba(255, 255, 255, 0.7)", maxWidth:"48%", - marginTop:"2%" + marginTop:"2%", + fontSize: "1.1875rem" } })); diff --git a/src/components/TermsOfService.jsx b/src/components/TermsOfService.jsx index 1266d552..2721b677 100644 --- a/src/components/TermsOfService.jsx +++ b/src/components/TermsOfService.jsx @@ -6,10 +6,18 @@ import { Stack, Typography } from '@mui/material'; const useStyles = makeStyles((theme) => ({ subtext: { - color: "rgba(0, 0, 0, 0.6)", - margin: 0, - fontSize:"0.75rem", - lineHeight:"166%", + 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" } })); @@ -19,9 +27,9 @@ export default function TermsOfService(props) { return ( - By creating an account, you agree to the Terms of Service. For more information about our privacy practices, see the zot's Privacy Policy. + By creating an account, you agree to the Terms of Service. For more information about our privacy practices, see the ZOT's Privacy Policy. - + Privacy Policy | Terms of Service diff --git a/src/index.css b/src/index.css index 85ce2720..b9b4a2bb 100644 --- a/src/index.css +++ b/src/index.css @@ -7,7 +7,7 @@ body { -moz-osx-font-smoothing: grayscale; min-height: 100vh; /* background-image: url(./assets/background.png); */ - background-color: #F5F5F5 !important; + background-color: #F6F7F9 !important; } code { diff --git a/src/pages/LoginPage.jsx b/src/pages/LoginPage.jsx index 69a3258a..2f836003 100644 --- a/src/pages/LoginPage.jsx +++ b/src/pages/LoginPage.jsx @@ -11,7 +11,7 @@ import SigninPresentation from 'components/SignInPresentation'; const useStyles = makeStyles((theme) => ({ container: { minHeight: "100vh", - backgroundColor: "#F5F5F5", + backgroundColor: "#F6F7F9", }, }));