Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support create/edit user role on user page #236

Merged
merged 9 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions client/src/http/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
UpdateUserParams,
CreateRoleParams,
DeleteRoleParams,
AssignRoleParams,
UnassignRoleParams,
} from '../pages/user/Types';
import BaseModel from './BaseModel';

Expand Down Expand Up @@ -45,6 +47,20 @@ export class UserHttp extends BaseModel {
return super.delete({ path: `${this.USER_URL}/roles/${data.roleName}` });
}

static updateUserRole(data: AssignRoleParams) {
return super.update({
path: `${this.USER_URL}/${data.username}/role/update`,
data,
});
}

static unassignUserRole(data: UnassignRoleParams) {
return super.update({
path: `${this.USER_URL}/${data.username}/role/unassign`,
data,
});
}

get _names() {
return this.names;
}
Expand Down
7 changes: 5 additions & 2 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',
updateRoleTitle: 'Update User Roles',
user: 'User',
users: 'Users',
deleteWarning: 'You are trying to drop user. This action cannot be undone.',
Expand All @@ -10,11 +11,13 @@ const userTrans = {
update: 'Update password',
isNotSame: 'Not same as new password',
deleteTip:
'Please select at least one item to drop and root can not be dropped.',

'Please select at least one item to drop and the root user can not be dropped.',
deleteEditRoleTip: 'root role is not editable.',
role: 'Role',
editRole: 'Edit Role',
roles: 'Roles',
createRoleTitle: 'Create Role',
updateRoleSuccess: 'User Role',
};

export default userTrans;
61 changes: 58 additions & 3 deletions client/src/pages/user/CreateUser.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { makeStyles, Theme } from '@material-ui/core';
import {
makeStyles,
Theme,
Checkbox,
FormGroup,
FormControlLabel,
Typography,
} from '@material-ui/core';
import { FC, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import DialogTemplate from '@/components/customDialog/DialogTemplate';
Expand All @@ -7,14 +14,25 @@ import { ITextfieldConfig } from '@/components/customInput/Types';
import { useFormValidation } from '@/hooks/Form';
import { formatForm } from '@/utils/Form';
import { CreateUserProps, CreateUserParams } from './Types';
import { Option as RoleOption } from '@/components/customSelector/Types';

const useStyles = makeStyles((theme: Theme) => ({
input: {
margin: theme.spacing(3, 0, 0.5),
margin: theme.spacing(2, 0, 0.5),
},
dialogWrapper: {
maxWidth: theme.spacing(70),
'& .MuiFormControlLabel-root': {
width: theme.spacing(20),
},
},
}));

const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
const CreateUser: FC<CreateUserProps> = ({
handleCreate,
handleClose,
roleOptions,
}) => {
const { t: commonTrans } = useTranslation();
const { t: userTrans } = useTranslation('user');
const { t: btnTrans } = useTranslation('btn');
Expand All @@ -24,10 +42,14 @@ const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
const [form, setForm] = useState<CreateUserParams>({
username: '',
password: '',
roles: [],
});

// selected Role
const checkedForm = useMemo(() => {
return formatForm(form);
}, [form]);

const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);

const classes = useStyles();
Expand Down Expand Up @@ -87,6 +109,7 @@ const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
confirmLabel={btnTrans('create')}
handleConfirm={handleCreateUser}
confirmDisabled={disabled}
dialogClass={classes.dialogWrapper}
>
<>
{createConfigs.map(v => (
Expand All @@ -98,6 +121,38 @@ const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
key={v.label}
/>
))}

<Typography variant="h5" component="span">
{userTrans('roles')}
</Typography>

<FormGroup row>
{roleOptions.map((r: RoleOption, index: number) => (
<FormControlLabel
control={
<Checkbox
onChange={(
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean
) => {
let newRoles = [...form.roles];

if (!checked) {
newRoles = newRoles.filter((n: string) => n === r.value);
} else {
newRoles.push(String(r.value));
}

setForm(v => ({ ...v, roles: [...newRoles] }));
}}
/>
}
key={index}
label={r.label}
value={r.value}
/>
))}
</FormGroup>
</>
</DialogTemplate>
);
Expand Down
25 changes: 25 additions & 0 deletions client/src/pages/user/Types.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
import { Option as RoleOption } from '@/components/customSelector/Types';

export interface UserData {
name: string;
roleName?: string;
roles: string[];
}

export interface CreateUserParams {
username: string;
password: string;
roles: string[];
}

export interface UpdateUserRoleParams {
username: string;
roles: string[];
}

export interface UpdateUserRoleProps {
onUpdate: (data: UpdateUserRoleParams) => void;
handleClose: () => void;
username: string;
roles: string[];
}

export interface CreateUserProps {
handleCreate: (data: CreateUserParams) => void;
handleClose: () => void;
roleOptions: RoleOption[];
}

export interface UpdateUserProps {
Expand Down Expand Up @@ -41,6 +59,13 @@ export interface DeleteRoleParams {
roleName: string;
}

export interface AssignRoleParams {
username: string;
roles: string[];
}

export interface UnassignRoleParams extends AssignRoleParams {}

export interface RoleData {
name: string;
}
Expand Down
103 changes: 103 additions & 0 deletions client/src/pages/user/UpdateUserRole.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {
makeStyles,
Theme,
Checkbox,
FormGroup,
FormControlLabel,
} from '@material-ui/core';
import { FC, useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import DialogTemplate from '@/components/customDialog/DialogTemplate';
import { UpdateUserRoleProps, UpdateUserRoleParams } from './Types';
import { UserHttp } from '@/http/User';

const useStyles = makeStyles((theme: Theme) => ({
input: {
margin: theme.spacing(2, 0, 0.5),
},
dialogWrapper: {
maxWidth: theme.spacing(70),
'& .MuiFormControlLabel-root': {
width: theme.spacing(20),
},
},
}));

const UpdateUserRole: FC<UpdateUserRoleProps> = ({
onUpdate,
handleClose,
roles,
username,
}) => {
const { t: userTrans } = useTranslation('user');
const { t: btnTrans } = useTranslation('btn');
const [roleOptions, setRoleOptions] = useState([]);

const [form, setForm] = useState<UpdateUserRoleParams>({
username: username,
roles: roles,
});

const classes = useStyles();

const handleUpdate = async () => {
await UserHttp.updateUserRole(form);
onUpdate(form);
};

const fetchAllRoles = async () => {
const roles = await UserHttp.getRoles();

setRoleOptions(roles.results.map((r: any) => r.role.name));
};

useEffect(() => {
fetchAllRoles();
}, []);

return (
<DialogTemplate
title={userTrans('updateRoleTitle')}
handleClose={handleClose}
confirmLabel={btnTrans('update')}
handleConfirm={handleUpdate}
confirmDisabled={false}
dialogClass={classes.dialogWrapper}
>
<>
<FormGroup row>
{roleOptions.map((roleOption: string, index: number) => (
<FormControlLabel
control={
<Checkbox
onChange={(
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean
) => {
let newRoles = [...form.roles];

if (!checked) {
newRoles = newRoles.filter(
(n: string | number) => n !== roleOption
);
} else {
newRoles.push(roleOption);
}

setForm(v => ({ ...v, roles: [...newRoles] }));
}}
/>
}
key={index}
label={roleOption}
value={roleOption}
checked={form.roles.indexOf(roleOption) !== -1}
/>
))}
</FormGroup>
</>
</DialogTemplate>
);
};

export default UpdateUserRole;
Loading
Loading