diff --git a/package-lock.json b/package-lock.json
index 01f27ca..0a1c91c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"axios": "^0.26.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
+ "react-icons": "^4.3.1",
"react-router-dom": "^6.2.1"
},
"devDependencies": {
@@ -10224,6 +10225,14 @@
"react": "17.0.2"
}
},
+ "node_modules/react-icons": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
+ "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -20040,6 +20049,12 @@
"scheduler": "^0.20.2"
}
},
+ "react-icons": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
+ "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==",
+ "requires": {}
+ },
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
diff --git a/package.json b/package.json
index 959b825..dcfdf73 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"axios": "^0.26.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
+ "react-icons": "^4.3.1",
"react-router-dom": "^6.2.1"
},
"scripts": {
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..0692308
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx
new file mode 100644
index 0000000..93eec1e
--- /dev/null
+++ b/src/components/Loading.tsx
@@ -0,0 +1,9 @@
+import React from "react";
+
+const Loading: React.FC = () => {
+ return(
+
Loading!
+ );
+};
+
+export default Loading;
\ No newline at end of file
diff --git a/src/components/navbar/NavBar.tsx b/src/components/navbar/NavBar.tsx
index ba076c1..da93276 100644
--- a/src/components/navbar/NavBar.tsx
+++ b/src/components/navbar/NavBar.tsx
@@ -13,7 +13,7 @@ import { getHostNameFromURL } from "../../utils";
const NavBar: React.FC = () => {
const { auth } = useAuth();
- const { setRepositories } = useRepositories();
+ const { setIsFetched, setRepositories } = useRepositories();
const [anchorElUser, setAnchorElUser] = React.useState<(EventTarget & HTMLButtonElement) | null>(null);
const [snackbarOpen, setSnackbarOpen] = React.useState(false);
@@ -110,6 +110,11 @@ const NavBar: React.FC = () => {
tags.push(tag);
});
repository.tags = tags;
+ }).catch((err) => {
+ const index = newRepositories.indexOf(repository);
+ if (index > -1) {
+ newRepositories.splice(index, 1);
+ }
});
promises.push(promise);
});
@@ -140,6 +145,7 @@ const NavBar: React.FC = () => {
await getTags(newRepositories, auth)
setRepositories(newRepositories);
+ setIsFetched(true);
// setRepositories(newRepositories);
};
diff --git a/src/components/repositoryInfo/RepoNotFound.tsx b/src/components/repositoryInfo/RepoNotFound.tsx
new file mode 100644
index 0000000..8170629
--- /dev/null
+++ b/src/components/repositoryInfo/RepoNotFound.tsx
@@ -0,0 +1,13 @@
+import React from "react";
+
+interface Props {
+ repositoryName: string;
+}
+
+const NotFound: React.FC = (props: Props) => {
+ return(
+ Repository "{props.repositoryName}" Not Found!
+ );
+};
+
+export default NotFound;
\ No newline at end of file
diff --git a/src/components/repositoryInfo/RepositoryInfo.tsx b/src/components/repositoryInfo/RepositoryInfo.tsx
index cc238f8..5c013a4 100644
--- a/src/components/repositoryInfo/RepositoryInfo.tsx
+++ b/src/components/repositoryInfo/RepositoryInfo.tsx
@@ -1,17 +1,19 @@
import React from "react";
-import { useLocation } from "react-router-dom";
-import { ListItemButton, Button, Box, Card, CardContent, Typography, CardActions, Grid, ListItemText, Snackbar, Alert } from "@mui/material";
+import { useLocation, Link } from "react-router-dom";
+import { ListItemButton, Button, Box, Card, CardContent, Typography, CardActions, Grid, List, ListItemText, Snackbar, Alert } from "@mui/material";
import AccessTimeIcon from '@mui/icons-material/AccessTime';
import useRepositories from "../../hooks/useRepositories";
import Tag from "../../interfaces/Tag";
import Repository from "../../interfaces/Repositoriy";
-import { getHostNameFromURL, printSize, printTimePassed } from "../../utils";
-import NotFound from "../NotFound";
+import { getHostNameFromURL, printSize, printTimePassed, PrintOSIcon } from "../../utils";
+import RepoNotFound from "./RepoNotFound"
+import Loading from "../Loading";
const RepositoryInfo: React.FC = () => {
const location = useLocation();
const path = location.pathname;
- const { repositories } = useRepositories();
+ const { isFetched, repositories } = useRepositories();
+ const [hideTags, setHideTags] = React.useState(true);
const [snackbarOpen, setSnackbarOpen] = React.useState(false);
const repository = repositories.find((element) => (element.name === path.slice(12,path.length)));
@@ -28,54 +30,128 @@ const RepositoryInfo: React.FC = () => {
const handleClose = () => {
setSnackbarOpen(false);
};
+
+ const toggleHide = () => {
+ setHideTags(!hideTags);
+ }
- return (repository ? (
-
-
-
- {/*
- Word of the Day
- */}
-
- {repository.name}
-
-
-
- {"Last updated: " + repository.tags.filter((tag: Tag) => (tag.label === "latest")).map((tag: Tag) => (tag.created ? printTimePassed(tag.created) : "")).join(" ")}
-
-
- Docker commands
-
-
- To push a new tag to this repository,
-
- {generatePushCommand(getHostNameFromURL(process.env.REGISTRY_URL ? process.env.REGISTRY_URL : ""))}
-
- {/*
-
- */}
+ return (isFetched ? (
+ repository ? (
+
+
+
+ {/*
+ Word of the Day
+ */}
+
+
+
+ {repository.name}
+
+
+
+ {"Last updated: " + repository.tags.filter((tag: Tag) => (tag.label === "latest")).map((tag: Tag) => (tag.created ? printTimePassed(tag.created) : "")).join(" ")}
+
+
+
+
+
+ Docker commands
+
+
+ To push a new tag to this repository,
+
+ {generatePushCommand(getHostNameFromURL(process.env.REGISTRY_URL ? process.env.REGISTRY_URL : ""))}
+
+
+
+
+ {/*
+
+ */}
+
+
+
+
+ Tags
+
+
+ {"This repository contains " + repository.tags.length + " tag" + (repository.tags.length > 1 ? "s" : "") + "."}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {repository.tags.sort((a,b) => {
+ let result = (b.created ? b.created.getTime() : 0) - (a.created ? a.created.getTime() : 0);
+ if (result === 0) {
+ if (b.label === "latest") {
+ return 1;
+ } else if (a.label === "latest") {
+ return -1;
+ } else {
+ return 0;
+ }
+ } else {
+ return result;
+ }
+ }).slice(0,((hideTags && repository.tags.length > 4) ? 3 : repository.tags.length)).map((tag) => (
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
+
+ ))}
+ {repository.tags.length > 4 ? (
+
+
+
+
+
+ ) : (
+ <>>
+ )}
+
+
+
+
+
+
Copied!
-
-
-
-
- Tags
-
-
- {"This repository contains " + repository.tags.length + " tag" + (repository.tags.length > 1 ? "s" : "") + "."}
-
-
-
-
-
-
-
+
+ ) : (
+
+ )
) : (
-
+
));
}
diff --git a/src/context/RepositoriesProvider.tsx b/src/context/RepositoriesProvider.tsx
index 48743c2..9b1ea2a 100644
--- a/src/context/RepositoriesProvider.tsx
+++ b/src/context/RepositoriesProvider.tsx
@@ -3,19 +3,24 @@ import Repository from "../interfaces/Repositoriy";
interface MyRepositoriesState {
+ isFetched: boolean;
+ setIsFetched: React.Dispatch>
repositories: Repository[];
setRepositories: React.Dispatch>
}
const RepositoriesContext = createContext({
+ isFetched: false,
+ setIsFetched: () => {},
repositories: [],
setRepositories: () => {}
});
export const RepositoriesProvider = ({ children }: { children: React.ReactNode }) => {
+ const [isFetched, setIsFetched] = useState(false);
const [repositories, setRepositories] = useState([]);
- return {children};
+ return {children};
};
export default RepositoriesContext;
\ No newline at end of file
diff --git a/src/style/modules/_repositoryInfo.sass b/src/style/modules/_repositoryInfo.sass
index adabc36..dff86a5 100644
--- a/src/style/modules/_repositoryInfo.sass
+++ b/src/style/modules/_repositoryInfo.sass
@@ -1,4 +1,6 @@
.repositoryInfo
+ max-width: 70%
+ margin: auto
.repositoryDetail
margin: 5%
padding: 15px
@@ -16,4 +18,9 @@
margin: 5%
padding: 15px
.lines
- margin-bottom: 10px
\ No newline at end of file
+ margin-bottom: 10px
+ .moreBtn
+ color: #1976d2
+ cursor: pointer
+ .moreBtn:focus
+ color: purple
\ No newline at end of file
diff --git a/src/style/style.css b/src/style/style.css
index 3f3d513..45e938b 100644
--- a/src/style/style.css
+++ b/src/style/style.css
@@ -24,6 +24,11 @@ a {
margin: auto;
}
+.repositoryInfo {
+ max-width: 70%;
+ margin: auto;
+}
+
.repositoryInfo .repositoryDetail {
margin: 5%;
padding: 15px;
@@ -54,6 +59,15 @@ a {
margin-bottom: 10px;
}
+.repositoryInfo .tagsDetail .moreBtn {
+ color: #1976d2;
+ cursor: pointer;
+}
+
+.repositoryInfo .tagsDetail .moreBtn:focus {
+ color: purple;
+}
+
.login .grid-container {
-webkit-box-align: center;
-ms-flex-align: center;
diff --git a/src/style/style.css.map b/src/style/style.css.map
index ccc7fd3..d859a12 100644
--- a/src/style/style.css.map
+++ b/src/style/style.css.map
@@ -1,6 +1,6 @@
{
"version": 3,
- "mappings": "AG8CA,AAAA,WAAW,CAAC;EACR,KAAK,EAAE,IAAI;CAAG;;AAElB,AAAA,CAAC,CAAC;EACE,eAAe,EAAE,IAAI;CAAG;;AElD5B,AAAA,OAAO,CAAC;EACJ,MAAM,EAAE,CAAC;CAKU;;AANvB,AAEI,OAFG,CAEH,SAAS,CAAC;EACN,KAAK,EAAE,KAAK;CAAG;;AAHvB,AAII,OAJG,CAIH,WAAW,CAAC;EACR,UAAU,EAAE,MAAM;EAClB,KAAK,EAAE,GAAG;CAAG;;AGNrB,AACI,YADQ,CACR,eAAe,CAAC;EACZ,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,IAAI;CAAG;;ACHvB,AACI,eADW,CACX,iBAAiB,CAAC;EACd,MAAM,EAAE,EAAE;EACV,OAAO,EAAE,IAAI;CAUW;;AAbhC,AAIQ,eAJO,CACX,iBAAiB,CAGb,MAAM,CAAC;EACH,aAAa,EAAE,IAAI;CAAG;;AALlC,AAMQ,eANO,CACX,iBAAiB,CAKb,WAAW,CAAC;EACR,cAAc,EAAE,MAAM;EACtB,YAAY,EAAE,IAAI;CAAG;;AARjC,AASQ,eATO,CACX,iBAAiB,CAQb,eAAe,CAAC;EACZ,WAAW,EAAE,IAAI;EACjB,aAAa,EAAE,GAAG;EAClB,OAAO,EAAE,MAAM;EACf,UAAU,EAAE,GAAG;CAAG;;AAb9B,AAcI,eAdW,CAcX,WAAW,CAAC;EACR,MAAM,EAAE,EAAE;EACV,OAAO,EAAE,IAAI;CAEe;;AAlBpC,AAiBQ,eAjBO,CAcX,WAAW,CAGP,MAAM,CAAC;EACH,aAAa,EAAE,IAAI;CAAG;;AClBlC,AACI,MADE,CACF,eAAe,CAAC;EACZ,WAAW,EAAE,MAAM;EACnB,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,GAAG;EACf,SAAS,EAAE,cAAc;CAeS;;AApB1C,AAMQ,MANF,CACF,eAAe,GAKT,CAAC,CAAC;EACA,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,MAAM;CAAG;;AAR7B,AASQ,MATF,CACF,eAAe,CAQX,YAAY,CAAC;EACT,OAAO,EAAE,YAAY;EACrB,UAAU,EAAE,MAAM;EAClB,MAAM,EAAE,IAAI;EACZ,SAAS,EAAE,IAAI;CAAG;;AAb9B,AAcQ,MAdF,CACF,eAAe,CAaX,UAAU,CAAC;EACP,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,GAAG;CACpB;;AAjBF,AAkBQ,MAlBF,CACF,eAAe,CAiBX,eAAe,CAAC;EACZ,MAAM,EAAE,IAAI;EACZ,gBAAgB,EAAE,OAAO;CAAG;;ACpBxC,AAAA,QAAQ,CAAC;EACL,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,GAAG;CAEU;;AAL7B,AAII,QAJI,CAIJ,eAAe,CAAC;EACZ,UAAU,EAAE,IAAI;CAAG",
+ "mappings": "AG8CA,AAAA,WAAW,CAAC;EACR,KAAK,EAAE,IAAI;CAAG;;AAElB,AAAA,CAAC,CAAC;EACE,eAAe,EAAE,IAAI;CAAG;;AElD5B,AAAA,OAAO,CAAC;EACJ,MAAM,EAAE,CAAC;CAKU;;AANvB,AAEI,OAFG,CAEH,SAAS,CAAC;EACN,KAAK,EAAE,KAAK;CAAG;;AAHvB,AAII,OAJG,CAIH,WAAW,CAAC;EACR,UAAU,EAAE,MAAM;EAClB,KAAK,EAAE,GAAG;CAAG;;AGNrB,AACI,YADQ,CACR,eAAe,CAAC;EACZ,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,IAAI;CAAG;;ACHvB,AAAA,eAAe,CAAC;EACZ,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,IAAI;CAuBgB;;AAzBhC,AAGI,eAHW,CAGX,iBAAiB,CAAC;EACd,MAAM,EAAE,EAAE;EACV,OAAO,EAAE,IAAI;CAUW;;AAfhC,AAMQ,eANO,CAGX,iBAAiB,CAGb,MAAM,CAAC;EACH,aAAa,EAAE,IAAI;CAAG;;AAPlC,AAQQ,eARO,CAGX,iBAAiB,CAKb,WAAW,CAAC;EACR,cAAc,EAAE,MAAM;EACtB,YAAY,EAAE,IAAI;CAAG;;AAVjC,AAWQ,eAXO,CAGX,iBAAiB,CAQb,eAAe,CAAC;EACZ,WAAW,EAAE,IAAI;EACjB,aAAa,EAAE,GAAG;EAClB,OAAO,EAAE,MAAM;EACf,UAAU,EAAE,GAAG;CAAG;;AAf9B,AAgBI,eAhBW,CAgBX,WAAW,CAAC;EACR,MAAM,EAAE,EAAE;EACV,OAAO,EAAE,IAAI;CAOS;;AAzB9B,AAmBQ,eAnBO,CAgBX,WAAW,CAGP,MAAM,CAAC;EACH,aAAa,EAAE,IAAI;CAAG;;AApBlC,AAqBQ,eArBO,CAgBX,WAAW,CAKP,QAAQ,CAAC;EACL,KAAK,EAAE,OAAO;EACd,MAAM,EAAE,OAAO;CAAG;;AAvB9B,AAwBQ,eAxBO,CAgBX,WAAW,CAQP,QAAQ,AAAA,MAAM,CAAC;EACX,KAAK,EAAE,MAAM;CAAG;;ACzB5B,AACI,MADE,CACF,eAAe,CAAC;EACZ,WAAW,EAAE,MAAM;EACnB,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,GAAG;EACf,SAAS,EAAE,cAAc;CAeS;;AApB1C,AAMQ,MANF,CACF,eAAe,GAKT,CAAC,CAAC;EACA,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,MAAM;CAAG;;AAR7B,AASQ,MATF,CACF,eAAe,CAQX,YAAY,CAAC;EACT,OAAO,EAAE,YAAY;EACrB,UAAU,EAAE,MAAM;EAClB,MAAM,EAAE,IAAI;EACZ,SAAS,EAAE,IAAI;CAAG;;AAb9B,AAcQ,MAdF,CACF,eAAe,CAaX,UAAU,CAAC;EACP,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,GAAG;CACpB;;AAjBF,AAkBQ,MAlBF,CACF,eAAe,CAiBX,eAAe,CAAC;EACZ,MAAM,EAAE,IAAI;EACZ,gBAAgB,EAAE,OAAO;CAAG;;ACpBxC,AAAA,QAAQ,CAAC;EACL,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,GAAG;CAEU;;AAL7B,AAII,QAJI,CAIJ,eAAe,CAAC;EACZ,UAAU,EAAE,IAAI;CAAG",
"sources": [
"style.sass",
"_variables.sass",
diff --git a/src/utils.tsx b/src/utils.tsx
index 7a3e452..777425a 100644
--- a/src/utils.tsx
+++ b/src/utils.tsx
@@ -1,4 +1,6 @@
import axios from "./api/axios"
+import { FcLinux } from "react-icons/fc";
+import { FaWindows } from "react-icons/fa";
const checkValidURL = async (url: string) => {
try {
@@ -54,4 +56,14 @@ const printSize = (sizeInByte: number): string => {
}
};
-export { checkValidURL, printTwoDecimalPlaces, printTimePassed, printSize, getHostNameFromURL };
\ No newline at end of file
+const PrintOSIcon: React.FC<{ os: string }> = ({ os }) => {
+ if (os === "linux") {
+ return
+ } else if (os === "windows") {
+ return
+ } else {
+ return os
;
+ }
+}
+
+export { checkValidURL, printTwoDecimalPlaces, printTimePassed, printSize, getHostNameFromURL, PrintOSIcon };
\ No newline at end of file