implemented RepositoriesProvider

This commit is contained in:
CodeServer 2022-04-11 10:36:56 +01:00
parent 9a49b30cd1
commit 0495bfd295
13 changed files with 343 additions and 162 deletions

View File

@ -3,6 +3,7 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import CheckENVRoute from "./CheckENVRoute";
import Home from "./components/home/Home";
import Login from "./components/Login";
import RepositoryInfo from "./components/repositoryInfo/RepositoryInfo";
import ProtectedRoute from "./ProtectedRoute";
const App: React.FC = () => {
@ -13,6 +14,7 @@ const App: React.FC = () => {
<Route path="/login" element={<Login />} />
<Route element={<ProtectedRoute />}>
<Route path="/" element={<Home />} />
<Route path="/repository/*" element={<RepositoryInfo />} />
</Route>
</Route>
</Routes>

View File

@ -3,9 +3,10 @@ import NavBar from "./components/navbar/NavBar";
import useAuth from "./hooks/useAuth";
const ProtectedRoute = () => {
const auth = useAuth();
const { auth } = useAuth();
const location = useLocation();
return ((auth.loginNeeded !== undefined && !auth.loginNeeded) || auth?.isLoggedIn) ? (
<>
<NavBar />

View File

@ -1,6 +1,6 @@
import { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { InputLabel, Stack, Typography } from "@mui/material";
import { InputLabel, Stack } from "@mui/material";
import Container from "@mui/material/Container";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
@ -12,7 +12,7 @@ interface LocationState {
from: { pathname: string };
}
const Login: React.FC = () => {
const setAuth = useAuth();
const { setAuth } = useAuth();
const navigate = useNavigate();
const location = useLocation();
@ -24,8 +24,12 @@ const Login: React.FC = () => {
const [hasError, setHasError] = useState(false);
const handleSkipLogin = () => {
setAuth["loginNeeded"] = false;
setAuth["isLoggedIn"] = false;
setAuth({
loginNeeded: false,
isLoggedIn: false,
username: "",
password: ""
});
navigate(from, { replace: true });
}
@ -55,12 +59,15 @@ const Login: React.FC = () => {
if (status === undefined) {
setHasError(true);
} else {
setAuth["loginNeeded"] = true
setAuth["isLoggedIn"] = true;
// setAuth["username"] = username;
// setAuth["password"] = password;
setAuth["username"] = "pusher";
setAuth["password"] = "pusher";
setAuth({
loginNeeded: true,
isLoggedIn: true,
// username: username,
// password: password,
username: "pusher",
password: "pusher"
});
setHasError(false);
navigate(from, { replace: true });
console.log("logged in!");

View File

@ -0,0 +1,125 @@
import axios from "../api/axios";
import useAuth from "../hooks/useAuth";
import useRepositories from "../hooks/useRepositories";
import { loginInfo } from "../context/AuthProvider";
import Tag from "../interfaces/Tag";
import Repository from "../interfaces/Repositoriy";
import Layer from "../interfaces/Layer";
// const [repositories, setRepositories] = useState<Repository[]>([]);
const getTagInfo = async(newRepositories: Repository[], auth: loginInfo) => {
let promises: Promise<void>[] = [];
newRepositories.forEach((repository: Repository) => {
repository.tags.forEach((tag: Tag) => {
let promise = axios.get(
"/" + repository.name + "/manifests/" + tag.label,
{
headers:{
Accept: "application/vnd.docker.distribution.manifest.v2+json",
},
auth: {
username: auth.username,
password: auth.password
}
}
).then((response) => {
tag.schemaVersion = response?.data['schemaVersion'];
tag.mediaType = response?.data['mediaType'];
tag.digest = response?.headers['docker-content-digest'];
tag.config = response?.data?.config;
tag.layers = response?.data?.layers;
let size = 0;
response?.data?.layers.forEach((layer: Layer) => {
size += layer.size;
});
tag.size = size;
return axios.get(
"/" + repository.name + "/blobs/" + response?.data?.config['digest'],
{
headers:{
Accept: "application/vnd.docker.distribution.manifest.v2+json",
},
auth: {
username: auth.username,
password: auth.password
}
}
).then((res) => {
tag.architecture = res?.data?.architecture;
tag.os = res?.data?.os;
tag.created = new Date(res?.data?.created);
});
});
promises.push(promise);
});
});
return Promise.all(promises);
};
const getTags = async(newRepositories: Repository[], auth: loginInfo) => {
let promises: Promise<void>[] = [];
newRepositories.forEach((repository: Repository) => {
let promise = axios.get(
"/" + repository.name + "/tags/list",
{
auth: {
username: auth.username,
password: auth.password
}
}
).then((res) => {
let tags: Tag[] = [];
res?.data?.tags.forEach((tagLabel: string) => {
let tag: Tag = {
label: tagLabel,
architecture: "",
os: "",
created: undefined,
schemaVersion: undefined,
mediaType: "",
config: undefined,
layers: undefined,
size: undefined,
digest: ""
}
tags.push(tag);
});
repository.tags = tags;
});
promises.push(promise);
});
await Promise.all(promises);
return getTagInfo(newRepositories, auth);
};
const listRepositories = async() => {
const { auth } = useAuth();
const { setRepositories } = useRepositories();
const response = await axios.get(
"/_catalog",
{
auth: {
username: auth.username,
password: auth.password
}
}
);
let newRepositories: Repository[] = [];
response?.data?.repositories.forEach((repositoriyName: string) => {
let newRepository: Repository = {
name: repositoriyName,
tags: []
}
newRepositories.push(newRepository);
});
await getTags(newRepositories, auth)
setRepositories(newRepositories);
// setRepositories(newRepositories);
};
export { listRepositories };

View File

@ -1,132 +1,11 @@
import React from "react";
import { useState, useEffect } from "react";
import { List } from "@mui/material";
import RepositoryItem from "./RepositoryEntry";
import axios from "../../api/axios";
import useAuth from "../../hooks/useAuth";
import Tag from "../../interfaces/Tag";
import useRepositories from "../../hooks/useRepositories";
import Repository from "../../interfaces/Repositoriy";
import Layer from "../../interfaces/Layer";
const Home: React.FC = () => {
const auth = useAuth();
const [repositories, setRepositories] = useState<Repository[]>([]);
auth['repositories'] = repositories;
const getTagInfo = async(newRepositories: Repository[]) => {
let promises: Promise<void>[] = [];
newRepositories.forEach((repository: Repository) => {
repository.tags.forEach((tag: Tag) => {
let promise = axios.get(
"/" + repository.name + "/manifests/" + tag.label,
{
headers:{
Accept: "application/vnd.docker.distribution.manifest.v2+json",
},
auth: {
username: auth.username,
password: auth.password
}
}
).then((response) => {
tag.schemaVersion = response?.data['schemaVersion'];
tag.mediaType = response?.data['mediaType'];
tag.digest = response?.headers['docker-content-digest'];
tag.config = response?.data?.config;
tag.layers = response?.data?.layers;
let size = 0;
response?.data?.layers.forEach((layer: Layer) => {
size += layer.size;
});
tag.size = size;
return axios.get(
"/" + repository.name + "/blobs/" + response?.data?.config['digest'],
{
headers:{
Accept: "application/vnd.docker.distribution.manifest.v2+json",
},
auth: {
username: auth.username,
password: auth.password
}
}
).then((res) => {
tag.architecture = res?.data?.architecture;
tag.os = res?.data?.os;
tag.created = new Date(res?.data?.created);
});
});
promises.push(promise);
});
});
return Promise.all(promises);
};
const getTags = async(newRepositories: Repository[]) => {
let promises: Promise<void>[] = [];
newRepositories.forEach((repository: Repository) => {
let promise = axios.get(
"/" + repository.name + "/tags/list",
{
auth: {
username: auth.username,
password: auth.password
}
}
).then((res) => {
let tags: Tag[] = [];
res?.data?.tags.forEach((tagLabel: string) => {
let tag: Tag = {
label: tagLabel,
architecture: "",
os: "",
created: undefined,
schemaVersion: undefined,
mediaType: "",
config: undefined,
layers: undefined,
size: undefined,
digest: ""
}
tags.push(tag);
});
repository.tags = tags;
});
promises.push(promise);
});
await Promise.all(promises);
return getTagInfo(newRepositories);
};
const listRepositories = async() => {
const response = await axios.get(
"/_catalog",
{
auth: {
username: auth.username,
password: auth.password
}
}
);
let newRepositories: Repository[] = [];
response?.data?.repositories.forEach((repositoriyName: string) => {
let newRepository: Repository = {
name: repositoriyName,
tags: []
}
newRepositories.push(newRepository);
});
await getTags(newRepositories)
setRepositories(newRepositories);
};
useEffect(() => {
setInterval(() => listRepositories(), 1000);
}, []);
const { repositories } = useRepositories();
return(
<div className="sectionHome">

View File

@ -1,5 +1,5 @@
import React from "react";
import { ListItemButton, Box, Typography, Grid, ListItemText } from "@mui/material";
import { ListItemButton, Grid, ListItemText } from "@mui/material";
import Tag from "../../interfaces/Tag";
import Repository from "../../interfaces/Repositoriy";
import { printSize, printTimePassed } from "../../utils";
@ -19,8 +19,6 @@ const RepositoryItem: React.FC<Props> = (props: Props) => {
<Grid container>
<Grid item sm={9}>
<ListItemText primary={props.repository.name} secondary={"Last updated: " + props.repository.tags.filter((tag: Tag) => (tag.label === "latest")).map((tag: Tag) => (tag.created ? printTimePassed(tag.created) : "")).join(" ")} />
{/* <Typography color="black" variant="h5">{props.repository.name}</Typography>
<Typography color="grey" variant="h6">{"Last updated: " + props.repository.tags.filter((tag: Tag) => (tag.label === "latest")).map((tag: Tag) => (tag.created ? printTimePassed(tag.created) : "")).join(" ")}</Typography> */}
</Grid>
<Grid item sm={3}>
<ListItemText style={{display:'flex', justifyContent:'flex-end'}} primary={props.repository.tags.filter((tag: Tag) => (tag.label === "latest")).map((tag: Tag) => (tag.size ? printSize(tag.size) : "")).join(" ")} />

View File

@ -1,9 +1,17 @@
import React from "react";
import { useEffect } from "react";
import { AppBar, Container, Toolbar, Typography, Box, IconButton, Menu, MenuItem , Tooltip, Avatar, Snackbar, Alert} from "@mui/material";
import axios from "../../api/axios";
import useAuth from "../../hooks/useAuth";
import useRepositories from "../../hooks/useRepositories";
import { loginInfo } from "../../context/AuthProvider";
import Tag from "../../interfaces/Tag";
import Repository from "../../interfaces/Repositoriy";
import Layer from "../../interfaces/Layer";
const NavBar: React.FC = () => {
const auth = useAuth();
const { auth } = useAuth();
const { setRepositories } = useRepositories();
const [anchorElUser, setAnchorElUser] = React.useState<(EventTarget & HTMLButtonElement) | null>(null);
const [snackbarOpen, setSnackbarOpen] = React.useState(false);
@ -22,6 +30,123 @@ const NavBar: React.FC = () => {
setSnackbarOpen(false);
};
const getTagInfo = async(newRepositories: Repository[], auth: loginInfo) => {
let promises: Promise<void>[] = [];
newRepositories.forEach((repository: Repository) => {
repository.tags.forEach((tag: Tag) => {
let promise = axios.get(
"/" + repository.name + "/manifests/" + tag.label,
{
headers:{
Accept: "application/vnd.docker.distribution.manifest.v2+json",
},
auth: {
username: auth.username,
password: auth.password
}
}
).then((response) => {
tag.schemaVersion = response?.data['schemaVersion'];
tag.mediaType = response?.data['mediaType'];
tag.digest = response?.headers['docker-content-digest'];
tag.config = response?.data?.config;
tag.layers = response?.data?.layers;
let size = 0;
response?.data?.layers.forEach((layer: Layer) => {
size += layer.size;
});
tag.size = size;
return axios.get(
"/" + repository.name + "/blobs/" + response?.data?.config['digest'],
{
headers:{
Accept: "application/vnd.docker.distribution.manifest.v2+json",
},
auth: {
username: auth.username,
password: auth.password
}
}
).then((res) => {
tag.architecture = res?.data?.architecture;
tag.os = res?.data?.os;
tag.created = new Date(res?.data?.created);
});
});
promises.push(promise);
});
});
return Promise.all(promises);
};
const getTags = async(newRepositories: Repository[], auth: loginInfo) => {
let promises: Promise<void>[] = [];
newRepositories.forEach((repository: Repository) => {
let promise = axios.get(
"/" + repository.name + "/tags/list",
{
auth: {
username: auth.username,
password: auth.password
}
}
).then((res) => {
let tags: Tag[] = [];
res?.data?.tags.forEach((tagLabel: string) => {
let tag: Tag = {
label: tagLabel,
architecture: "",
os: "",
created: undefined,
schemaVersion: undefined,
mediaType: "",
config: undefined,
layers: undefined,
size: undefined,
digest: ""
}
tags.push(tag);
});
repository.tags = tags;
});
promises.push(promise);
});
await Promise.all(promises);
return getTagInfo(newRepositories, auth);
};
const listRepositories = async() => {
const response = await axios.get(
"/_catalog",
{
auth: {
username: auth.username,
password: auth.password
}
}
);
let newRepositories: Repository[] = [];
response?.data?.repositories.forEach((repositoriyName: string) => {
let newRepository: Repository = {
name: repositoriyName,
tags: []
}
newRepositories.push(newRepository);
});
await getTags(newRepositories, auth)
setRepositories(newRepositories);
// setRepositories(newRepositories);
};
useEffect(() => {
setInterval(() => listRepositories(), 1000);
}, []);
return (
<AppBar className="navbar" position="static">
<Container maxWidth={false} sx={{ m: 0, width: '100%' }}>

View File

@ -0,0 +1,15 @@
import React from "react";
import { useLocation } from "react-router-dom";
import { ListItemButton, Box, Typography, Grid, ListItemText } from "@mui/material";
import Tag from "../../interfaces/Tag";
import Repository from "../../interfaces/Repositoriy";
const RepositoryInfo: React.FC = () => {
const location = useLocation()
return (
<h1>{location.pathname.slice(12,location.pathname.length)}</h1>
);
}
export default RepositoryInfo;

View File

@ -1,26 +1,32 @@
import { createContext, useState } from "react";
import Repository from "../interfaces/Repositoriy";
interface loginInfo {
export interface loginInfo {
loginNeeded: boolean;
isLoggedIn: boolean;
username: string;
password: string;
repositories: Repository[];
}
const AuthContext = createContext<loginInfo>({
interface MyAuthState {
auth: loginInfo;
setAuth: React.Dispatch<React.SetStateAction<loginInfo>>
}
const AuthContext = createContext<MyAuthState>({
auth: {
loginNeeded: true,
isLoggedIn: false,
username: "",
password: "",
repositories: []
password: ""
},
setAuth: () => {}
});
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [auth] = useState<loginInfo>({ loginNeeded: true, isLoggedIn: false, username: "", password: "", repositories: [] });
const [auth, setAuth] = useState<loginInfo>({ loginNeeded: true, isLoggedIn: false, username: "", password: "" });
return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
return <AuthContext.Provider value={{auth, setAuth}}>{children}</AuthContext.Provider>;
};
export default AuthContext;

View File

@ -0,0 +1,21 @@
import { createContext, useState } from "react";
import Repository from "../interfaces/Repositoriy";
interface MyRepositoriesState {
repositories: Repository[];
setRepositories: React.Dispatch<React.SetStateAction<Repository[]>>
}
const RepositoriesContext = createContext<MyRepositoriesState>({
repositories: [],
setRepositories: () => {}
});
export const RepositoriesProvider = ({ children }: { children: React.ReactNode }) => {
const [repositories, setRepositories] = useState<Repository[]>([]);
return <RepositoriesContext.Provider value={{repositories, setRepositories}}>{children}</RepositoriesContext.Provider>;
};
export default RepositoriesContext;

View File

@ -1,17 +1,8 @@
import { useContext } from "react";
import AuthContext from "../context/AuthProvider";
import Repository from "../interfaces/Repositoriy";
interface loginInfo {
loginNeeded: boolean;
isLoggedIn: boolean;
username: string;
password: string;
repositories: Repository[];
}
const useAuth = () => {
return useContext<loginInfo>(AuthContext);
return useContext(AuthContext);
};
export default useAuth;

View File

@ -0,0 +1,8 @@
import { useContext } from "react";
import RepositoriesContext from "../context/RepositoriesProvider";
const useRepositories = () => {
return useContext(RepositoriesContext);
};
export default useRepositories;

View File

@ -2,12 +2,15 @@ import ReactDOM from "react-dom";
import App from "./App";
import "./style/style.css";
import { AuthProvider } from "./context/AuthProvider";
import { RepositoriesProvider } from "./context/RepositoriesProvider";
const Index: React.FC = () => {
return (
<AuthProvider>
<RepositoriesProvider>
<App />
</RepositoriesProvider>
</AuthProvider>
);
};