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 manage roles #234

Merged
merged 2 commits into from
Jul 27, 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
14 changes: 14 additions & 0 deletions client/src/http/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {
CreateUserParams,
DeleteUserParams,
UpdateUserParams,
CreateRoleParams,
DeleteRoleParams,
} from '../pages/user/Types';
import BaseModel from './BaseModel';

Expand Down Expand Up @@ -31,6 +33,18 @@ export class UserHttp extends BaseModel {
return super.delete({ path: `${this.USER_URL}/${data.username}` });
}

static createRole(data: CreateRoleParams) {
return super.create({ path: `${this.USER_URL}/roles`, data });
}

static getRoles() {
return super.search({ path: `${this.USER_URL}/roles`, params: {} });
}

static deleteRole(data: DeleteRoleParams) {
return super.delete({ path: `${this.USER_URL}/roles/${data.roleName}` });
}

get _names() {
return this.names;
}
Expand Down
5 changes: 5 additions & 0 deletions client/src/i18n/en/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const userTrans = {
createTitle: 'Create User',
updateTitle: 'Update Milvus User',
user: 'User',
users: 'Users',
deleteWarning: 'You are trying to drop user. This action cannot be undone.',
oldPassword: 'Current Password',
newPassword: 'New Password',
Expand All @@ -10,6 +11,10 @@ const userTrans = {
isNotSame: 'Not same as new password',
deleteTip:
'Please select at least one item to drop and root can not be dropped.',

role: 'Role',
roles: 'Roles',
createRoleTitle: 'Create Role',
};

export default userTrans;
86 changes: 86 additions & 0 deletions client/src/pages/user/CreateRole.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { makeStyles, Theme } from '@material-ui/core';
import { FC, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import DialogTemplate from '@/components/customDialog/DialogTemplate';
import CustomInput from '@/components/customInput/CustomInput';
import { ITextfieldConfig } from '@/components/customInput/Types';
import { useFormValidation } from '@/hooks/Form';
import { formatForm } from '@/utils/Form';
import { CreateRoleProps, CreateRoleParams } from './Types';

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

const CreateRole: FC<CreateRoleProps> = ({ handleCreate, handleClose }) => {
const { t: commonTrans } = useTranslation();
const { t: userTrans } = useTranslation('user');
const { t: btnTrans } = useTranslation('btn');
const { t: warningTrans } = useTranslation('warning');
const attuTrans = commonTrans('attu');

const [form, setForm] = useState<CreateRoleParams>({
roleName: '',
});
const checkedForm = useMemo(() => {
return formatForm(form);
}, [form]);
const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);

const classes = useStyles();

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

const createConfigs: ITextfieldConfig[] = [
{
label: userTrans('role'),
key: 'roleName',
onChange: (value: string) => handleInputChange('roleName', value),
variant: 'filled',
className: classes.input,
placeholder: userTrans('role'),
fullWidth: true,
validations: [
{
rule: 'require',
errorText: warningTrans('required', {
name: userTrans('role'),
}),
},
],
defaultValue: form.roleName,
},
];

const handleCreateRole = () => {
handleCreate(form);
};

return (
<DialogTemplate
title={userTrans('createRoleTitle')}
handleClose={handleClose}
confirmLabel={btnTrans('create')}
handleConfirm={handleCreateRole}
confirmDisabled={disabled}
>
<>
{createConfigs.map(v => (
<CustomInput
type="text"
textConfig={v}
checkValid={checkIsValid}
validInfo={validation}
key={v.label}
/>
))}
</>
</DialogTemplate>
);
};

export default CreateRole;
File renamed without changes.
148 changes: 148 additions & 0 deletions client/src/pages/user/Roles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React, { useContext, useEffect, useState } from 'react';
import { makeStyles, Theme } from '@material-ui/core';
import { useTranslation } from 'react-i18next';
import { UserHttp } from '@/http/User';
import AttuGrid from '@/components/grid/Grid';
import { ColDefinitionsType, ToolBarConfig } from '@/components/grid/Types';
import { CreateRoleParams, DeleteRoleParams, RoleData } from './Types';
import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
import { rootContext } from '@/context/Root';
import { useNavigationHook } from '@/hooks/Navigation';
import { ALL_ROUTER_TYPES } from '@/router/Types';
import CreateRole from './CreateRole';

const useStyles = makeStyles((theme: Theme) => ({
wrapper: {
height: `calc(100vh - 160px)`,
},
}));

const Roles = () => {
useNavigationHook(ALL_ROUTER_TYPES.USER);
const classes = useStyles();

const [roles, setRoles] = useState<RoleData[]>([]);
const [selectedRole, setSelectedRole] = useState<RoleData[]>([]);
const { setDialog, handleCloseDialog, openSnackBar } =
useContext(rootContext);
const { t: successTrans } = useTranslation('success');
const { t: userTrans } = useTranslation('user');
const { t: btnTrans } = useTranslation('btn');
const { t: dialogTrans } = useTranslation('dialog');

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

setRoles(roles.results.map((v: any) => ({ name: v.role.name })));
};

const handleCreate = async (data: CreateRoleParams) => {
await UserHttp.createRole(data);
fetchRoles();
openSnackBar(successTrans('create', { name: userTrans('role') }));
handleCloseDialog();
};

const handleDelete = async () => {
for (const role of selectedRole) {
const param: DeleteRoleParams = {
roleName: role.name,
};
await UserHttp.deleteRole(param);
}

openSnackBar(successTrans('delete', { name: userTrans('role') }));
fetchRoles();
handleCloseDialog();
};

const toolbarConfigs: ToolBarConfig[] = [
{
label: userTrans('role'),
onClick: () => {
setDialog({
open: true,
type: 'custom',
params: {
component: (
<CreateRole
handleCreate={handleCreate}
handleClose={handleCloseDialog}
/>
),
},
});
},
icon: 'add',
},

{
type: 'iconBtn',
onClick: () => {
setDialog({
open: true,
type: 'custom',
params: {
component: (
<DeleteTemplate
label={btnTrans('drop')}
title={dialogTrans('deleteTitle', { type: userTrans('role') })}
text={userTrans('deleteWarning')}
handleDelete={handleDelete}
/>
),
},
});
},
label: '',
disabled: () =>
selectedRole.length === 0 ||
selectedRole.findIndex(v => v.name === 'root') > -1,
disabledTooltip: userTrans('deleteTip'),

icon: 'delete',
},
];

const colDefinitions: ColDefinitionsType[] = [
{
id: 'name',
align: 'left',
disablePadding: false,
label: userTrans('role'),
},
];

const handleSelectChange = (value: RoleData[]) => {
setSelectedRole(value);
};

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

return (
<div className={classes.wrapper}>
<AttuGrid
toolbarConfigs={toolbarConfigs}
colDefinitions={colDefinitions}
rows={roles}
rowCount={roles.length}
primaryKey="name"
showPagination={false}
selected={selectedRole}
setSelected={handleSelectChange}
// page={currentPage}
// onChangePage={handlePageChange}
// rowsPerPage={pageSize}
// setRowsPerPage={handlePageSize}
// isLoading={loading}
// order={order}
// orderBy={orderBy}
// handleSort={handleGridSort}
/>
</div>
);
};

