From 7c1316a332ac2d31afd9b4609734069011ddacd1 Mon Sep 17 00:00:00 2001 From: shanghaikid Date: Thu, 20 Jul 2023 16:00:17 +0800 Subject: [PATCH 1/3] add database api Signed-off-by: shanghaikid --- server/src/app.ts | 2 + server/src/database/databases.controller.ts | 66 +++++++++++++++++++++ server/src/database/databases.service.ts | 33 +++++++++++ server/src/database/dto.ts | 11 ++++ server/src/database/index.ts | 8 +++ 5 files changed, 120 insertions(+) create mode 100644 server/src/database/databases.controller.ts create mode 100644 server/src/database/databases.service.ts create mode 100644 server/src/database/dto.ts create mode 100644 server/src/database/index.ts diff --git a/server/src/app.ts b/server/src/app.ts index 036fa369..844d5224 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -8,6 +8,7 @@ import * as path from 'path'; import chalk from 'chalk'; import { router as connectRouter } from './milvus'; import { router as collectionsRouter } from './collections'; +import { router as databasesRouter } from './database'; import { router as partitionsRouter } from './partitions'; import { router as schemaRouter } from './schema'; import { router as cronsRouter } from './crons'; @@ -35,6 +36,7 @@ const insightCache = new LruCache({ const router = express.Router(); // define routers router.use('/milvus', connectRouter); +router.use('/databases', databasesRouter); router.use('/collections', collectionsRouter); router.use('/partitions', partitionsRouter); router.use('/schema', schemaRouter); diff --git a/server/src/database/databases.controller.ts b/server/src/database/databases.controller.ts new file mode 100644 index 00000000..bc2a4c27 --- /dev/null +++ b/server/src/database/databases.controller.ts @@ -0,0 +1,66 @@ +import { NextFunction, Request, Response, Router } from 'express'; +import { dtoValidationMiddleware } from '../middlewares/validation'; +import { milvusService } from '../milvus'; +import { DatabasesService } from './databases.service'; +import { CreateDatabaseDto, DropDatabaseDto } from './dto'; + +export class DatabasesController { + private databasesService: DatabasesService; + private router: Router; + + constructor() { + this.databasesService = new DatabasesService(milvusService); + + this.router = Router(); + } + + get databasesServiceGetter() { + return this.databasesService; + } + + generateRoutes() { + this.router.get('/', this.listDatabases.bind(this)); + this.router.post( + '/', + dtoValidationMiddleware(CreateDatabaseDto), + this.createDatabase.bind(this) + ); + this.router.delete( + '/', + dtoValidationMiddleware(DropDatabaseDto), + this.createDatabase.bind(this) + ); + return this.router; + } + + async createDatabase(req: Request, res: Response, next: NextFunction) { + const createDatabaseData = req.body; + try { + const result = await this.databasesService.createDatabase( + createDatabaseData + ); + res.send(result); + } catch (error) { + next(error); + } + } + + async listDatabases(req: Request, res: Response, next: NextFunction) { + try { + const result = await this.databasesService.listDatabase(); + res.send(result); + } catch (error) { + next(error); + } + } + + async dropDatabase(req: Request, res: Response, next: NextFunction) { + const dropDatabaseData = req.body; + try { + const result = await this.databasesService.dropDatabase(dropDatabaseData); + res.send(result); + } catch (error) { + next(error); + } + } +} diff --git a/server/src/database/databases.service.ts b/server/src/database/databases.service.ts new file mode 100644 index 00000000..82d9cf05 --- /dev/null +++ b/server/src/database/databases.service.ts @@ -0,0 +1,33 @@ +import { MilvusService } from '../milvus/milvus.service'; +import { + CreateDatabaseRequest, + ListDatabasesRequest, + DropDatabasesRequest, +} from '@zilliz/milvus2-sdk-node'; +import { throwErrorFromSDK } from '../utils/Error'; + +export class DatabasesService { + constructor(private milvusService: MilvusService) {} + + async createDatabase(data?: CreateDatabaseRequest) { + const res = await this.milvusService.client.createDatabase(data); + throwErrorFromSDK(res); + return res; + } + + async listDatabase(data?: ListDatabasesRequest) { + const res = await this.milvusService.client.listDatabases(data); + throwErrorFromSDK(res.status); + return res; + } + + async dropDatabase(data?: DropDatabasesRequest) { + const res = await this.milvusService.client.listDatabases(data); + throwErrorFromSDK(res.status); + return res; + } + + async use(db_name: string) { + return await await MilvusService.activeMilvusClient.use({ db_name }); + } +} diff --git a/server/src/database/dto.ts b/server/src/database/dto.ts new file mode 100644 index 00000000..1fc5c367 --- /dev/null +++ b/server/src/database/dto.ts @@ -0,0 +1,11 @@ +import { IsString } from 'class-validator'; + +export class CreateDatabaseDto { + @IsString() + readonly db_name: string; +} + +export class DropDatabaseDto { + @IsString() + readonly db_name: string; +} diff --git a/server/src/database/index.ts b/server/src/database/index.ts new file mode 100644 index 00000000..333d146a --- /dev/null +++ b/server/src/database/index.ts @@ -0,0 +1,8 @@ +import { DatabasesController } from './databases.controller'; + +const databasesManager = new DatabasesController(); + +const router = databasesManager.generateRoutes(); +const DatabasesService = databasesManager.databasesServiceGetter; + +export { router, DatabasesService }; From 51e9ba0743b0d396f3267ed40f8bb56b4bbea546 Mon Sep 17 00:00:00 2001 From: shanghaikid Date: Thu, 20 Jul 2023 19:06:39 +0800 Subject: [PATCH 2/3] add database UI Signed-off-by: shanghaikid --- client/src/components/icons/Icons.tsx | 63 +++++++++++ client/src/components/icons/Types.ts | 1 + client/src/hooks/Navigation.ts | 8 ++ client/src/http/Database.ts | 32 ++++++ client/src/i18n/cn/database.ts | 12 +++ client/src/i18n/en/collection.ts | 2 +- client/src/i18n/en/database.ts | 13 +++ client/src/i18n/en/index.ts | 2 +- client/src/i18n/en/nav.ts | 5 +- client/src/i18n/en/partition.ts | 2 +- client/src/i18n/en/user.ts | 4 +- client/src/i18n/index.ts | 4 + client/src/pages/database/Create.tsx | 84 +++++++++++++++ client/src/pages/database/Database.tsx | 143 +++++++++++++++++++++++++ client/src/pages/database/Types.ts | 15 +++ client/src/pages/database/Update.tsx | 140 ++++++++++++++++++++++++ client/src/pages/index.tsx | 9 ++ client/src/pages/user/User.tsx | 2 +- client/src/router/Router.tsx | 7 +- client/src/router/Types.ts | 1 + 20 files changed, 539 insertions(+), 10 deletions(-) create mode 100644 client/src/http/Database.ts create mode 100644 client/src/i18n/cn/database.ts create mode 100644 client/src/i18n/en/database.ts create mode 100644 client/src/pages/database/Create.tsx create mode 100644 client/src/pages/database/Database.tsx create mode 100644 client/src/pages/database/Types.ts create mode 100644 client/src/pages/database/Update.tsx diff --git a/client/src/components/icons/Icons.tsx b/client/src/components/icons/Icons.tsx index 037833b2..2aec22e9 100644 --- a/client/src/components/icons/Icons.tsx +++ b/client/src/components/icons/Icons.tsx @@ -120,6 +120,69 @@ const icons: { [x in IconsType]: (props?: any) => React.ReactElement } = { vectorSearch: (props = {}) => ( ), + database: (props = {}) => ( + + + + ), copyExpression: (props = {}) => ( ), diff --git a/client/src/components/icons/Types.ts b/client/src/components/icons/Types.ts index f51d662b..198487d5 100644 --- a/client/src/components/icons/Types.ts +++ b/client/src/components/icons/Types.ts @@ -40,4 +40,5 @@ export type IconsType = | 'download' | 'source' | 'edit' + | 'database' | 'uploadFile'; diff --git a/client/src/hooks/Navigation.ts b/client/src/hooks/Navigation.ts index dd114261..f632fa71 100644 --- a/client/src/hooks/Navigation.ts +++ b/client/src/hooks/Navigation.ts @@ -26,6 +26,14 @@ export const useNavigationHook = ( setNavInfo(navInfo); break; } + case ALL_ROUTER_TYPES.DATABASES: { + const navInfo: NavInfo = { + navTitle: navTrans('database'), + backPath: '', + }; + setNavInfo(navInfo); + break; + } case ALL_ROUTER_TYPES.COLLECTIONS: { const navInfo: NavInfo = { navTitle: navTrans('collection'), diff --git a/client/src/http/Database.ts b/client/src/http/Database.ts new file mode 100644 index 00000000..dfb38bb7 --- /dev/null +++ b/client/src/http/Database.ts @@ -0,0 +1,32 @@ +import { + CreateDatabaseParams, + DropDatabaseParams, +} from '../pages/database/Types'; +import BaseModel from './BaseModel'; + +export class DatabaseHttp extends BaseModel { + private names!: string[]; + + constructor(props: {}) { + super(props); + Object.assign(this, props); + } + + static DATABASE_URL = `/databases`; + + static getDatabases() { + return super.search({ path: this.DATABASE_URL, params: {} }); + } + + static createDatabase(data: CreateDatabaseParams) { + return super.create({ path: this.DATABASE_URL, data }); + } + + static dropDatabase(data: DropDatabaseParams) { + return super.delete({ path: `${this.DATABASE_URL}/${data.db_name}` }); + } + + get _names() { + return this.names; + } +} diff --git a/client/src/i18n/cn/database.ts b/client/src/i18n/cn/database.ts new file mode 100644 index 00000000..b78c7cd5 --- /dev/null +++ b/client/src/i18n/cn/database.ts @@ -0,0 +1,12 @@ +const databaseTrans = { + createTitle: 'Create database', + databases: 'Databases', + deleteWarning: + 'You are trying to drop a database. This action cannot be undone.', + databaseName: 'Database Name', + confirmDatabase: 'Confirm Password', + deleteTip: + 'Please select at least one item to drop and default_db can not be dropped.', +}; + +export default databaseTrans; diff --git a/client/src/i18n/en/collection.ts b/client/src/i18n/en/collection.ts index 1bf3ebf8..53070e3e 100644 --- a/client/src/i18n/en/collection.ts +++ b/client/src/i18n/en/collection.ts @@ -4,7 +4,7 @@ const collectionTrans = { rowCount: 'Approx Entity Count', - create: 'Create Collection', + create: 'Collection', delete: 'delete', deleteTooltip: 'Please select at least one item to delete.', rename: 'rename', diff --git a/client/src/i18n/en/database.ts b/client/src/i18n/en/database.ts new file mode 100644 index 00000000..cdaa5cb1 --- /dev/null +++ b/client/src/i18n/en/database.ts @@ -0,0 +1,13 @@ +const databaseTrans = { + createTitle: 'Create Database', + databases: 'Databases', + database: 'Database', + deleteWarning: + 'You are trying to drop a database. This action cannot be undone.', + databaseName: 'Database Name', + confirmDatabase: 'Confirm Password', + deleteTip: + 'Please select at least one item to drop and default_db can not be dropped.', +}; + +export default databaseTrans; diff --git a/client/src/i18n/en/index.ts b/client/src/i18n/en/index.ts index 58e2a56a..d570266b 100644 --- a/client/src/i18n/en/index.ts +++ b/client/src/i18n/en/index.ts @@ -2,7 +2,7 @@ const indexTrans = { type: 'Index Type', param: 'Index Parameters', - create: 'Create Index', + create: 'Index', index: 'Index', desc: 'Description', diff --git a/client/src/i18n/en/nav.ts b/client/src/i18n/en/nav.ts index 74ae4bd9..83e6b956 100644 --- a/client/src/i18n/en/nav.ts +++ b/client/src/i18n/en/nav.ts @@ -1,10 +1,11 @@ const navTrans = { overview: 'Overview', - collection: 'Collection', + collection: 'Collections', console: 'Search Console', search: 'Vector Search', system: 'System View', - user: 'Milvus Users', + user: 'Users', + database: 'Databases', }; export default navTrans; diff --git a/client/src/i18n/en/partition.ts b/client/src/i18n/en/partition.ts index 94360d93..6eef5d31 100644 --- a/client/src/i18n/en/partition.ts +++ b/client/src/i18n/en/partition.ts @@ -1,5 +1,5 @@ const partitionTrans = { - create: 'Create Partition', + create: 'Partition', delete: 'Delete partition', partition: 'Partition', diff --git a/client/src/i18n/en/user.ts b/client/src/i18n/en/user.ts index 6961cea7..ef407e95 100644 --- a/client/src/i18n/en/user.ts +++ b/client/src/i18n/en/user.ts @@ -1,7 +1,7 @@ const userTrans = { - createTitle: 'Create Milvus User', + createTitle: 'Create User', updateTitle: 'Update Milvus User', - user: 'Milvus User', + user: 'User', deleteWarning: 'You are trying to drop user. This action cannot be undone.', oldPassword: 'Current Password', newPassword: 'New Password', diff --git a/client/src/i18n/index.ts b/client/src/i18n/index.ts index fdd73433..f8ca3210 100644 --- a/client/src/i18n/index.ts +++ b/client/src/i18n/index.ts @@ -29,6 +29,8 @@ import systemViewTransEn from './en/systemView'; import systemViewTransCn from './cn/systemView'; import userTransEn from './en/user'; import userTransCn from './cn/user'; +import databaseTransEn from './en/database'; +import databaseTransCn from './cn/database'; import prometheusTransEn from './en/prometheus'; import prometheusTransCn from './cn/prometheus'; @@ -48,6 +50,7 @@ export const resources = { search: searchCn, systemView: systemViewTransCn, user: userTransCn, + database: databaseTransCn, prometheus: prometheusTransCn, }, en: { @@ -65,6 +68,7 @@ export const resources = { search: searchEn, systemView: systemViewTransEn, user: userTransEn, + database: databaseTransEn, prometheus: prometheusTransEn, }, }; diff --git a/client/src/pages/database/Create.tsx b/client/src/pages/database/Create.tsx new file mode 100644 index 00000000..15270b0a --- /dev/null +++ b/client/src/pages/database/Create.tsx @@ -0,0 +1,84 @@ +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 { CreateDatabaseProps, CreateDatabaseParams } from './Types'; + +const useStyles = makeStyles((theme: Theme) => ({ + input: { + margin: theme.spacing(3, 0, 0.5), + }, +})); + +const CreateUser: FC = ({ handleCreate, handleClose }) => { + const { t: databaseTrans } = useTranslation('database'); + const { t: btnTrans } = useTranslation('btn'); + const { t: warningTrans } = useTranslation('warning'); + + const [form, setForm] = useState({ + db_name: '', + }); + const checkedForm = useMemo(() => { + return formatForm(form); + }, [form]); + const { validation, checkIsValid, disabled } = useFormValidation(checkedForm); + + const classes = useStyles(); + + const handleInputChange = (key: 'db_name', value: string) => { + setForm(v => ({ ...v, [key]: value })); + }; + + const createConfigs: ITextfieldConfig[] = [ + { + label: databaseTrans('database'), + key: 'db_name', + onChange: (value: string) => handleInputChange('db_name', value), + variant: 'filled', + className: classes.input, + placeholder: databaseTrans('database'), + fullWidth: true, + validations: [ + { + rule: 'require', + errorText: warningTrans('required', { + name: databaseTrans('databaseName'), + }), + }, + ], + defaultValue: form.db_name, + }, + ]; + + const handleCreateDatabase = () => { + handleCreate(form); + }; + + return ( + + <> + {createConfigs.map(v => ( + + ))} + + + ); +}; + +export default CreateUser; diff --git a/client/src/pages/database/Database.tsx b/client/src/pages/database/Database.tsx new file mode 100644 index 00000000..ca9fed78 --- /dev/null +++ b/client/src/pages/database/Database.tsx @@ -0,0 +1,143 @@ +import React, { useContext, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DatabaseHttp } from '../../http/Database'; +import AttuGrid from '../../components/grid/Grid'; +import { ColDefinitionsType, ToolBarConfig } from '../../components/grid/Types'; +import { + CreateDatabaseParams, + DropDatabaseParams, + DatabaseData, +} 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 CreateUser from './Create'; + +const Database = () => { + useNavigationHook(ALL_ROUTER_TYPES.DATABASES); + + const [databases, setDatabases] = useState([]); + const [selectedDatabase, setSelectedDatabase] = useState([]); + const { setDialog, handleCloseDialog, openSnackBar } = + useContext(rootContext); + const { t: successTrans } = useTranslation('success'); + const { t: dbTrans } = useTranslation('database'); + const { t: btnTrans } = useTranslation('btn'); + const { t: dialogTrans } = useTranslation('dialog'); + + const fetchDatabases = async () => { + const res = await DatabaseHttp.getDatabases(); + setDatabases(res.db_names.map((v: string) => ({ name: v }))); + }; + + const handleCreate = async (data: CreateDatabaseParams) => { + await DatabaseHttp.createDatabase(data); + fetchDatabases(); + openSnackBar(successTrans('create', { name: dbTrans('database') })); + handleCloseDialog(); + }; + + const handleDelete = async () => { + for (const user of selectedDatabase) { + const param: DropDatabaseParams = { + db_name: user.name, + }; + await DatabaseHttp.dropDatabase(param); + } + + openSnackBar(successTrans('delete', { name: dbTrans('user') })); + fetchDatabases(); + handleCloseDialog(); + }; + + const toolbarConfigs: ToolBarConfig[] = [ + { + label: dbTrans('database'), + onClick: () => { + setDialog({ + open: true, + type: 'custom', + params: { + component: ( + + ), + }, + }); + }, + icon: 'add', + }, + + { + type: 'iconBtn', + onClick: () => { + setDialog({ + open: true, + type: 'custom', + params: { + component: ( + + ), + }, + }); + }, + label: '', + disabled: () => + selectedDatabase.length === 0 || + selectedDatabase.findIndex(v => v.name === 'root') > -1, + disabledTooltip: dbTrans('deleteTip'), + + icon: 'delete', + }, + ]; + + const colDefinitions: ColDefinitionsType[] = [ + { + id: 'name', + align: 'left', + disablePadding: false, + label: 'Name', + }, + ]; + + const handleSelectChange = (value: DatabaseData[]) => { + setSelectedDatabase(value); + }; + + useEffect(() => { + fetchDatabases(); + }, []); + + return ( +
+ +
+ ); +}; + +export default Database; diff --git a/client/src/pages/database/Types.ts b/client/src/pages/database/Types.ts new file mode 100644 index 00000000..0f54dd50 --- /dev/null +++ b/client/src/pages/database/Types.ts @@ -0,0 +1,15 @@ +export interface DatabaseData { + name: string; +} +export interface CreateDatabaseParams { + db_name: string; +} + +export interface CreateDatabaseProps { + handleCreate: (data: CreateDatabaseParams) => void; + handleClose: () => void; +} + +export interface DropDatabaseParams { + db_name: string; +} diff --git a/client/src/pages/database/Update.tsx b/client/src/pages/database/Update.tsx new file mode 100644 index 00000000..ca27afe9 --- /dev/null +++ b/client/src/pages/database/Update.tsx @@ -0,0 +1,140 @@ +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 { UpdateUserParams, UpdateUserProps } from './Types'; + +const useStyles = makeStyles((theme: Theme) => ({ + input: { + margin: theme.spacing(3, 0, 0.5), + }, +})); + +const UpdateUser: FC = ({ + handleClose, + handleUpdate, + username, +}) => { + const { t: userTrans } = useTranslation('user'); + const { t: btnTrans } = useTranslation('btn'); + const { t: warningTrans } = useTranslation('warning'); + + const [form, setForm] = useState< + Omit & { confirmPassword: string } + >({ + oldPassword: '', + newPassword: '', + confirmPassword: '', + }); + const checkedForm = useMemo(() => { + const { oldPassword, newPassword } = form; + return formatForm({ oldPassword, newPassword }); + }, [form]); + const { validation, checkIsValid, disabled } = useFormValidation(checkedForm); + + const classes = useStyles(); + + const handleInputChange = ( + key: 'oldPassword' | 'newPassword' | 'confirmPassword', + value: string + ) => { + setForm(v => ({ ...v, [key]: value })); + }; + + const createConfigs: ITextfieldConfig[] = [ + { + label: userTrans('oldPassword'), + key: 'oldPassword', + onChange: (value: string) => handleInputChange('oldPassword', value), + variant: 'filled', + className: classes.input, + placeholder: userTrans('oldPassword'), + fullWidth: true, + validations: [ + { + rule: 'require', + errorText: warningTrans('required', { + name: userTrans('oldPassword'), + }), + }, + ], + type: 'password', + defaultValue: form.oldPassword, + }, + { + label: userTrans('newPassword'), + key: 'newPassword', + onChange: (value: string) => handleInputChange('newPassword', value), + variant: 'filled', + className: classes.input, + placeholder: userTrans('newPassword'), + fullWidth: true, + validations: [ + { + rule: 'require', + errorText: warningTrans('required', { + name: userTrans('newPassword'), + }), + }, + ], + type: 'password', + defaultValue: form.newPassword, + }, + { + label: userTrans('confirmPassword'), + key: 'confirmPassword', + onChange: (value: string) => handleInputChange('confirmPassword', value), + variant: 'filled', + className: classes.input, + placeholder: userTrans('confirmPassword'), + fullWidth: true, + validations: [ + { + rule: 'confirm', + extraParam: { + compareValue: form.newPassword, + }, + errorText: userTrans('isNotSame'), + }, + ], + type: 'password', + defaultValue: form.confirmPassword, + }, + ]; + + const handleUpdateUser = () => { + handleUpdate({ + username, + newPassword: form.newPassword, + oldPassword: form.oldPassword, + }); + }; + + return ( + + <> + {createConfigs.map(v => ( + + ))} + + + ); +}; + +export default UpdateUser; diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index a15be4dd..aed4f90e 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -69,6 +69,10 @@ function Index() { return navTrans('user'); } + if (location.pathname.includes('databases')) { + return navTrans('database'); + } + return navTrans('overview'); }, [location, navTrans]); @@ -90,6 +94,11 @@ function Index() { iconActiveClass: 'normal', iconNormalClass: 'active', }, + { + icon: icons.database, + label: navTrans('database'), + onClick: () => navigate('/databases'), + }, ]; if (!isManaged) { diff --git a/client/src/pages/user/User.tsx b/client/src/pages/user/User.tsx index f2635257..4bbec30a 100644 --- a/client/src/pages/user/User.tsx +++ b/client/src/pages/user/User.tsx @@ -63,7 +63,7 @@ const Users = () => { const toolbarConfigs: ToolBarConfig[] = [ { - label: userTrans('createTitle'), + label: userTrans('user'), onClick: () => { setDialog({ open: true, diff --git a/client/src/router/Router.tsx b/client/src/router/Router.tsx index f365d88d..87a49eff 100644 --- a/client/src/router/Router.tsx +++ b/client/src/router/Router.tsx @@ -5,6 +5,7 @@ import Collection from '../pages/collections/Collection'; import Collections from '../pages/collections/Collections'; import Connect from '../pages/connect/Connect'; import Users from '../pages/user/User'; +import Database from '../pages/database/Database'; import Index from '../pages/index'; import Search from '../pages/search/VectorSearch'; import System from '../pages/system/SystemView'; @@ -15,6 +16,10 @@ const routeObj = [ path: '/', element: , children: [ + { + path: '/databases', + element: , + }, { path: '/collections', element: , @@ -23,12 +28,10 @@ const routeObj = [ path: '/collections/:collectionName', element: , }, - { path: '/search', element: , }, - { path: '/system_healthy', element: , diff --git a/client/src/router/Types.ts b/client/src/router/Types.ts index 65e77eb3..f3a413eb 100644 --- a/client/src/router/Types.ts +++ b/client/src/router/Types.ts @@ -12,6 +12,7 @@ export enum ALL_ROUTER_TYPES { // plugins PLUGIN = 'plugin', USER = 'user', + DATABASES = 'databases', } export type NavInfo = { From 57ed54d45bdff71bc5f9c619d85dff16f1154c75 Mon Sep 17 00:00:00 2001 From: shanghaikid Date: Thu, 20 Jul 2023 19:36:33 +0800 Subject: [PATCH 3/3] fix delete database Signed-off-by: shanghaikid --- client/src/pages/database/Database.tsx | 10 ++++++---- server/src/database/databases.controller.ts | 14 ++++++-------- server/src/database/databases.service.ts | 8 ++++---- server/src/database/dto.ts | 5 ----- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/client/src/pages/database/Database.tsx b/client/src/pages/database/Database.tsx index ca9fed78..bc8d8799 100644 --- a/client/src/pages/database/Database.tsx +++ b/client/src/pages/database/Database.tsx @@ -39,14 +39,14 @@ const Database = () => { }; const handleDelete = async () => { - for (const user of selectedDatabase) { + for (const db of selectedDatabase) { const param: DropDatabaseParams = { - db_name: user.name, + db_name: db.name, }; await DatabaseHttp.dropDatabase(param); } - openSnackBar(successTrans('delete', { name: dbTrans('user') })); + openSnackBar(successTrans('delete', { name: dbTrans('database') })); fetchDatabases(); handleCloseDialog(); }; @@ -81,7 +81,9 @@ const Database = () => { component: ( diff --git a/server/src/database/databases.controller.ts b/server/src/database/databases.controller.ts index bc2a4c27..311d8b62 100644 --- a/server/src/database/databases.controller.ts +++ b/server/src/database/databases.controller.ts @@ -2,7 +2,7 @@ import { NextFunction, Request, Response, Router } from 'express'; import { dtoValidationMiddleware } from '../middlewares/validation'; import { milvusService } from '../milvus'; import { DatabasesService } from './databases.service'; -import { CreateDatabaseDto, DropDatabaseDto } from './dto'; +import { CreateDatabaseDto } from './dto'; export class DatabasesController { private databasesService: DatabasesService; @@ -25,11 +25,9 @@ export class DatabasesController { dtoValidationMiddleware(CreateDatabaseDto), this.createDatabase.bind(this) ); - this.router.delete( - '/', - dtoValidationMiddleware(DropDatabaseDto), - this.createDatabase.bind(this) - ); + + this.router.delete('/:name', this.dropDatabase.bind(this)); + return this.router; } @@ -55,9 +53,9 @@ export class DatabasesController { } async dropDatabase(req: Request, res: Response, next: NextFunction) { - const dropDatabaseData = req.body; + const db_name = req.params?.name; try { - const result = await this.databasesService.dropDatabase(dropDatabaseData); + const result = await this.databasesService.dropDatabase({ db_name }); res.send(result); } catch (error) { next(error); diff --git a/server/src/database/databases.service.ts b/server/src/database/databases.service.ts index 82d9cf05..8d640a4a 100644 --- a/server/src/database/databases.service.ts +++ b/server/src/database/databases.service.ts @@ -9,7 +9,7 @@ import { throwErrorFromSDK } from '../utils/Error'; export class DatabasesService { constructor(private milvusService: MilvusService) {} - async createDatabase(data?: CreateDatabaseRequest) { + async createDatabase(data: CreateDatabaseRequest) { const res = await this.milvusService.client.createDatabase(data); throwErrorFromSDK(res); return res; @@ -21,9 +21,9 @@ export class DatabasesService { return res; } - async dropDatabase(data?: DropDatabasesRequest) { - const res = await this.milvusService.client.listDatabases(data); - throwErrorFromSDK(res.status); + async dropDatabase(data: DropDatabasesRequest) { + const res = await this.milvusService.client.dropDatabase(data); + throwErrorFromSDK(res); return res; } diff --git a/server/src/database/dto.ts b/server/src/database/dto.ts index 1fc5c367..ffd49c26 100644 --- a/server/src/database/dto.ts +++ b/server/src/database/dto.ts @@ -4,8 +4,3 @@ export class CreateDatabaseDto { @IsString() readonly db_name: string; } - -export class DropDatabaseDto { - @IsString() - readonly db_name: string; -}