Browse Source

Merge pull request #236 from zilliztech/user_roles

Support create/edit user role on user page
ryjiang 1 year ago
parent
commit
011ab44076

+ 16 - 0
client/src/http/User.ts

@@ -4,6 +4,8 @@ import {
   UpdateUserParams,
   CreateRoleParams,
   DeleteRoleParams,
+  AssignRoleParams,
+  UnassignRoleParams,
 } from '../pages/user/Types';
 import BaseModel from './BaseModel';
 
@@ -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;
   }

+ 5 - 2
client/src/i18n/en/user.ts

@@ -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.',
@@ -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;

+ 58 - 3
client/src/pages/user/CreateUser.tsx

@@ -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';
@@ -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');
@@ -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();
@@ -87,6 +109,7 @@ const CreateUser: FC<CreateUserProps> = ({ handleCreate, handleClose }) => {
       confirmLabel={btnTrans('create')}
       handleConfirm={handleCreateUser}
       confirmDisabled={disabled}
+      dialogClass={classes.dialogWrapper}
     >
       <>
         {createConfigs.map(v => (
@@ -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>
   );

+ 25 - 0
client/src/pages/user/Types.ts

@@ -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 {
@@ -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;
 }

+ 103 - 0
client/src/pages/user/UpdateUserRole.tsx

@@ -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;

+ 73 - 4
client/src/pages/user/User.tsx

@@ -9,12 +9,14 @@ import {
   DeleteUserParams,
   UpdateUserParams,
   UserData,
+  UpdateUserRoleParams,
 } 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 './CreateUser';
+import UpdateUserRole from './UpdateUserRole';
 import UpdateUser from './Update';
 
 const useStyles = makeStyles((theme: Theme) => ({
@@ -38,17 +40,45 @@ const Users = () => {
 
   const fetchUsers = async () => {
     const res = await UserHttp.getUsers();
-
-    setUsers(res.usernames.map((v: string) => ({ name: v })));
+    const roles = await UserHttp.getRoles();
+    setUsers(
+      res.usernames.map((v: string) => {
+        const name = v;
+        const rolesByName = roles.results.filter((r: any) =>
+          r.users.map((u: any) => u.name).includes(name)
+        );
+        const originRoles =
+          v === 'root' ? ['root'] : rolesByName.map((r: any) => r.role.name);
+        return {
+          name: v,
+          role: originRoles.join(' , '),
+          roles: originRoles,
+        };
+      })
+    );
   };
 
   const handleCreate = async (data: CreateUserParams) => {
     await UserHttp.createUser(data);
+    // assign user role if
+    await UserHttp.updateUserRole({
+      username: data.username,
+      roles: data.roles,
+    });
+
     fetchUsers();
     openSnackBar(successTrans('create', { name: userTrans('user') }));
     handleCloseDialog();
   };
 
+  const onUpdate = async (data: UpdateUserRoleParams) => {
+    fetchUsers();
+    openSnackBar(
+      successTrans('update', { name: userTrans('updateRoleSuccess') })
+    );
+    handleCloseDialog();
+  };
+
   const handleUpdate = async (data: UpdateUserParams) => {
     await UserHttp.updateUser(data);
     fetchUsers();
@@ -72,7 +102,8 @@ const Users = () => {
   const toolbarConfigs: ToolBarConfig[] = [
     {
       label: userTrans('user'),
-      onClick: () => {
+      onClick: async () => {
+        const roles = await UserHttp.getRoles();
         setDialog({
           open: true,
           type: 'custom',
@@ -81,6 +112,9 @@ const Users = () => {
               <CreateUser
                 handleCreate={handleCreate}
                 handleClose={handleCloseDialog}
+                roleOptions={roles.results.map((r: any) => {
+                  return { label: r.role.name, value: r.role.name };
+                })}
               />
             ),
           },
@@ -89,6 +123,35 @@ const Users = () => {
       icon: 'add',
     },
 
+    {
+      type: 'iconBtn',
+      label: userTrans('editRole'),
+      onClick: async () => {
+        setDialog({
+          open: true,
+          type: 'custom',
+          params: {
+            component: (
+              <UpdateUserRole
+                username={selectedUser[0]!.name}
+                onUpdate={onUpdate}
+                handleClose={handleCloseDialog}
+                roles={
+                  users.filter(u => u.name === selectedUser[0].name)[0].roles
+                }
+              />
+            ),
+          },
+        });
+      },
+      icon: 'edit',
+      disabled: () =>
+        selectedUser.length === 0 ||
+        selectedUser.length > 1 ||
+        selectedUser.findIndex(v => v.name === 'root') > -1,
+      disabledTooltip: userTrans('deleteEditRoleTip'),
+    },
+
     {
       type: 'iconBtn',
       onClick: () => {
@@ -112,7 +175,6 @@ const Users = () => {
         selectedUser.length === 0 ||
         selectedUser.findIndex(v => v.name === 'root') > -1,
       disabledTooltip: userTrans('deleteTip'),
-
       icon: 'delete',
     },
   ];
@@ -124,11 +186,18 @@ const Users = () => {
       disablePadding: false,
       label: userTrans('user'),
     },
+    {
+      id: 'role',
+      align: 'left',
+      disablePadding: false,
+      label: userTrans('role'),
+    },
     {
       id: 'action',
       disablePadding: false,
       label: 'Action',
       showActionCell: true,
+      sortBy: 'action',
       actionBarConfigs: [
         {
           onClick: (e: React.MouseEvent, row: UserData) => {

+ 1 - 1
server/package.json

@@ -12,7 +12,7 @@
     "url": "https://github.com/zilliztech/attu"
   },
   "dependencies": {
-    "@zilliz/milvus2-sdk-node": "^2.2.19",
+    "@zilliz/milvus2-sdk-node": "2.2.22-beta.1",
     "axios": "^1.4.0",
     "chalk": "^4.1.2",
     "class-sanitizer": "^1.0.1",

+ 16 - 0
server/src/users/dto.ts

@@ -23,3 +23,19 @@ export class UpdateUserDto {
   @IsString()
   readonly newPassword: string;
 }
+
+export class AssignUserRoleDto {
+  @IsString()
+  readonly username: string;
+
+  @IsString({ each: true })
+  readonly roles: string;
+}
+
+export class UnassignUserRoleDto {
+  @IsString()
+  readonly username: string;
+
+  @IsString()
+  readonly roleName: string;
+}

+ 74 - 2
server/src/users/users.controller.ts

@@ -2,8 +2,13 @@ import { NextFunction, Request, Response, Router } from 'express';
 import { dtoValidationMiddleware } from '../middlewares/validation';
 import { UserService } from './users.service';
 import { milvusService } from '../milvus';
-
-import { CreateUserDto, UpdateUserDto, CreateRoleDto } from './dto';
+import {
+  CreateUserDto,
+  UpdateUserDto,
+  CreateRoleDto,
+  AssignUserRoleDto,
+  UnassignUserRoleDto,
+} from './dto';
 
 export class UserController {
   private router: Router;
@@ -41,12 +46,25 @@ export class UserController {
 
     this.router.delete('/roles/:roleName', this.deleteRole.bind(this));
 
+    this.router.put(
+      '/:username/role/update',
+      dtoValidationMiddleware(AssignUserRoleDto),
+      this.updateUserRole.bind(this)
+    );
+
+    this.router.put(
+      '/:username/role/unassign',
+      dtoValidationMiddleware(UnassignUserRoleDto),
+      this.unassignUserRole.bind(this)
+    );
+
     return this.router;
   }
 
   async getUsers(req: Request, res: Response, next: NextFunction) {
     try {
       const result = await this.userService.getUsers();
+
       res.send(result);
     } catch (error) {
       next(error);
@@ -115,4 +133,58 @@ export class UserController {
       next(error);
     }
   }
+
+  async updateUserRole(req: Request, res: Response, next: NextFunction) {
+    const { roles } = req.body;
+    const { username } = req.params;
+
+    const results = [];
+
+    try {
+      // get user existing roles
+      const selectUser = await this.userService.selectUser({
+        username,
+        includeRoleInfo: false,
+      });
+
+      const existingRoles = selectUser.results[0].roles;
+      // remove user existing roles
+      for (let i = 0; i < existingRoles.length; i++) {
+        if (existingRoles[i].name.length > 0) {
+          await this.userService.unassignUserRole({
+            username,
+            roleName: existingRoles[i].name,
+          });
+        }
+      }
+
+      // assign new user roles
+      for (let i = 0; i < roles.length; i++) {
+        const result = await this.userService.assignUserRole({
+          username,
+          roleName: roles[i],
+        });
+        results.push(result);
+      }
+
+      res.send(results);
+    } catch (error) {
+      next(error);
+    }
+  }
+
+  async unassignUserRole(req: Request, res: Response, next: NextFunction) {
+    const { roleName } = req.body;
+    const { username } = req.params;
+
+    try {
+      const result = await this.userService.unassignUserRole({
+        username,
+        roleName,
+      });
+      res.send(result);
+    } catch (error) {
+      next(error);
+    }
+  }
 }

+ 32 - 4
server/src/users/users.service.ts

@@ -5,6 +5,11 @@ import {
   DeleteUserReq,
   CreateRoleReq,
   DropRoleReq,
+  AddUserToRoleReq,
+  RemoveUserFromRoleReq,
+  HasRoleReq,
+  listRoleReq,
+  SelectUserReq,
 } from '@zilliz/milvus2-sdk-node';
 import { throwErrorFromSDK } from '../utils/Error';
 
@@ -38,10 +43,15 @@ export class UserService {
     return res;
   }
 
-  async getRoles() {
-    const res = await this.milvusService.client.listRoles({
-      includeUserInfo: true,
-    });
+  async getRoles(data?: listRoleReq) {
+    const res = await this.milvusService.client.listRoles(data);
+    throwErrorFromSDK(res.status);
+
+    return res;
+  }
+
+  async selectUser(data?: SelectUserReq) {
+    const res = await this.milvusService.client.selectUser(data);
     throwErrorFromSDK(res.status);
 
     return res;
@@ -59,4 +69,22 @@ export class UserService {
     throwErrorFromSDK(res);
     return res;
   }
+
+  async assignUserRole(data: AddUserToRoleReq) {
+    const res = await this.milvusService.client.addUserToRole(data);
+    throwErrorFromSDK(res);
+    return res;
+  }
+
+  async unassignUserRole(data: RemoveUserFromRoleReq) {
+    const res = await this.milvusService.client.removeUserFromRole(data);
+    throwErrorFromSDK(res);
+    return res;
+  }
+
+  async hasRole(data: HasRoleReq) {
+    const res = await this.milvusService.client.hasRole(data);
+    throwErrorFromSDK(res.status);
+    return res;
+  }
 }

+ 5 - 11
server/tslint.json

@@ -1,19 +1,13 @@
 {
   "defaultSeverity": "error",
-  "extends": [
-    "tslint:recommended"
-  ],
+  "extends": ["tslint:recommended"],
   "jsRules": {},
   "rules": {
-    "trailing-comma": [
-      false
-    ],
+    "trailing-comma": [false],
     "no-console": false,
     "max-classes-per-file": false,
-    "variable-name": [
-      false,
-      "allow-leading-underscore"
-    ]
+    "variable-name": [false, "allow-leading-underscore"],
+    "prefer-for-of": false
   },
   "rulesDirectory": []
-}
+}

+ 36 - 114
server/yarn.lock

@@ -15,14 +15,14 @@
     "@jridgewell/gen-mapping" "^0.3.0"
     "@jridgewell/trace-mapping" "^0.3.9"
 
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.22.5":
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658"
   integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==
   dependencies:
     "@babel/highlight" "^7.22.5"
 
-"@babel/compat-data@^7.16.0", "@babel/compat-data@^7.22.9":
+"@babel/compat-data@^7.22.9":
   version "7.22.9"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730"
   integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==
@@ -48,7 +48,7 @@
     json5 "^2.2.2"
     semver "^6.3.1"
 
-"@babel/generator@^7.16.0", "@babel/generator@^7.22.7", "@babel/generator@^7.22.9", "@babel/generator@^7.7.2":
+"@babel/generator@^7.22.7", "@babel/generator@^7.22.9", "@babel/generator@^7.7.2":
   version "7.22.9"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d"
   integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==
@@ -58,7 +58,7 @@
     "@jridgewell/trace-mapping" "^0.3.17"
     jsesc "^2.5.1"
 
-"@babel/helper-compilation-targets@^7.16.0", "@babel/helper-compilation-targets@^7.22.9":
+"@babel/helper-compilation-targets@^7.22.9":
   version "7.22.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892"
   integrity sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==
@@ -74,7 +74,7 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98"
   integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==
 
-"@babel/helper-function-name@^7.16.0", "@babel/helper-function-name@^7.22.5":
+"@babel/helper-function-name@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be"
   integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==
@@ -82,35 +82,21 @@
     "@babel/template" "^7.22.5"
     "@babel/types" "^7.22.5"
 
-"@babel/helper-get-function-arity@^7.16.0":
-  version "7.16.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa"
-  integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==
-  dependencies:
-    "@babel/types" "^7.16.0"
-
-"@babel/helper-hoist-variables@^7.16.0", "@babel/helper-hoist-variables@^7.22.5":
+"@babel/helper-hoist-variables@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
   integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
   dependencies:
     "@babel/types" "^7.22.5"
 
-"@babel/helper-member-expression-to-functions@^7.16.0":
-  version "7.16.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4"
-  integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==
-  dependencies:
-    "@babel/types" "^7.16.0"
-
-"@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.22.5":
+"@babel/helper-module-imports@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c"
   integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==
   dependencies:
     "@babel/types" "^7.22.5"
 
-"@babel/helper-module-transforms@^7.16.0", "@babel/helper-module-transforms@^7.22.9":
+"@babel/helper-module-transforms@^7.22.9":
   version "7.22.9"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129"
   integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==
@@ -121,36 +107,19 @@
     "@babel/helper-split-export-declaration" "^7.22.6"
     "@babel/helper-validator-identifier" "^7.22.5"
 
-"@babel/helper-optimise-call-expression@^7.16.0":
-  version "7.16.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338"
-  integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==
-  dependencies:
-    "@babel/types" "^7.16.0"
-
 "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
   integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
 
-"@babel/helper-replace-supers@^7.16.0":
-  version "7.16.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17"
-  integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==
-  dependencies:
-    "@babel/helper-member-expression-to-functions" "^7.16.0"
-    "@babel/helper-optimise-call-expression" "^7.16.0"
-    "@babel/traverse" "^7.16.0"
-    "@babel/types" "^7.16.0"
-
-"@babel/helper-simple-access@^7.16.0", "@babel/helper-simple-access@^7.22.5":
+"@babel/helper-simple-access@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de"
   integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
   dependencies:
     "@babel/types" "^7.22.5"
 
-"@babel/helper-split-export-declaration@^7.16.0", "@babel/helper-split-export-declaration@^7.22.6":
+"@babel/helper-split-export-declaration@^7.22.6":
   version "7.22.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
   integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
@@ -162,17 +131,17 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
   integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
 
-"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.15.7", "@babel/helper-validator-identifier@^7.22.5":
+"@babel/helper-validator-identifier@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
   integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
 
-"@babel/helper-validator-option@^7.14.5", "@babel/helper-validator-option@^7.22.5":
+"@babel/helper-validator-option@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac"
   integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==
 
-"@babel/helpers@^7.16.0", "@babel/helpers@^7.22.6":
+"@babel/helpers@^7.22.6":
   version "7.22.6"
   resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd"
   integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==
@@ -181,7 +150,7 @@
     "@babel/traverse" "^7.22.6"
     "@babel/types" "^7.22.5"
 
-"@babel/highlight@^7.14.5", "@babel/highlight@^7.16.0", "@babel/highlight@^7.22.5":
+"@babel/highlight@^7.22.5":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031"
   integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==
@@ -190,7 +159,7 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.0", "@babel/parser@^7.22.5", "@babel/parser@^7.22.7":
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.22.5", "@babel/parser@^7.22.7":
   version "7.22.7"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae"
   integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==
@@ -293,7 +262,7 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
 
-"@babel/template@^7.16.0", "@babel/template@^7.22.5", "@babel/template@^7.3.3":
+"@babel/template@^7.22.5", "@babel/template@^7.3.3":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec"
   integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==
@@ -302,7 +271,7 @@
     "@babel/parser" "^7.22.5"
     "@babel/types" "^7.22.5"
 
-"@babel/traverse@^7.16.0", "@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8":
+"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8":
   version "7.22.8"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e"
   integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==
@@ -318,7 +287,7 @@
     debug "^4.1.0"
     globals "^11.1.0"
 
-"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.22.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
+"@babel/types@^7.0.0", "@babel/types@^7.22.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe"
   integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==
@@ -438,15 +407,15 @@
     minimatch "^3.0.4"
     plist "^3.0.4"
 
-"@grpc/grpc-js@^1.8.17":
-  version "1.8.18"
-  resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.18.tgz#fdbf2728064fd3db7e72e970372db28bd0f6fafb"
-  integrity sha512-2uWPtxhsXmVgd8WzDhfamSjHpZDXfMjMDciY6VRTq4Sn7rFzazyf0LLDa0oav+61UHIoEZb4KKaAV6S7NuJFbQ==
+"@grpc/grpc-js@1.8.17":
+  version "1.8.17"
+  resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.17.tgz#a3a2f826fc033eae7d2f5ee41e0ab39cee948838"
+  integrity sha512-DGuSbtMFbaRsyffMf+VEkVu8HkSXEUfO3UyGJNtqxW9ABdtTIA+2UXAJpwbJS+xfQxuwqLUeELmL6FuZkOqPxw==
   dependencies:
     "@grpc/proto-loader" "^0.7.0"
     "@types/node" ">=12.12.47"
 
-"@grpc/proto-loader@^0.7.0", "@grpc/proto-loader@^0.7.7":
+"@grpc/proto-loader@0.7.7", "@grpc/proto-loader@^0.7.0":
   version "0.7.7"
   resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.7.tgz#d33677a77eea8407f7c66e2abd97589b60eb4b21"
   integrity sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==
@@ -1211,16 +1180,16 @@
   resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.9.tgz#b6ef7457e826be8049667ae673eda7876eb049be"
   integrity sha512-4VSbbcMoxc4KLjb1gs96SRmi7w4h1SF+fCoiK0XaQX62buCc1G5d0DC5bJ9xJBNPDSVCmIrcl8BiYxzjrqaaJA==
 
-"@zilliz/milvus2-sdk-node@^2.2.19":
-  version "2.2.19"
-  resolved "https://registry.yarnpkg.com/@zilliz/milvus2-sdk-node/-/milvus2-sdk-node-2.2.19.tgz#423764fb077999366918c66946a62a8717242927"
-  integrity sha512-kKlQpic5ceVr7OQ0rg+AWHsMUcfoRvzn7BWKPutzU+Sst8cDbLiEaDcSaSR9gUchISBsKh7WwQ7WqK0rYpSYWA==
+"@zilliz/milvus2-sdk-node@2.2.21-beta.1":
+  version "2.2.22-beta.1"
+  resolved "https://registry.yarnpkg.com/@zilliz/milvus2-sdk-node/-/milvus2-sdk-node-2.2.22-beta.1.tgz#c58456c6c82bd7a5b34b3b3a6360d818233ad618"
+  integrity sha512-PrG1AWbv8HvHFbfKrXCbSsFFVLoWBfRfNcqJjSH1Lh5Av6RtWOuSz4wfO+7Ko78+vJ1RZtIe4zfFUezp83feEA==
   dependencies:
-    "@grpc/grpc-js" "^1.8.17"
-    "@grpc/proto-loader" "^0.7.7"
+    "@grpc/grpc-js" "1.8.17"
+    "@grpc/proto-loader" "0.7.7"
     dayjs "^1.11.7"
     lru-cache "^9.1.2"
-    protobufjs "^7.2.4"
+    protobufjs "7.2.4"
     winston "^3.9.0"
 
 abbrev@1, abbrev@^1.0.0:
@@ -1606,7 +1575,7 @@ braces@^3.0.1, braces@~3.0.2:
   dependencies:
     fill-range "^7.0.1"
 
-browserslist@^4.16.6, browserslist@^4.21.9:
+browserslist@^4.21.9:
   version "4.21.9"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635"
   integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==
@@ -1752,7 +1721,7 @@ camelcase@^6.2.0:
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
   integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
 
-caniuse-lite@^1.0.30001274, caniuse-lite@^1.0.30001503:
+caniuse-lite@^1.0.30001503:
   version "1.0.30001516"
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz#621b1be7d85a8843ee7d210fd9d87b52e3daab3a"
   integrity sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==
@@ -1860,15 +1829,6 @@ cli-truncate@^2.1.0:
     slice-ansi "^3.0.0"
     string-width "^4.2.0"
 
-cliui@^7.0.2:
-  version "7.0.4"
-  resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
-  integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
-  dependencies:
-    string-width "^4.2.0"
-    strip-ansi "^6.0.0"
-    wrap-ansi "^7.0.0"
-
 cliui@^8.0.1:
   version "8.0.1"
   resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
@@ -2296,7 +2256,7 @@ electron-publish@24.4.0:
     lazy-val "^1.0.5"
     mime "^2.5.2"
 
-electron-to-chromium@^1.3.886, electron-to-chromium@^1.4.431:
+electron-to-chromium@^1.4.431:
   version "1.4.464"
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.464.tgz#2f94bad78dff34e527aacbfc5d0b1a33cf046507"
   integrity sha512-guZ84yoou4+ILNdj0XEbmGs6DEWj6zpVOWYpY09GU66yEb0DSYvP/biBPzHn0GuW/3RC/pnaYNUWlQE1fJYtgA==
@@ -3549,7 +3509,7 @@ json-stringify-safe@^5.0.1:
   resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
   integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
 
-json5@^2.1.2, json5@^2.2.0, json5@^2.2.2, json5@^2.2.3:
+json5@^2.2.0, json5@^2.2.2, json5@^2.2.3:
   version "2.2.3"
   resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
   integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
@@ -3768,11 +3728,6 @@ micromatch@^4.0.4:
     braces "^3.0.1"
     picomatch "^2.2.3"
 
-mime-db@1.50.0:
-  version "1.50.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f"
-  integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==
-
 mime-db@1.52.0:
   version "1.52.0"
   resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@@ -3943,11 +3898,6 @@ natural-compare@^1.4.0:
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
   integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
 
-negotiator@0.6.2:
-  version "0.6.2"
-  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
-  integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
-
 negotiator@0.6.3, negotiator@^0.6.3:
   version "0.6.3"
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
@@ -4001,7 +3951,7 @@ node-int64@^0.4.0:
   resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
   integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=
 
-node-releases@^2.0.1, node-releases@^2.0.12:
+node-releases@^2.0.12:
   version "2.0.13"
   resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
   integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
@@ -4290,7 +4240,7 @@ prompts@^2.0.1:
     kleur "^3.0.3"
     sisteransi "^1.0.5"
 
-protobufjs@^7.0.0, protobufjs@^7.2.4:
+protobufjs@7.2.4, protobufjs@^7.0.0:
   version "7.2.4"
   resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae"
   integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==
@@ -4734,11 +4684,6 @@ source-map-support@^0.5.19:
     buffer-from "^1.0.0"
     source-map "^0.6.0"
 
-source-map@^0.5.0:
-  version "0.5.7"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
-  integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-
 source-map@^0.6.0, source-map@^0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@@ -5280,11 +5225,6 @@ xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1:
   resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
   integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==
 
-xmlbuilder@^9.0.7:
-  version "9.0.7"
-  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
-  integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
-
 y18n@^5.0.5:
   version "5.0.8"
   resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
@@ -5300,29 +5240,11 @@ yallist@^4.0.0:
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
   integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
 
-yargs-parser@^20.2.2:
-  version "20.2.9"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
-  integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
-
 yargs-parser@^21.0.1, yargs-parser@^21.1.1:
   version "21.1.1"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
   integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
 
-yargs@^16.2.0:
-  version "16.2.0"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
-  integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
-  dependencies:
-    cliui "^7.0.2"
-    escalade "^3.1.1"
-    get-caller-file "^2.0.5"
-    require-directory "^2.1.1"
-    string-width "^4.2.0"
-    y18n "^5.0.5"
-    yargs-parser "^20.2.2"
-
 yargs@^17.0.1, yargs@^17.3.1, yargs@^17.6.2, yargs@^17.7.2:
   version "17.7.2"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"