export default Roles;
26 changes: 26 additions & 0 deletions client/src/pages/user/Types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface UserData {
name: string;
}

export interface CreateUserParams {
username: string;
password: string;
Expand All @@ -10,6 +11,7 @@ export interface CreateUserProps {
handleCreate: (data: CreateUserParams) => void;
handleClose: () => void;
}

export interface UpdateUserProps {
handleUpdate: (data: UpdateUserParams) => void;
handleClose: () => void;
Expand All @@ -25,3 +27,27 @@ export interface UpdateUserParams {
export interface DeleteUserParams {
username: string;
}

export interface CreateRoleParams {
roleName: string;
}

export interface CreateRoleProps {
handleCreate: (data: CreateRoleParams) => void;
handleClose: () => void;
}

export interface DeleteRoleParams {
roleName: string;
}

export interface RoleData {
name: string;
}

export enum TAB_EMUM {
'schema',
'partition',
'data-preview',
'data-query',
}
14 changes: 11 additions & 3 deletions client/src/pages/user/User.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useContext, useEffect, useState } from 'react';
import { makeStyles, Theme } from '@material-ui/core';
import { useTranslation } from 'react-i18next';
import { UserHttp } from '@/http/User';
import AttuGrid from '@/components/grid/Grid';
Expand All @@ -13,11 +14,18 @@ import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
import { rootContext } from '@/context/Root';
import { useNavigationHook } from '@/hooks/Navigation';
import { ALL_ROUTER_TYPES } from '@/router/Types';
import CreateUser from './Create';
import CreateUser from './CreateUser';
import UpdateUser from './Update';

const useStyles = makeStyles((theme: Theme) => ({
wrapper: {
height: `calc(100vh - 160px)`,
},
}));

const Users = () => {
useNavigationHook(ALL_ROUTER_TYPES.USER);
const classes = useStyles();

const [users, setUsers] = useState<UserData[]>([]);
const [selectedUser, setSelectedUser] = useState<UserData[]>([]);
Expand Down Expand Up @@ -114,7 +122,7 @@ const Users = () => {
id: 'name',
align: 'left',
disablePadding: false,
label: 'Name',
label: userTrans('user'),
},
{
id: 'action',
Expand Down Expand Up @@ -154,7 +162,7 @@ const Users = () => {
}, []);

return (
<div className="page-wrapper">
<div className={classes.wrapper}>
<AttuGrid
toolbarConfigs={toolbarConfigs}
colDefinitions={colDefinitions}
Expand Down
Loading
Loading