123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- import { FC, useContext, useState, MouseEvent } from 'react';
- import { useTranslation } from 'react-i18next';
- import Typography from '@mui/material/Typography';
- import Tooltip from '@mui/material/Tooltip';
- import Menu from '@mui/material/Menu';
- import MenuItem from '@mui/material/MenuItem';
- import { useNavigate } from 'react-router-dom';
- import { navContext, dataContext, authContext, rootContext } from '@/context';
- import { MilvusService } from '@/http';
- import CustomSelector from '@/components/customSelector/CustomSelector';
- import StatusIcon from '@/components/status/StatusIcon';
- import UpdateUser from '@/pages/user/dialogs/UpdateUserPassDialog';
- import icons from '../icons/Icons';
- import { styled } from '@mui/material/styles';
- import IconButton from '@mui/material/IconButton';
- import { ColorModeContext } from '@/context';
- import { LoadingType } from '@/components/status/StatusIcon';
- const HeaderWrapper = styled('header')(({ theme }) => ({
- display: 'flex',
- alignItems: 'center',
- color: theme.palette.text.primary,
- backgroundColor: theme.palette.background.paper,
- paddingRight: theme.spacing(1),
- borderBottom: `1px solid ${theme.palette.divider}`,
- height: 48,
- }));
- const ContentWrapper = styled('div')({
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- flex: 1,
- height: 48,
- });
- const Navigation = styled('div')({
- display: 'flex',
- alignItems: 'center',
- });
- const StyledIcon = styled('div')(({ theme }) => ({
- color: theme.palette.primary.main,
- cursor: 'pointer',
- marginRight: theme.spacing(1),
- }));
- const AddressWrapper = styled('div')(({ theme }) => ({
- display: 'flex',
- alignItems: 'center',
- '& .text': {
- marginRight: theme.spacing(2),
- '& .address': {
- fontSize: '12px',
- lineHeight: 1.3,
- },
- '& .status': {
- fontSize: '12px',
- lineHeight: 1.3,
- color: '#1ba954',
- },
- },
- }));
- const Title = styled(Typography)(({ theme }) => ({
- paddingLeft: theme.spacing(2),
- }));
- const DatabaseSelector = styled(CustomSelector)(({ theme }) => ({
- transform: 'translateY(-4px)',
- width: 'auto',
- minWidth: 120,
- '& .MuiInputLabel-root': {
- top: '4px',
- },
- }));
- const ModeButton = styled(IconButton)(({ theme }) => ({
- marginRight: theme.spacing(1),
- '& svg': {
- fontSize: 18,
- color: theme.palette.text.primary,
- },
- }));
- const Extra = styled('span')(({ theme }) => ({
- marginLeft: theme.spacing(0.5),
- display: 'flex',
- '& svg': {
- fontSize: 15,
- color: theme.palette.primary.main,
- },
- }));
- const Header: FC = () => {
- // use context
- const { navInfo } = useContext(navContext);
- const { mode, toggleColorMode } = useContext(ColorModeContext);
- const { database, databases, setDatabase, loading } = useContext(dataContext);
- const { authReq, logout } = useContext(authContext);
- const { setDialog, handleCloseDialog, openSnackBar } =
- useContext(rootContext);
- const { address, username } = authReq;
- const navigate = useNavigate();
- // UI states
- const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
- // i8n
- const { t: commonTrans } = useTranslation();
- const statusTrans = commonTrans('status');
- const { t: dbTrans } = useTranslation('database');
- const { t: successTrans } = useTranslation('success');
- const { t: userTrans } = useTranslation('user');
- // icons
- const BackIcon = icons.back;
- const LogoutIcon = icons.logout;
- const Avatar = icons.avatar;
- // UI handlers
- const handleBack = (path: string) => {
- navigate(path);
- };
- const handleLogout = async () => {
- logout(false);
- };
- const useDatabase = async (database: string) => {
- await MilvusService.useDatabase({ database });
- };
- const handleUserMenuClick = (event: MouseEvent<HTMLDivElement>) => {
- setAnchorEl(event.currentTarget);
- };
- const handleUserMenuClose = () => {
- setAnchorEl(null);
- };
- const handleChangePassword = () => {
- setAnchorEl(null);
- setDialog({
- open: true,
- type: 'custom',
- params: {
- component: (
- <UpdateUser
- username={username}
- onUpdate={res => {
- if (res.error_code === 'Success') {
- openSnackBar(successTrans('passwordChanged'));
- handleCloseDialog();
- setAnchorEl(null);
- logout();
- } else {
- openSnackBar(res.detail, 'error');
- }
- }}
- handleClose={handleCloseDialog}
- />
- ),
- },
- });
- };
- // local computes
- const dbOptions = databases.map(d => ({ value: d.name, label: d.name }));
- const isLoadingDb = dbOptions.length === 0;
- return (
- <HeaderWrapper>
- <ContentWrapper>
- <Navigation>
- {navInfo.backPath !== '' && (
- <StyledIcon onClick={() => handleBack(navInfo.backPath)}>
- <BackIcon />
- </StyledIcon>
- )}
- {navInfo.showDatabaseSelector &&
- (!isLoadingDb ? (
- <DatabaseSelector
- label={dbTrans('database')}
- value={database}
- onChange={async (e: { target: { value: unknown } }) => {
- const database = e.target.value as string;
- await useDatabase(database);
- setDatabase(database);
- // if url contains databases, go to the database page
- if (window.location.hash.includes('databases')) {
- navigate(`/databases/${database}/collections`);
- }
- }}
- options={dbOptions}
- variant="filled"
- disabled={loading}
- />
- ) : (
- <StatusIcon type={LoadingType.CREATING} />
- ))}
- <Title variant="h5" color="textPrimary">
- {navInfo.navTitle}
- </Title>
- <Extra>{navInfo.extra}</Extra>
- </Navigation>
- <AddressWrapper>
- <ModeButton onClick={toggleColorMode} color="inherit">
- {mode === 'dark' ? <icons.night /> : <icons.day />}
- </ModeButton>
- <div className="text">
- <Typography className="address">{address}</Typography>
- <Typography className="status">{statusTrans.running}</Typography>
- </div>
- {username && (
- <>
- <Tooltip title={username}>
- <StyledIcon
- onClick={handleUserMenuClick}
- style={{ cursor: 'pointer' }}
- >
- <Avatar />
- </StyledIcon>
- </Tooltip>
- <Menu
- anchorEl={anchorEl}
- open={Boolean(anchorEl)}
- onClose={handleUserMenuClose}
- anchorOrigin={{
- vertical: 'bottom',
- horizontal: 'right',
- }}
- transformOrigin={{
- vertical: 'top',
- horizontal: 'right',
- }}
- >
- <MenuItem onClick={handleChangePassword}>
- {userTrans('changePassword')}
- </MenuItem>
- </Menu>
- </>
- )}
- <Tooltip title={'disconnect'}>
- <StyledIcon>
- <LogoutIcon onClick={handleLogout} />
- </StyledIcon>
- </Tooltip>
- </AddressWrapper>
- </ContentWrapper>
- </HeaderWrapper>
- );
- };
- export default Header;
|