Skip to content

Commit

Permalink
update password dialog (#780)
Browse files Browse the repository at this point in the history
Signed-off-by: ryjiang <[email protected]>
  • Loading branch information
shanghaikid authored Feb 25, 2025
1 parent 8c286b2 commit f36783e
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 67 deletions.
93 changes: 84 additions & 9 deletions client/src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { FC, useContext } from 'react';
import { FC, useContext, useState, MouseEvent } from 'react';
import { useTranslation } from 'react-i18next';
import { Theme, Typography, Tooltip } from '@mui/material';
import { Theme } from '@mui/material';
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 } from '@/context';
import { navContext, dataContext, authContext, rootContext } from '@/context';
import { MilvusService } from '@/http';
import CustomSelector from '@/components/customSelector/CustomSelector';
import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
import StatusIcon from '@/components/status/StatusIcon';
import { LoadingType } from '@/components/status/StatusIcon';
import UpdateUser from '@/pages/user/dialogs/UpdateUserPassDialog';
import icons from '../icons/Icons';
import { makeStyles } from '@mui/styles';
import IconButton from '@mui/material/IconButton';
Expand Down Expand Up @@ -85,22 +91,34 @@ const useStyles = makeStyles((theme: Theme) => ({
}));

const Header: FC = () => {
// styles
const classes = useStyles();
// 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');

// icons
const BackIcon = icons.back;
const LogoutIcon = icons.logout;
const Avatar = icons.avatar;

// UI handlers
const handleBack = (path: string) => {
navigate(path);
};
Expand All @@ -113,6 +131,41 @@ const Header: FC = () => {
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;

Expand Down Expand Up @@ -173,11 +226,33 @@ const Header: FC = () => {
<Typography className="status">{statusTrans.running}</Typography>
</div>
{username && (
<Tooltip title={username}>
<div>
<Avatar classes={{ root: classes.icon }} />
</div>
</Tooltip>
<>
<Tooltip title={username}>
<div
onClick={handleUserMenuClick}
style={{ cursor: 'pointer' }}
>
<Avatar classes={{ root: classes.icon }} />
</div>
</Tooltip>
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleUserMenuClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
>
<MenuItem onClick={handleChangePassword}>
Change Password
</MenuItem>
</Menu>
</>
)}
<Tooltip title={'disconnect'}>
<div>
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/cn/success.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const successTrans = {
empty: `{{name}}清空已经开始.`,
reset: `{{name}}重置成功。`,
modifyReplica: `{{name}}修改副本数量成功。`,
passwordChanged: `密码更新成功`,
};

export default successTrans;
1 change: 1 addition & 0 deletions client/src/i18n/cn/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const userTrans = {
createTitle: '创建用户',
updateTitle: '更新Milvus用户',
updateUserPassTitle: `更新 {{username}} 的密码`,
updateRoleTitle: '更新用户角色',
user: '用户',
users: '用户们',
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/en/success.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const successTrans = {
empty: `Emptying data for {{name}} has started.`,
reset: `{{name}} has been reset.`,
modifyReplica: `Replica number for {{name}} has been modified.`,
passwordChanged: `Password updated successfully`,
};

export default successTrans;
1 change: 1 addition & 0 deletions client/src/i18n/en/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const userTrans = {
createTitle: 'Create User',
updateTitle: 'Update Milvus User',
updateUserPassTitle: `Update {{username}}'s Password`,
updateRoleTitle: 'Update User Roles',
user: 'User',
users: 'Users',
Expand Down
35 changes: 0 additions & 35 deletions client/src/pages/databases/tree/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,8 @@ export const useStyles = makeStyles((theme: Theme) => ({
fontSize: '15px',
color: theme.palette.text.primary,
backgroundColor: theme.palette.background.default,
'& .MuiTreeItem-iconContainer': {
width: 'auto',
},
'& .MuiTreeItem-group': {
marginLeft: 0,
'& .MuiTreeItem-content': {
padding: '0 0 0 8px',
},
},
'& .MuiTreeItem-label:hover': {
backgroundColor: 'none',
},
'& .MuiTreeItem-content': {
width: 'auto',
padding: '0',
'&.Mui-focused': {
backgroundColor: 'rgba(10, 206, 130, 0.08)',
},
'&.Mui-selected': {
backgroundColor: 'rgba(10, 206, 130, 0.28)',
},
'&.Mui-focused.Mui-selected': {
backgroundColor: 'rgba(10, 206, 130, 0.28) !important',
},

'&:hover': {
backgroundColor: 'rgba(10, 206, 130, 0.08)',
},
'& .MuiTreeItem-label': {
background: 'none',
},
},
},
treeItem: {
'& .MuiTreeItem-iconContainer': {
color: '#666',
},
'& .right-selected-on': {
'& .MuiTreeItem-content': {
backgroundColor: 'rgba(10, 206, 130, 0.08)',
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/user/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface CreateUserProps {
}

export interface UpdateUserProps {
handleUpdate: (data: UpdateUserParams) => void;
onUpdate: (res: any) => void;
handleClose: () => void;
username: string;
}
Expand Down
15 changes: 9 additions & 6 deletions client/src/pages/user/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,14 @@ const Users = () => {
handleCloseDialog();
};

const handleUpdate = async (data: UpdateUserParams) => {
await UserService.updateUser(data);
fetchUsers();
openSnackBar(successTrans('update', { name: userTrans('user') }));
handleCloseDialog();
const onUpdateUserPass = async (res: any) => {
if (res.error_code === 'Success') {
openSnackBar(successTrans('passwordChanged'));
fetchUsers();
handleCloseDialog();
} else {
openSnackBar(res.detail, 'error');
}
};

const handleDelete = async () => {
Expand Down Expand Up @@ -149,7 +152,7 @@ const Users = () => {
component: (
<UpdateUser
username={selectedUser[0]!.username}
handleUpdate={handleUpdate}
onUpdate={onUpdateUserPass}
handleClose={handleCloseDialog}
/>
),
Expand Down
50 changes: 34 additions & 16 deletions client/src/pages/user/dialogs/UpdateUserPassDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,65 @@ import CustomInput from '@/components/customInput/CustomInput';
import { useFormValidation } from '@/hooks';
import { formatForm } from '@/utils';
import { makeStyles } from '@mui/styles';
import { UserService } from '@/http';
import type { UpdateUserParams, UpdateUserProps } from '../Types';
import type { ITextfieldConfig } from '@/components/customInput/Types';

const useStyles = makeStyles((theme: Theme) => ({
root: {
maxWidth: 480,
},
input: {
margin: theme.spacing(1, 0, 0.5),
},
}));

const UpdateUser: FC<UpdateUserProps> = ({
handleClose,
handleUpdate,
onUpdate,
username,
}) => {
// styles
const classes = useStyles();

// i18n
const { t: userTrans } = useTranslation('user');
const { t: btnTrans } = useTranslation('btn');
const { t: warningTrans } = useTranslation('warning');

// UI state
const [form, setForm] = useState<
Omit<UpdateUserParams, 'username'> & { confirmPassword: string }
>({
oldPassword: '',
newPassword: '',
confirmPassword: '',
});

// UI handlers
const checkedForm = useMemo(() => {
const { oldPassword, newPassword } = form;
return formatForm({ oldPassword, newPassword });
}, [form]);
const { oldPassword, newPassword, confirmPassword } = form;
return formatForm({ oldPassword, newPassword, confirmPassword });
}, [JSON.stringify(form)]);
const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);

const classes = useStyles();

const handleInputChange = (
key: 'oldPassword' | 'newPassword' | 'confirmPassword',
value: string
) => {
setForm(v => ({ ...v, [key]: value }));
};

const handleUpdateUser = async () => {
const res = await UserService.updateUser({
username,
newPassword: form.newPassword,
oldPassword: form.oldPassword,
});
onUpdate(res);
};

// UI configs
const createConfigs: ITextfieldConfig[] = [
{
label: userTrans('oldPassword'),
Expand Down Expand Up @@ -94,6 +113,12 @@ const UpdateUser: FC<UpdateUserProps> = ({
placeholder: userTrans('confirmPassword'),
fullWidth: true,
validations: [
{
rule: 'require',
errorText: warningTrans('required', {
name: userTrans('newPassword'),
}),
},
{
rule: 'confirm',
extraParam: {
Expand All @@ -107,19 +132,12 @@ const UpdateUser: FC<UpdateUserProps> = ({
},
];

const handleUpdateUser = () => {
handleUpdate({
username,
newPassword: form.newPassword,
oldPassword: form.oldPassword,
});
};

return (
<DialogTemplate
title={userTrans('updateTitle')}
dialogClass={classes.root}
title={userTrans('updateUserPassTitle', { username })}
handleClose={handleClose}
confirmLabel={btnTrans('create')}
confirmLabel={btnTrans('update')}
handleConfirm={handleUpdateUser}
confirmDisabled={disabled}
>
Expand Down
Loading

0 comments on commit f36783e

Please sign in to comment.