DockerRegistryWebUI/src/components/navbar/NavBar.tsx

209 lines
7.4 KiB
TypeScript

import React from "react";
import { useEffect } from "react";
import { NavLink } from "react-router-dom";
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";
import { getHostNameFromURL } from "../../utils";
const NavBar: React.FC = () => {
const { auth } = useAuth();
const { setRepositories } = useRepositories();
const [anchorElUser, setAnchorElUser] = React.useState<(EventTarget & HTMLButtonElement) | null>(null);
const [snackbarOpen, setSnackbarOpen] = React.useState(false);
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
const handleClick = () => {
const url = process.env.REGISTRY_URL ? process.env.REGISTRY_URL : "";
navigator.clipboard.writeText(getHostNameFromURL(url));
setSnackbarOpen(true);
};
const handleClose = () => {
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%' }}>
<Toolbar disableGutters>
<Typography
className="homeLink"
variant="h6"
noWrap
component={NavLink}
to="/"
sx={{ mr: 2, display: 'flex', textDecoration: "none" }}
>
Docker Registry
</Typography>
<Box sx={{ flexGrow: 1, display: 'flex' }}>
<Typography onClick={handleClick} className="centerText" > Your registry instance is at {process.env.REGISTRY_URL ? process.env.REGISTRY_URL : ""} </Typography>
</Box>
<Snackbar open={snackbarOpen} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success" sx={{ width: '100%' }}>
Registry address copied!
</Alert>
</Snackbar>
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Open settings">
<IconButton onClick={(event) => {setAnchorElUser(event.currentTarget)}} sx={{ p: 0 }}>
<Avatar alt={auth['username']} src="/pic.png" />
</IconButton>
</Tooltip>
<Menu
sx={{ mt: '45px' }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
<MenuItem onClick={handleCloseUserMenu}>
<Typography textAlign="center">Account</Typography>
</MenuItem>
</Menu>
</Box>
</Toolbar>
</Container>
</AppBar>
);
};
export default NavBar;