Pārlūkot izejas kodu

feat: upgrade UI (#894)

* part1

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* grade status action

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update common.css

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* adjust gap

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update seach page UI

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update UI for collections

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update schema style

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update tab style

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* upgrade user and page ui

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* fix icon

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update schema page ui

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update pk style

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update ui

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update theme

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* part23

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update connect UI

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update alert color

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* better mmap edit dialog

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* update i18n

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

---------

Signed-off-by: ryjiang <jiangruiyi@gmail.com>
ryjiang 1 mēnesi atpakaļ
vecāks
revīzija
923045221d
57 mainītis faili ar 1163 papildinājumiem un 830 dzēšanām
  1. 15 11
      client/src/components/customSelector/CustomMultiSelector.tsx
  2. 13 32
      client/src/components/customSnackBar/CustomSnackBar.tsx
  3. 2 3
      client/src/components/customTabList/CustomTabList.tsx
  4. 2 5
      client/src/components/customTabList/RouteTabList.tsx
  5. 2 1
      client/src/components/customToolTip/CustomToolTip.tsx
  6. 1 0
      client/src/components/customToolTip/Types.ts
  7. 7 1
      client/src/components/grid/Grid.tsx
  8. 7 2
      client/src/components/grid/ToolBar.tsx
  9. 1 0
      client/src/components/grid/Types.ts
  10. 17 19
      client/src/components/icons/Icons.tsx
  11. 2 3
      client/src/components/icons/Types.ts
  12. 29 16
      client/src/components/layout/Header.tsx
  13. 44 20
      client/src/components/menu/NavMenu.tsx
  14. 1 1
      client/src/components/status/Status.tsx
  15. 2 1
      client/src/components/status/Types.ts
  16. 3 8
      client/src/context/Root.tsx
  17. 2 2
      client/src/context/hooks/useSnackBar.ts
  18. 1 1
      client/src/i18n/cn/button.ts
  19. 9 7
      client/src/i18n/cn/collection.ts
  20. 2 1
      client/src/i18n/cn/common.ts
  21. 1 1
      client/src/i18n/cn/dialog.ts
  22. 17 18
      client/src/i18n/en/button.ts
  23. 4 3
      client/src/i18n/en/collection.ts
  24. 3 4
      client/src/i18n/en/common.ts
  25. 1 1
      client/src/i18n/en/dialog.ts
  26. 13 13
      client/src/i18n/en/success.ts
  27. 145 61
      client/src/pages/connect/AuthForm.tsx
  28. 28 24
      client/src/pages/connect/ConnectContainer.tsx
  29. 7 7
      client/src/pages/databases/Databases.tsx
  30. 1 1
      client/src/pages/databases/StyledComponents.ts
  31. 6 4
      client/src/pages/databases/collections/Collections.tsx
  32. 237 155
      client/src/pages/databases/collections/StatusAction.tsx
  33. 36 62
      client/src/pages/databases/collections/data/CollectionData.tsx
  34. 67 11
      client/src/pages/databases/collections/schema/IndexTypeElement.tsx
  35. 17 2
      client/src/pages/databases/collections/schema/Schema.tsx
  36. 6 6
      client/src/pages/databases/collections/schema/StyledComponents.tsx
  37. 124 118
      client/src/pages/databases/collections/search/Search.tsx
  38. 1 12
      client/src/pages/databases/collections/search/SearchInputBox.tsx
  39. 1 1
      client/src/pages/databases/collections/search/SearchParams.tsx
  40. 23 29
      client/src/pages/databases/collections/search/StyledComponents.ts
  41. 2 4
      client/src/pages/databases/tree/index.tsx
  42. 38 57
      client/src/pages/dialogs/EditMmapDialog.tsx
  43. 1 0
      client/src/pages/dialogs/create/rows/ScalarFieldRow.tsx
  44. 0 1
      client/src/pages/dialogs/insert/Dialog.tsx
  45. 11 10
      client/src/pages/home/DatabaseCard.tsx
  46. 4 3
      client/src/pages/home/Home.tsx
  47. 0 3
      client/src/pages/home/SysCard.tsx
  48. 0 6
      client/src/pages/index.tsx
  49. 4 2
      client/src/pages/play/Play.tsx
  50. 2 2
      client/src/pages/system/NodeListView.tsx
  51. 1 3
      client/src/pages/system/SystemView.tsx
  52. 1 4
      client/src/pages/user/PrivilegeGroups.tsx
  53. 13 13
      client/src/pages/user/Roles.tsx
  54. 1 4
      client/src/pages/user/User.tsx
  55. 1 2
      client/src/pages/user/UsersAndRoles.tsx
  56. 1 9
      client/src/styles/common.css
  57. 183 40
      client/src/styles/theme.ts

+ 15 - 11
client/src/components/customSelector/CustomMultiSelector.tsx

@@ -19,6 +19,7 @@ const CustomSelector: FC<CustomMultiSelectorType> = props => {
     labelClass = '',
     labelClass = '',
     size = 'small',
     size = 'small',
     renderValue = selected => <>selected</>,
     renderValue = selected => <>selected</>,
+    sx,
     ...others
     ...others
   } = props;
   } = props;
 
 
@@ -29,7 +30,7 @@ const CustomSelector: FC<CustomMultiSelectorType> = props => {
       variant={variant}
       variant={variant}
       className={wrapperClass}
       className={wrapperClass}
       size={size}
       size={size}
-      sx={{ minWidth: 120 }}
+      sx={{ ...sx }}
     >
     >
       {label && (
       {label && (
         <InputLabel className={labelClass} htmlFor={id}>
         <InputLabel className={labelClass} htmlFor={id}>
@@ -38,7 +39,6 @@ const CustomSelector: FC<CustomMultiSelectorType> = props => {
       )}
       )}
       <Select
       <Select
         className={classes?.root}
         className={classes?.root}
-        {...others}
         multiple
         multiple
         value={values}
         value={values}
         onChange={onChange}
         onChange={onChange}
@@ -46,25 +46,29 @@ const CustomSelector: FC<CustomMultiSelectorType> = props => {
           id,
           id,
         }}
         }}
         renderValue={renderValue}
         renderValue={renderValue}
-        sx={{
-          '& .MuiSelect-multiple': {
-            display: 'flex',
-            flexWrap: 'wrap',
-            gap: 0.5,
+        MenuProps={{
+          PaperProps: {
+            style: {
+              maxHeight: 300,
+            },
           },
           },
         }}
         }}
+        {...others}
       >
       >
         {options.map(v => (
         {options.map(v => (
           <MenuItem
           <MenuItem
             key={v.value}
             key={v.value}
             value={v.value}
             value={v.value}
             sx={{
             sx={{
-              minHeight: 'auto',
-              px: 1,
-              fontSize: '0.875rem',
+              padding: '4px',
+              fontSize: '12px',
             }}
             }}
           >
           >
-            <Checkbox checked={values.indexOf(v.value as string) !== -1} />
+            <Checkbox
+              checked={values.indexOf(v.value as string) !== -1}
+              size="small"
+              sx={{ padding: '4px' }}
+            />
             {v.label}
             {v.label}
           </MenuItem>
           </MenuItem>
         ))}
         ))}

+ 13 - 32
client/src/components/customSnackBar/CustomSnackBar.tsx

@@ -1,60 +1,41 @@
 import { forwardRef, FC } from 'react';
 import { forwardRef, FC } from 'react';
 import MuiAlert from '@mui/material/Alert';
 import MuiAlert from '@mui/material/Alert';
+import Icons from '@/components/icons/Icons';
 import Snackbar from '@mui/material/Snackbar';
 import Snackbar from '@mui/material/Snackbar';
-import Slide from '@mui/material/Slide';
 import type { AlertProps } from '@mui/material/Alert';
 import type { AlertProps } from '@mui/material/Alert';
-import type { SlideProps } from '@mui/material/Slide';
 import type { CustomSnackBarType } from './Types';
 import type { CustomSnackBarType } from './Types';
 
 
 // Forward ref for Alert component
 // Forward ref for Alert component
 const Alert = forwardRef<HTMLDivElement, AlertProps>((props, ref) => {
 const Alert = forwardRef<HTMLDivElement, AlertProps>((props, ref) => {
-  return <MuiAlert ref={ref} elevation={6} variant="filled" {...props} />;
+  return <MuiAlert ref={ref} elevation={0} variant="filled" {...props} />;
 });
 });
 
 
-// SlideTransition component
-const SlideTransition: FC<SlideProps> = props => {
-  return <Slide {...props} direction="left" />;
-};
-
 const CustomSnackBar: FC<CustomSnackBarType> = props => {
 const CustomSnackBar: FC<CustomSnackBarType> = props => {
   const {
   const {
-    vertical,
-    horizontal,
+    vertical = 'top',
+    horizontal = 'center',
     open,
     open,
-    autoHideDuration = 2500,
+    autoHideDuration = 3000,
     type,
     type,
     message,
     message,
     onClose,
     onClose,
   } = props;
   } = props;
 
 
-  const handleClose = (event: React.SyntheticEvent<any> | Event) => {
-    onClose && onClose();
-  };
-
   return (
   return (
     <Snackbar
     <Snackbar
-      anchorOrigin={{
-        vertical: vertical,
-        horizontal: horizontal,
-      }}
-      key={`${vertical}${horizontal}`}
+      anchorOrigin={{ vertical, horizontal }}
       open={open}
       open={open}
-      onClose={handleClose}
+      onClose={onClose}
       autoHideDuration={autoHideDuration}
       autoHideDuration={autoHideDuration}
-      TransitionComponent={SlideTransition}
-      sx={{
-        '&.MuiSnackbar-anchorOriginTopRight': {
-          top: { xs: 56, md: 72 },
-          right: theme => theme.spacing(4),
-        },
-      }}
     >
     >
       <Alert
       <Alert
-        onClose={handleClose}
+        onClose={onClose}
         severity={type}
         severity={type}
-        sx={{
-          maxWidth: '50vh',
-          wordBreak: 'break-all',
+        iconMapping={{
+          error: <Icons.error />,
+          info: <Icons.info />,
+          success: <Icons.check />,
+          warning: <Icons.cross />,
         }}
         }}
       >
       >
         {message}
         {message}

+ 2 - 3
client/src/components/customTabList/CustomTabList.tsx

@@ -54,7 +54,6 @@ const CustomTabList: FC<ITabListProps> = props => {
             height: theme => theme.spacing(0.5),
             height: theme => theme.spacing(0.5),
           },
           },
         }}
         }}
-        TabIndicatorProps={{ children: <div className="tab-indicator" /> }}
         value={value}
         value={value}
         onChange={handleChange}
         onChange={handleChange}
         aria-label="tabs"
         aria-label="tabs"
@@ -64,7 +63,7 @@ const CustomTabList: FC<ITabListProps> = props => {
             sx={{
             sx={{
               textTransform: 'capitalize',
               textTransform: 'capitalize',
               minWidth: 0,
               minWidth: 0,
-              marginRight: theme => theme.spacing(3),
+              fontSize: '13px',
             }}
             }}
             key={tab.label}
             key={tab.label}
             label={tab.label}
             label={tab.label}
@@ -93,4 +92,4 @@ const CustomTabList: FC<ITabListProps> = props => {
   );
   );
 };
 };
 
 
-export default CustomTabList;
+export default CustomTabList;

+ 2 - 5
client/src/components/customTabList/RouteTabList.tsx

@@ -9,14 +9,12 @@ import type { SxProps, Theme } from '@mui/material/styles';
 const tabSx: SxProps<Theme> = {
 const tabSx: SxProps<Theme> = {
   textTransform: 'capitalize',
   textTransform: 'capitalize',
   minWidth: 0,
   minWidth: 0,
-  marginRight: 3,
+  fontSize: '13px',
+  fontWeight: 500,
 };
 };
 
 
 const tabsSx: SxProps<Theme> = {
 const tabsSx: SxProps<Theme> = {
   borderBottom: theme => `1px solid ${theme.palette.divider}`,
   borderBottom: theme => `1px solid ${theme.palette.divider}`,
-  '& .MuiTabs-indicator': {
-    height: (theme: Theme) => theme.spacing(0.5),
-  },
 };
 };
 
 
 const tabPanelSx: SxProps<Theme> = {
 const tabPanelSx: SxProps<Theme> = {
@@ -75,7 +73,6 @@ const RouteTabList: FC<ITabListProps> = props => {
     <Box sx={wrapperSx} className={wrapperClass}>
     <Box sx={wrapperSx} className={wrapperClass}>
       <Tabs
       <Tabs
         sx={tabsSx}
         sx={tabsSx}
-        TabIndicatorProps={{ children: <div className="tab-indicator" /> }}
         value={activeIndex}
         value={activeIndex}
         onChange={handleChange}
         onChange={handleChange}
         aria-label="tabs"
         aria-label="tabs"

+ 2 - 1
client/src/components/customToolTip/CustomToolTip.tsx

@@ -3,10 +3,11 @@ import { FC } from 'react';
 import type { CustomToolTipType } from './Types';
 import type { CustomToolTipType } from './Types';
 
 
 const CustomToolTip: FC<CustomToolTipType> = props => {
 const CustomToolTip: FC<CustomToolTipType> = props => {
-  const { title, placement = 'right', children, leaveDelay = 0, sx } = props;
+  const { title, placement = 'right', children, leaveDelay = 0, enterDelay = 0, sx } = props;
   return (
   return (
     <Tooltip
     <Tooltip
       leaveDelay={leaveDelay}
       leaveDelay={leaveDelay}
+      enterDelay={enterDelay}
       title={title}
       title={title}
       placement={placement}
       placement={placement}
       arrow
       arrow

+ 1 - 0
client/src/components/customToolTip/Types.ts

@@ -6,6 +6,7 @@ export type CustomToolTipType = {
   placement?: placement;
   placement?: placement;
   children: ReactElement<any, any>;
   children: ReactElement<any, any>;
   leaveDelay?: number;
   leaveDelay?: number;
+  enterDelay?: number;
   sx?: SxProps<Theme>;
   sx?: SxProps<Theme>;
 };
 };
 
 

+ 7 - 1
client/src/components/grid/Grid.tsx

@@ -78,6 +78,7 @@ const AttuGrid: FC<AttuGridType> = props => {
     showPagination = true,
     showPagination = true,
     hideOnDisable,
     hideOnDisable,
     rowDecorator = () => ({}),
     rowDecorator = () => ({}),
+    sx = {},
   } = props;
   } = props;
 
 
   const _isSelected = (row: { [x: string]: any }) => {
   const _isSelected = (row: { [x: string]: any }) => {
@@ -157,7 +158,12 @@ const AttuGrid: FC<AttuGridType> = props => {
   return (
   return (
     <Grid
     <Grid
       container
       container
-      sx={{ height: '100%', flexWrap: 'nowrap', flexDirection: 'column' }}
+      sx={{
+        height: '100%',
+        flexWrap: 'nowrap',
+        flexDirection: 'column',
+        ...sx,
+      }}
       ref={tableRef}
       ref={tableRef}
     >
     >
       {title && (
       {title && (

+ 7 - 2
client/src/components/grid/ToolBar.tsx

@@ -71,10 +71,15 @@ const CustomToolBar: FC<ToolBarType> = props => {
                 // use contained variant as default
                 // use contained variant as default
                 variant={c.btnVariant || 'contained'}
                 variant={c.btnVariant || 'contained'}
                 tooltip={tooltip}
                 tooltip={tooltip}
-                sx={theme => ({ marginRight: theme.spacing(0.5) })}
+                sx={theme => ({
+                  marginRight: theme.spacing(0.5),
+                  p: theme.spacing(1),
+                })}
                 role="button"
                 role="button"
               >
               >
-                <Typography variant="button">{c.label}</Typography>
+                <Typography variant="button" sx={{ fontSize: 13 }}>
+                  {c.label}
+                </Typography>
               </CustomButton>
               </CustomButton>
             );
             );
 
 

+ 1 - 0
client/src/components/grid/Types.ts

@@ -157,6 +157,7 @@ export type AttuGridType = ToolBarType & {
   hideOnDisable?: boolean;
   hideOnDisable?: boolean;
   pagerHeight?: number;
   pagerHeight?: number;
   rowDecorator?: (row: any) => SxProps<Theme> | React.CSSProperties;
   rowDecorator?: (row: any) => SxProps<Theme> | React.CSSProperties;
+  sx?: SxProps<Theme>;
 };
 };
 
 
 export type ActionBarType = {
 export type ActionBarType = {

+ 17 - 19
client/src/components/icons/Icons.tsx

@@ -1,6 +1,5 @@
 import React from 'react';
 import React from 'react';
 import { SvgIcon, SvgIconProps } from '@mui/material';
 import { SvgIcon, SvgIconProps } from '@mui/material';
-import AppsIcon from '@mui/icons-material/Apps';
 import CancelIcon from '@mui/icons-material/Cancel';
 import CancelIcon from '@mui/icons-material/Cancel';
 import ConsoleIcon from '@/assets/icons/console.svg?react';
 import ConsoleIcon from '@/assets/icons/console.svg?react';
 import KeyIcon from '@/assets/icons/key.svg?react';
 import KeyIcon from '@/assets/icons/key.svg?react';
@@ -62,23 +61,6 @@ const icons: {
       ></path>
       ></path>
     </SvgIcon>
     </SvgIcon>
   ),
   ),
-  fileplus: props => (
-    <SvgIcon
-      width="15"
-      height="15"
-      viewBox="0 0 15 15"
-      fill="none"
-      {...props}
-      xmlns="http://www.w3.org/2000/svg"
-    >
-      <path
-        d="M3.5 2C3.22386 2 3 2.22386 3 2.5V12.5C3 12.7761 3.22386 13 3.5 13H11.5C11.7761 13 12 12.7761 12 12.5V4.70711L9.29289 2H3.5ZM2 2.5C2 1.67157 2.67157 1 3.5 1H9.5C9.63261 1 9.75979 1.05268 9.85355 1.14645L12.7803 4.07322C12.921 4.21388 13 4.40464 13 4.60355V12.5C13 13.3284 12.3284 14 11.5 14H3.5C2.67157 14 2 13.3284 2 12.5V2.5ZM4.75 7.5C4.75 7.22386 4.97386 7 5.25 7H7V5.25C7 4.97386 7.22386 4.75 7.5 4.75C7.77614 4.75 8 4.97386 8 5.25V7H9.75C10.0261 7 10.25 7.22386 10.25 7.5C10.25 7.77614 10.0261 8 9.75 8H8V9.75C8 10.0261 7.77614 10.25 7.5 10.25C7.22386 10.25 7 10.0261 7 9.75V8H5.25C4.97386 8 4.75 7.77614 4.75 7.5Z"
-        fill="currentColor"
-        fillRule="evenodd"
-        clipRule="evenodd"
-      ></path>
-    </SvgIcon>
-  ),
   delete: (props = {}) => (
   delete: (props = {}) => (
     <SvgIcon
     <SvgIcon
       width="15"
       width="15"
@@ -163,7 +145,6 @@ const icons: {
       ></path>
       ></path>
     </SvgIcon>
     </SvgIcon>
   ),
   ),
-  app: (props = {}) => <AppsIcon {...props} />,
   visible: (props = {}) => (
   visible: (props = {}) => (
     <SvgIcon
     <SvgIcon
       width="15"
       width="15"
@@ -1029,6 +1010,23 @@ const icons: {
       ></path>
       ></path>
     </SvgIcon>
     </SvgIcon>
   ),
   ),
+  caretSort: (props = {}) => (
+    <SvgIcon
+      width="15"
+      height="15"
+      viewBox="0 0 15 15"
+      fill="none"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path
+        d="M4.93179 5.43179C4.75605 5.60753 4.75605 5.89245 4.93179 6.06819C5.10753 6.24392 5.39245 6.24392 5.56819 6.06819L7.49999 4.13638L9.43179 6.06819C9.60753 6.24392 9.89245 6.24392 10.0682 6.06819C10.2439 5.89245 10.2439 5.60753 10.0682 5.43179L7.81819 3.18179C7.73379 3.0974 7.61933 3.04999 7.49999 3.04999C7.38064 3.04999 7.26618 3.0974 7.18179 3.18179L4.93179 5.43179ZM10.0682 9.56819C10.2439 9.39245 10.2439 9.10753 10.0682 8.93179C9.89245 8.75606 9.60753 8.75606 9.43179 8.93179L7.49999 10.8636L5.56819 8.93179C5.39245 8.75606 5.10753 8.75606 4.93179 8.93179C4.75605 9.10753 4.75605 9.39245 4.93179 9.56819L7.18179 11.8182C7.35753 11.9939 7.64245 11.9939 7.81819 11.8182L10.0682 9.56819Z"
+        fill="currentColor"
+        fillRule="evenodd"
+        clipRule="evenodd"
+      ></path>
+    </SvgIcon>
+  ),
 };
 };
 
 
 export default icons;
 export default icons;

+ 2 - 3
client/src/components/icons/Types.ts

@@ -10,7 +10,6 @@ export type IconsType =
   | 'copy'
   | 'copy'
   | 'error'
   | 'error'
   | 'clear'
   | 'clear'
-  | 'app'
   | 'navOverview'
   | 'navOverview'
   | 'navCollection'
   | 'navCollection'
   | 'navConsole'
   | 'navConsole'
@@ -60,7 +59,7 @@ export type IconsType =
   | 'day'
   | 'day'
   | 'night'
   | 'night'
   | 'img'
   | 'img'
-  | 'fileplus'
   | 'file'
   | 'file'
   | 'eye'
   | 'eye'
-  | 'newWindow';
+  | 'newWindow'
+  | 'caretSort';

+ 29 - 16
client/src/components/layout/Header.tsx

@@ -111,7 +111,7 @@ const Header: FC = () => {
       elevation={0}
       elevation={0}
       sx={{
       sx={{
         borderBottom: theme => `1px solid ${theme.palette.divider}`,
         borderBottom: theme => `1px solid ${theme.palette.divider}`,
-        height: 48,
+        height: 45,
         justifyContent: 'center',
         justifyContent: 'center',
         backgroundColor: theme =>
         backgroundColor: theme =>
           mode === 'dark' ? theme.palette.background.default : '#fff',
           mode === 'dark' ? theme.palette.background.default : '#fff',
@@ -120,7 +120,7 @@ const Header: FC = () => {
       <Toolbar
       <Toolbar
         disableGutters
         disableGutters
         sx={{
         sx={{
-          minHeight: 48,
+          minHeight: 45,
           px: 2,
           px: 2,
           display: 'flex',
           display: 'flex',
           justifyContent: 'space-between',
           justifyContent: 'space-between',
@@ -137,14 +137,21 @@ const Header: FC = () => {
             </IconButton>
             </IconButton>
           )}
           )}
           {navInfo.showDatabaseSelector && (
           {navInfo.showDatabaseSelector && (
-            <Breadcrumbs aria-label="breadcrumb" sx={{ mx: 1 }}>
-              <Typography
-                sx={{ cursor: 'pointer', fontWeight: 500 }}
-                color="primary"
+            <Breadcrumbs aria-label="breadcrumb">
+              <Box
+                sx={{
+                  display: 'flex',
+                  alignItems: 'center',
+                  cursor: 'pointer',
+                  color: 'primary.main',
+                }}
                 onClick={handleDbClick}
                 onClick={handleDbClick}
               >
               >
-                {database}
-              </Typography>
+                <Typography sx={{ fontSize: 15, fontWeight: 500 }}>
+                  {database}
+                </Typography>
+                <icons.caretSort sx={{ fontSize: 16, ml: 0.5 }} />
+              </Box>
               <Menu
               <Menu
                 anchorEl={dbAnchorEl}
                 anchorEl={dbAnchorEl}
                 open={Boolean(dbAnchorEl)}
                 open={Boolean(dbAnchorEl)}
@@ -171,16 +178,17 @@ const Header: FC = () => {
               </Menu>
               </Menu>
             </Breadcrumbs>
             </Breadcrumbs>
           )}
           )}
-          <Typography variant="h5" color="text.primary">
+          <Typography
+            color="text.primary"
+            sx={{ fontSize: 15, fontWeight: 500, ml: 0 }}
+          >
             {navInfo.navTitle}
             {navInfo.navTitle}
           </Typography>
           </Typography>
           {navInfo.extra && (
           {navInfo.extra && (
             <Box
             <Box
               sx={{
               sx={{
-                ml: 0.5,
                 display: 'flex',
                 display: 'flex',
                 alignItems: 'center',
                 alignItems: 'center',
-                '& svg': { fontSize: 15, color: 'primary.main' },
               }}
               }}
             >
             >
               {navInfo.extra}
               {navInfo.extra}
@@ -188,20 +196,25 @@ const Header: FC = () => {
           )}
           )}
         </Stack>
         </Stack>
         <Stack direction="row" alignItems="center" spacing={1}>
         <Stack direction="row" alignItems="center" spacing={1}>
-          <IconButton onClick={toggleColorMode} color="inherit" size="small">
+          <IconButton
+            onClick={toggleColorMode}
+            color="inherit"
+            size="small"
+            sx={{ '& svg': { fontSize: 14 } }}
+          >
             {mode === 'dark' ? <icons.night /> : <icons.day />}
             {mode === 'dark' ? <icons.night /> : <icons.day />}
           </IconButton>
           </IconButton>
           <Box sx={{ display: 'flex', alignItems: 'center', mr: 2 }}>
           <Box sx={{ display: 'flex', alignItems: 'center', mr: 2 }}>
             <Box sx={{ mr: 2 }}>
             <Box sx={{ mr: 2 }}>
               <Typography
               <Typography
                 className="address"
                 className="address"
-                sx={{ fontSize: 12, lineHeight: 1.3 }}
+                sx={{ fontSize: 11, lineHeight: 1.3 }}
               >
               >
                 {address}
                 {address}
               </Typography>
               </Typography>
               <Typography
               <Typography
                 className="status"
                 className="status"
-                sx={{ fontSize: 12, lineHeight: 1.3, color: '#1ba954' }}
+                sx={{ fontSize: 11, lineHeight: 1.3, color: '#1ba954' }}
               >
               >
                 {commonTrans('status.running')}
                 {commonTrans('status.running')}
               </Typography>
               </Typography>
@@ -212,7 +225,7 @@ const Header: FC = () => {
                   <IconButton
                   <IconButton
                     size="small"
                     size="small"
                     onClick={handleUserMenuClick}
                     onClick={handleUserMenuClick}
-                    sx={{ color: 'primary.main' }}
+                    sx={{ color: 'primary.main', '& svg': { fontSize: 16 } }}
                   >
                   >
                     <Avatar />
                     <Avatar />
                   </IconButton>
                   </IconButton>
@@ -239,7 +252,7 @@ const Header: FC = () => {
             <Tooltip title={'disconnect'}>
             <Tooltip title={'disconnect'}>
               <IconButton
               <IconButton
                 size="small"
                 size="small"
-                sx={{ color: 'primary.main' }}
+                sx={{ color: 'primary.main', '& svg': { fontSize: 16 } }}
                 onClick={handleLogout}
                 onClick={handleLogout}
               >
               >
                 <LogoutIcon />
                 <LogoutIcon />

+ 44 - 20
client/src/components/menu/NavMenu.tsx

@@ -12,7 +12,6 @@ import { dataContext } from '@/context';
 
 
 const NavMenu: FC<NavMenuType> = props => {
 const NavMenu: FC<NavMenuType> = props => {
   const { data, defaultActive = '', versionInfo } = props;
   const { data, defaultActive = '', versionInfo } = props;
-  // Styles moved inline using sx prop
   const [active, setActive] = useState<string>(defaultActive);
   const [active, setActive] = useState<string>(defaultActive);
 
 
   const { databases } = useContext(dataContext);
   const { databases } = useContext(dataContext);
@@ -47,29 +46,55 @@ const NavMenu: FC<NavMenuType> = props => {
               disabled={disabled}
               disabled={disabled}
               sx={{
               sx={{
                 width: 'initial',
                 width: 'initial',
+                minWidth: 'auto',
+                padding: 0,
                 borderRadius: 1,
                 borderRadius: 1,
                 m: 0.5,
                 m: 0.5,
-                mb: 1.5,
+                mb: 1,
                 cursor: 'pointer',
                 cursor: 'pointer',
-                '&:hover': {
-                  backgroundColor: theme => theme.palette.primary.main,
-                  color: '#fff',
-                  '& .icon': { color: '#fff' },
+                display: 'flex',
+                justifyContent: 'center',
+                '& .itemIcon': {
+                  minWidth: 'auto',
+                  margin: 0,
+                  display: 'flex',
+                  justifyContent: 'center',
+                  alignItems: 'center',
+                  width: 32,
+                  height: 32,
+                  borderRadius: 1,
+                  transition: 'all 0.2s ease',
+                  '& .icon': {
+                    transform: 'scale(0.8)',
+                    color: theme => theme.palette.text.primary,
+                  },
                 },
                 },
-                '&.attu .icon': {
-                  color: theme => theme.palette.primary.main,
-                  '&:hover': { color: '#fff' },
-                  '&.active:hover': { color: '#fff' },
+                '&:hover': {
+                  '& .itemIcon': {
+                    backgroundColor: theme => theme.palette.primary.main,
+                    '& .icon': {
+                      color: '#fff',
+                    },
+                  },
                 },
                 },
-                '& .itemIcon': {
-                  marginLeft: -1,
-                  minWidth: 24,
+                '&.attu .itemIcon': {
+                  '& .icon': {
+                    color: theme => theme.palette.primary.main,
+                  },
+                  '&:hover': {
+                    backgroundColor: theme => theme.palette.primary.main,
+                    '& .icon': {
+                      color: '#fff',
+                    },
+                  },
                 },
                 },
                 '&.active': {
                 '&.active': {
-                  borderRadius: 1,
-                  backgroundColor: theme => theme.palette.primary.main,
-                  color: '#fff',
-                  '& .icon path': { fill: '#fff' },
+                  '& .itemIcon': {
+                    backgroundColor: theme => theme.palette.primary.main,
+                    '& .icon': {
+                      color: '#fff',
+                    },
+                  },
                 },
                 },
               }}
               }}
               className={clsx({
               className={clsx({
@@ -102,12 +127,11 @@ const NavMenu: FC<NavMenuType> = props => {
     <List
     <List
       component="nav"
       component="nav"
       sx={{
       sx={{
-        boxShadow: '0px 6px 30px rgba(0, 0, 0, 0.1)',
         borderRight: theme => `1px solid ${theme.palette.divider}`,
         borderRight: theme => `1px solid ${theme.palette.divider}`,
-        width: 48,
+        width: 46,
         pt: 0,
         pt: 0,
         color: theme => theme.palette.text.primary,
         color: theme => theme.palette.text.primary,
-        backgroundColor: theme => theme.palette.background.default,
+        backgroundColor: theme => theme.palette.background.paper,
         position: 'relative',
         position: 'relative',
       }}
       }}
     >
     >

+ 1 - 1
client/src/components/status/Status.tsx

@@ -3,7 +3,7 @@ import StatusIcon from '@/components/status/StatusIcon';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import Typography from '@mui/material/Typography';
 import Typography from '@mui/material/Typography';
 import { useTheme } from '@mui/material/styles';
 import { useTheme } from '@mui/material/styles';
-import { styled, keyframes } from '@mui/system';
+import { styled } from '@mui/system';
 import { LOADING_STATE } from '@/consts';
 import { LOADING_STATE } from '@/consts';
 import { LoadingType } from '@/components/status/StatusIcon';
 import { LoadingType } from '@/components/status/StatusIcon';
 
 

+ 2 - 1
client/src/components/status/Types.ts

@@ -1,13 +1,14 @@
 import { LOADING_STATE } from '@/consts';
 import { LOADING_STATE } from '@/consts';
 import type { CollectionObject } from '@server/types';
 import type { CollectionObject } from '@server/types';
+import { SxProps, Theme } from '@mui/material';
 
 
 export type StatusActionType = {
 export type StatusActionType = {
   status: LOADING_STATE;
   status: LOADING_STATE;
   percentage?: string | number;
   percentage?: string | number;
-  action?: Function;
   onIndexCreate?: Function;
   onIndexCreate?: Function;
   showExtraAction?: boolean;
   showExtraAction?: boolean;
   showLoadButton?: boolean;
   showLoadButton?: boolean;
   collection: CollectionObject;
   collection: CollectionObject;
   createIndexElement?: React.ReactNode;
   createIndexElement?: React.ReactNode;
+  sx?: SxProps<Theme>;
 };
 };

+ 3 - 8
client/src/context/Root.tsx

@@ -30,12 +30,7 @@ const DefaultDrawerConfigs: DrawerType = {
 };
 };
 
 
 export const rootContext = React.createContext<RootContextType>({
 export const rootContext = React.createContext<RootContextType>({
-  openSnackBar: (
-    message,
-    type = 'success',
-    autoHideDuration,
-    position = { vertical: 'top', horizontal: 'right' }
-  ) => {},
+  openSnackBar: (message, type = 'success', autoHideDuration, position) => {},
   dialog: DefaultDialogConfigs,
   dialog: DefaultDialogConfigs,
   dialog2: DefaultDialogConfigs,
   dialog2: DefaultDialogConfigs,
   setDialog: params => {},
   setDialog: params => {},
@@ -80,9 +75,9 @@ export const RootProvider = (props: { children: React.ReactNode }) => {
         open: false,
         open: false,
         type: 'success',
         type: 'success',
         message: '',
         message: '',
+        autoHideDuration: 30000,
         vertical: 'top',
         vertical: 'top',
-        horizontal: 'right',
-        autoHideDuration: 3000,
+        horizontal: 'center',
       });
       });
       // hide dialog
       // hide dialog
       setDialog({
       setDialog({

+ 2 - 2
client/src/context/hooks/useSnackBar.ts

@@ -6,7 +6,7 @@ const defaultSnackBar: SnackBarType = {
   type: 'success',
   type: 'success',
   message: '',
   message: '',
   vertical: 'top',
   vertical: 'top',
-  horizontal: 'right',
+  horizontal: 'center',
   autoHideDuration: 1000,
   autoHideDuration: 1000,
 };
 };
 
 
@@ -18,7 +18,7 @@ export function useSnackBar(initial: SnackBarType = defaultSnackBar) {
       message = '',
       message = '',
       type = 'success',
       type = 'success',
       autoHideDuration: number | null | undefined = 5000,
       autoHideDuration: number | null | undefined = 5000,
-      position = { vertical: 'top', horizontal: 'right' }
+      position = { vertical: 'top', horizontal: 'center' }
     ) => {
     ) => {
       setSnackBar({
       setSnackBar({
         open: true,
         open: true,

+ 1 - 1
client/src/i18n/cn/button.ts

@@ -46,7 +46,7 @@ const btnTrans = {
   downloadChart: '下载图表',
   downloadChart: '下载图表',
   editDefaultValue: '编辑默认值',
   editDefaultValue: '编辑默认值',
   viewData: '查看数据',
   viewData: '查看数据',
-  mmapSetting: '内存映射 (MMap) 设置',
+  mmapSetting: '内存映射 (mmap) 设置',
   importFromJSON: '从 JSON 导入',
   importFromJSON: '从 JSON 导入',
 
 
   // tips
   // tips

+ 9 - 7
client/src/i18n/cn/collection.ts

@@ -11,10 +11,10 @@ const collectionTrans = {
   aliasTooltip: '请选择一个 Collection 创建别名',
   aliasTooltip: '请选择一个 Collection 创建别名',
   collection: 'Collection',
   collection: 'Collection',
   entities: 'Entities',
   entities: 'Entities',
-  mmapEnabled: '内存映射 (MMap)',
-  mmapSettings: 'MMap 设置',
-  collectionMMapSettingsLabel: '全局原始数据 MMap 设置',
-  rawData: '全局内存映射 (MMap) 的原始数据配置',
+  mmapEnabled: '内存映射开启 (mmap)',
+  mmapSettings: 'mmap 设置',
+  collectionMMapSettingsLabel: 'Collection 级别原始数据 mmap 设置',
+  rawData: '原始数据',
   functions: 'Functions',
   functions: 'Functions',
 
 
   // table
   // table
@@ -26,6 +26,7 @@ const collectionTrans = {
   desc: '描述',
   desc: '描述',
   createdTime: '创建时间',
   createdTime: '创建时间',
   maxLength: '最大长度',
   maxLength: '最大长度',
+  maxCapacity: '最大容量',
   dynamicSchema: '动态 Schema',
   dynamicSchema: '动态 Schema',
   function: 'Function',
   function: 'Function',
   functionInput: 'Function 输入',
   functionInput: 'Function 输入',
@@ -83,7 +84,8 @@ const collectionTrans = {
   loadCollectionAfterCreateTooltip:
   loadCollectionAfterCreateTooltip:
     'Attu 将使用 AUTOINDEX 为所有字段创建 Index,然后加载 Collection。',
     'Attu 将使用 AUTOINDEX 为所有字段创建 Index,然后加载 Collection。',
   addBm25Function: '添加 BM25 Function',
   addBm25Function: '添加 BM25 Function',
-  bm25NoVarcharAndSparse: '要创建 BM25 Function,请至少添加一个 VarChar 字段和一个 SparseFloatVector 字段。',
+  bm25NoVarcharAndSparse:
+    '要创建 BM25 Function,请至少添加一个 VarChar 字段和一个 SparseFloatVector 字段。',
   bm25NoVarchar: '要创建 BM25 Function,请至少添加一个 VarChar 字段。',
   bm25NoVarchar: '要创建 BM25 Function,请至少添加一个 VarChar 字段。',
   bm25NoSparse: '要创建 BM25 Function,请至少添加一个 SparseFloatVector 字段。',
   bm25NoSparse: '要创建 BM25 Function,请至少添加一个 SparseFloatVector 字段。',
   bm25InputVarChar: '输入 VarChar 字段',
   bm25InputVarChar: '输入 VarChar 字段',
@@ -159,7 +161,7 @@ const collectionTrans = {
     '确保在同一会话中所有数据写入可以立即在读取中感知。',
     '确保在同一会话中所有数据写入可以立即在读取中感知。',
   consistencyEventuallyTooltip:
   consistencyEventuallyTooltip:
     '不保证读写的顺序,副本最终会在没有进一步写操作的情况下收敛到相同的状态。',
     '不保证读写的顺序,副本最终会在没有进一步写操作的情况下收敛到相同的状态。',
-  noVectorIndexTooltip: '请保证所有向量列都有 Index。',
+  noVectorIndexTooltip: '请保证所有向量列都有索引。',
   mmapTooltip: `内存映射文件允许将原始数据和 Index 文件直接映射到内存中。此功能提高了内存效率,尤其是在可用内存稀缺但无法完全加载数据的情况下。`,
   mmapTooltip: `内存映射文件允许将原始数据和 Index 文件直接映射到内存中。此功能提高了内存效率,尤其是在可用内存稀缺但无法完全加载数据的情况下。`,
   mmapFieldSettingDisabledTooltip: `此设置已禁用,因为 Collection 级别的 mmap 配置覆盖了字段级别的设置。`,
   mmapFieldSettingDisabledTooltip: `此设置已禁用,因为 Collection 级别的 mmap 配置覆盖了字段级别的设置。`,
   mmapCollectionNotReleasedTooltip: `Collection 没有释放,无法更新 mmap 配置。`,
   mmapCollectionNotReleasedTooltip: `Collection 没有释放,无法更新 mmap 配置。`,
@@ -167,7 +169,7 @@ const collectionTrans = {
   clickToLoad: '点击加载 Collection',
   clickToLoad: '点击加载 Collection',
   clickToRelease: '点击释放 Collection',
   clickToRelease: '点击释放 Collection',
   clickToSearch: '点击执行向量搜索',
   clickToSearch: '点击执行向量搜索',
-  clickToCreateVectorIndex: '点击创建向量 Index',
+  clickToCreateVectorIndex: '点击创建向量索引',
   collectionIsLoading: 'Collection 正在加载...',
   collectionIsLoading: 'Collection 正在加载...',
 };
 };
 
 

+ 2 - 1
client/src/i18n/cn/common.ts

@@ -23,10 +23,11 @@ const commonTrans = {
   status: {
   status: {
     loaded: '已加载',
     loaded: '已加载',
     unloaded: '未加载',
     unloaded: '未加载',
+    readyToLoad: '可加载',
     error: '错误',
     error: '错误',
     running: '运行中',
     running: '运行中',
     loading: '正在加载',
     loading: '正在加载',
-    noVectorIndex: '向量 Index 不存在',
+    noVectorIndex: '向量索引不存在',
   },
   },
   grid: {
   grid: {
     action: '操作',
     action: '操作',

+ 1 - 1
client/src/i18n/cn/dialog.ts

@@ -14,7 +14,7 @@ const dialogTrans = {
   editEntityTitle: `编辑 Entity`,
   editEntityTitle: `编辑 Entity`,
   modifyReplicaTitle: `修改 {{type}} 的副本`,
   modifyReplicaTitle: `修改 {{type}} 的副本`,
   editAnalyzerTitle: `编辑分析器`,
   editAnalyzerTitle: `编辑分析器`,
-  manageMmapTitle: `管理 {{type}} 的内存映射 (MMap) 设置`,
+  manageMmapTitle: `管理 {{type}} 的内存映射 (mmap) 设置`,
 
 
   loadContent: `您正在尝试加载带有数据的 {{type}}。只有已加载的 {{type}} 可以被搜索。`,
   loadContent: `您正在尝试加载带有数据的 {{type}}。只有已加载的 {{type}} 可以被搜索。`,
   releaseContent: `您正在尝试释放带有数据的 {{type}}。请注意,数据将不再可用于搜索。`,
   releaseContent: `您正在尝试释放带有数据的 {{type}}。请注意,数据将不再可用于搜索。`,

+ 17 - 18
client/src/i18n/en/button.ts

@@ -46,30 +46,29 @@ const btnTrans = {
   downloadChart: 'Download Chart',
   downloadChart: 'Download Chart',
   EditDefaultValue: 'Edit Default Value',
   EditDefaultValue: 'Edit Default Value',
   viewData: 'View Data',
   viewData: 'View Data',
-  mmapSetting: 'MMap Settings',
+  mmapSetting: 'Mmap Settings',
   importFromJSON: 'Import from JSON',
   importFromJSON: 'Import from JSON',
 
 
   // tips
   // tips
-  loadColTooltip: 'Load Collection',
-  releaseColTooltip: 'Release Collection',
-  importFileTooltip: 'Import JSON or CSV file',
-  importSampleDataTooltip: 'Insert sample data into the current collection',
-  exportTooltip: 'Export selected data to csv',
-  copyJsonTooltip: 'Copy selected data as JSON format',
-  emptyTooltip: 'Empty all data in the collection',
+  loadColTooltip: 'Load collection into memory',
+  releaseColTooltip: 'Release collection from memory',
+  importFileTooltip: 'Import data from JSON or CSV file',
+  importSampleDataTooltip: 'Insert sample data into this collection',
+  exportTooltip: 'Export selected data to CSV file',
+  copyJsonTooltip: 'Copy selected data in JSON format',
+  emptyTooltip: 'Remove all data from this collection',
   deleteTooltip: 'Delete selected data',
   deleteTooltip: 'Delete selected data',
-  deleteColTooltip: 'Drop selected collection',
-  duplicateTooltip: 'Duplicate selected collection without data',
-  renameTooltip: 'Rename collection',
-  editEntityTooltip: 'Edit entity(JSON)',
-  viewDataTooltip: 'View data detail',
+  deleteColTooltip: 'Delete selected collection',
+  duplicateTooltip: 'Create a copy of this collection (without data)',
+  renameTooltip: 'Rename this collection',
+  editEntityTooltip: 'Edit entity in JSON format',
+  viewDataTooltip: 'View detailed data information',
 
 
   // disable tooltip
   // disable tooltip
-  downloadDisabledTooltip: 'Please select data before exporting',
-  deleteDisableTooltip: 'Please select at least one item to delete.',
-  editEntityDisabledTooltip: 'Only one entity can be edited at a time.',
-  editEntityDisabledTooltipAutoId:
-    'The auto-generated ID entity cannot be edited.',
+  downloadDisabledTooltip: 'Please select data to export',
+  deleteDisableTooltip: 'Please select at least one item to delete',
+  editEntityDisabledTooltip: 'You can only edit one entity at a time',
+  editEntityDisabledTooltipAutoId: 'Auto-generated ID entities cannot be edited',
 };
 };
 
 
 export default btnTrans;
 export default btnTrans;

+ 4 - 3
client/src/i18n/en/collection.ts

@@ -11,9 +11,9 @@ const collectionTrans = {
   aliasTooltip: 'Please select one collection to create alias',
   aliasTooltip: 'Please select one collection to create alias',
   collection: 'Collection',
   collection: 'Collection',
   entities: 'entities',
   entities: 'entities',
-  mmapEnabled: 'MMap-Enabled',
-  mmapSettings: 'MMap Settings',
-  collectionMMapSettingsLabel: 'Collection Raw Data MMap Settings',
+  mmapEnabled: 'mmap enabled',
+  mmapSettings: 'Mmap Settings',
+  collectionMMapSettingsLabel: 'Collection level raw data mmap settings',
   rawData: 'Raw Data',
   rawData: 'Raw Data',
   functions: 'Functions',
   functions: 'Functions',
 
 
@@ -26,6 +26,7 @@ const collectionTrans = {
   desc: 'Description',
   desc: 'Description',
   createdTime: 'Created Time',
   createdTime: 'Created Time',
   maxLength: 'Max Length',
   maxLength: 'Max Length',
+  maxCapacity: 'Max Capacity',
   dynamicSchema: 'Dynamic Schema',
   dynamicSchema: 'Dynamic Schema',
   function: 'Function',
   function: 'Function',
   functionInput: 'Input',
   functionInput: 'Input',

+ 3 - 4
client/src/i18n/en/common.ts

@@ -1,5 +1,3 @@
-import { use } from 'i18next';
-
 const commonTrans = {
 const commonTrans = {
   attu: {
   attu: {
     admin: 'Attu',
     admin: 'Attu',
@@ -24,12 +22,13 @@ const commonTrans = {
     version: 'Version',
     version: 'Version',
   },
   },
   status: {
   status: {
-    loaded: 'loaded',
+    loaded: 'Loaded',
     unloaded: 'unloaded',
     unloaded: 'unloaded',
+    readyToLoad: 'Ready to load',
     error: 'error',
     error: 'error',
     running: 'running',
     running: 'running',
     loading: 'is loaded',
     loading: 'is loaded',
-    noVectorIndex: 'No Vector Index',
+    noVectorIndex: 'No vector index',
   },
   },
   grid: {
   grid: {
     action: 'action',
     action: 'action',

+ 1 - 1
client/src/i18n/en/dialog.ts

@@ -14,7 +14,7 @@ const dialogTrans = {
   editEntityTitle: `Edit Entity(JSON)`,
   editEntityTitle: `Edit Entity(JSON)`,
   editAnalyzerTitle: `Edit Analyzer`,
   editAnalyzerTitle: `Edit Analyzer`,
   modifyReplicaTitle: `Modify replica for {{type}}`,
   modifyReplicaTitle: `Modify replica for {{type}}`,
-  manageMmapTitle: `Manage MMap settings for {{type}}`,
+  manageMmapTitle: `Manage mmap settings for {{type}}`,
 
 
   loadContent: `You are trying to load a {{type}} with data. Only loaded {{type}} can be searched.`,
   loadContent: `You are trying to load a {{type}} with data. Only loaded {{type}} can be searched.`,
   releaseContent: `You are trying to release {{type}} with data. Please be aware that the data will no longer be available for search.`,
   releaseContent: `You are trying to release {{type}} with data. Please be aware that the data will no longer be available for search.`,

+ 13 - 13
client/src/i18n/en/success.ts

@@ -1,17 +1,17 @@
 const successTrans = {
 const successTrans = {
-  connect: 'Connection to milvus successful',
-  create: `{{name}} has been created.`,
-  load: `{{name}} is loading.`,
-  delete: `{{name}} successfully dropped.`,
-  release: `{{name}} has been released.`,
-  update: `{{name}} has been updated.`,
-  rename: `{{name}} has been renamed.`,
-  duplicate: `{{name}} has been duplicated.`,
-  empty: `Emptying data for {{name}} has started.`,
-  reset: `{{name}} has been reset.`,
-  modifyReplica: `Replica number for {{name}} has been modified.`,
-  passwordChanged: `Password updated successfully`,
-  updateMmap: `Mmap settings for {{name}} have been updated.`,
+  connect: 'Successfully connected to Milvus',
+  create: `{{name}} has been created successfully`,
+  load: `{{name}} is now loading`,
+  delete: `{{name}} has been successfully deleted`,
+  release: `{{name}} has been released successfully`,
+  update: `{{name}} has been updated successfully`,
+  rename: `{{name}} has been renamed successfully`,
+  duplicate: `{{name}} has been duplicated successfully`,
+  empty: `Data clearing process for {{name}} has started`,
+  reset: `{{name}} has been reset successfully`,
+  modifyReplica: `Replica count for {{name}} has been updated`,
+  passwordChanged: `Password has been updated successfully`,
+  updateMmap: `Memory mapping settings for {{name}} have been updated successfully`,
 };
 };
 
 
 export default successTrans;
 export default successTrans;

+ 145 - 61
client/src/pages/connect/AuthForm.tsx

@@ -249,20 +249,30 @@ export const AuthForm = () => {
           flexDirection: 'column',
           flexDirection: 'column',
           padding: (theme: Theme) => theme.spacing(0, 3),
           padding: (theme: Theme) => theme.spacing(0, 3),
           position: 'relative',
           position: 'relative',
+          height: '100%',
         }}
         }}
       >
       >
         <Box
         <Box
           sx={{
           sx={{
             textAlign: 'left',
             textAlign: 'left',
             alignSelf: 'flex-start',
             alignSelf: 'flex-start',
-            padding: (theme: Theme) => theme.spacing(3, 0),
+            padding: (theme: Theme) => theme.spacing(2, 0, 1.5),
             '& svg': {
             '& svg': {
-              fontSize: 15,
+              fontSize: 16,
               marginLeft: (theme: Theme) => theme.spacing(0.5),
               marginLeft: (theme: Theme) => theme.spacing(0.5),
+              color: 'primary.main',
             },
             },
           }}
           }}
         >
         >
-          <Typography variant="h4" component="h4">
+          <Typography
+            variant="h4"
+            component="h4"
+            sx={{
+              fontSize: 20,
+              fontWeight: 600,
+              color: 'text.primary',
+            }}
+          >
             {commonTrans('attu.connectTitle')}
             {commonTrans('attu.connectTitle')}
             <CustomToolTip title={commonTrans('attu.connectionTip')}>
             <CustomToolTip title={commonTrans('attu.connectionTip')}>
               <Icons.info />
               <Icons.info />
@@ -280,10 +290,19 @@ export const AuthForm = () => {
               handleInputChange('address', String(val)),
               handleInputChange('address', String(val)),
             variant: 'filled',
             variant: 'filled',
             sx: {
             sx: {
-              margin: (theme: Theme) => theme.spacing(0.5, 0, 0),
+              margin: (theme: Theme) => theme.spacing(0.5, 0),
               '& .MuiFilledInput-adornedEnd': {
               '& .MuiFilledInput-adornedEnd': {
                 paddingRight: 0,
                 paddingRight: 0,
               },
               },
+              '& .MuiFilledInput-root': {
+                backgroundColor: 'background.default',
+                '&:hover': {
+                  backgroundColor: 'action.hover',
+                },
+                '&.Mui-focused': {
+                  backgroundColor: 'background.default',
+                },
+              },
             },
             },
             placeholder: commonTrans('attu.address'),
             placeholder: commonTrans('attu.address'),
             fullWidth: true,
             fullWidth: true,
@@ -298,6 +317,7 @@ export const AuthForm = () => {
                     '& button': {
                     '& button': {
                       width: 36,
                       width: 36,
                       height: 36,
                       height: 36,
+                      color: 'primary.main',
                     },
                     },
                   }}
                   }}
                   onClick={handleMenuClick}
                   onClick={handleMenuClick}
@@ -330,9 +350,15 @@ export const AuthForm = () => {
             onChange: (value: string) => handleInputChange('database', value),
             onChange: (value: string) => handleInputChange('database', value),
             variant: 'filled',
             variant: 'filled',
             sx: {
             sx: {
-              margin: (theme: Theme) => theme.spacing(0.5, 0, 0),
-              '& .MuiFilledInput-adornedEnd': {
-                paddingRight: 0,
+              margin: (theme: Theme) => theme.spacing(0.5, 0),
+              '& .MuiFilledInput-root': {
+                backgroundColor: 'background.default',
+                '&:hover': {
+                  backgroundColor: 'action.hover',
+                },
+                '&.Mui-focused': {
+                  backgroundColor: 'background.default',
+                },
               },
               },
             },
             },
             placeholder: dbTrans('database'),
             placeholder: dbTrans('database'),
@@ -350,6 +376,7 @@ export const AuthForm = () => {
             display: 'flex',
             display: 'flex',
             width: '100%',
             width: '100%',
             justifyContent: 'flex-start',
             justifyContent: 'flex-start',
+            marginTop: (theme: Theme) => theme.spacing(1),
           }}
           }}
         >
         >
           <CustomRadio
           <CustomRadio
@@ -370,9 +397,15 @@ export const AuthForm = () => {
                 onChange: (val: string) => handleInputChange('token', val),
                 onChange: (val: string) => handleInputChange('token', val),
                 variant: 'filled',
                 variant: 'filled',
                 sx: {
                 sx: {
-                  margin: (theme: Theme) => theme.spacing(0.5, 0, 0),
-                  '& .MuiFilledInput-adornedEnd': {
-                    paddingRight: 0,
+                  margin: (theme: Theme) => theme.spacing(0.5, 0),
+                  '& .MuiFilledInput-root': {
+                    backgroundColor: 'background.default',
+                    '&:hover': {
+                      backgroundColor: 'action.hover',
+                    },
+                    '&.Mui-focused': {
+                      backgroundColor: 'background.default',
+                    },
                   },
                   },
                 },
                 },
                 placeholder: commonTrans('attu.token'),
                 placeholder: commonTrans('attu.token'),
@@ -393,9 +426,15 @@ export const AuthForm = () => {
                   handleInputChange('username', value),
                   handleInputChange('username', value),
                 variant: 'filled',
                 variant: 'filled',
                 sx: {
                 sx: {
-                  margin: (theme: Theme) => theme.spacing(0.5, 0, 0),
-                  '& .MuiFilledInput-adornedEnd': {
-                    paddingRight: 0,
+                  margin: (theme: Theme) => theme.spacing(0.5, 0),
+                  '& .MuiFilledInput-root': {
+                    backgroundColor: 'background.default',
+                    '&:hover': {
+                      backgroundColor: 'action.hover',
+                    },
+                    '&.Mui-focused': {
+                      backgroundColor: 'background.default',
+                    },
                   },
                   },
                 },
                 },
                 placeholder: commonTrans('attu.username'),
                 placeholder: commonTrans('attu.username'),
@@ -416,9 +455,15 @@ export const AuthForm = () => {
                   handleInputChange('password', value),
                   handleInputChange('password', value),
                 variant: 'filled',
                 variant: 'filled',
                 sx: {
                 sx: {
-                  margin: (theme: Theme) => theme.spacing(0.5, 0, 0),
-                  '& .MuiFilledInput-adornedEnd': {
-                    paddingRight: 0,
+                  margin: (theme: Theme) => theme.spacing(0.5, 0),
+                  '& .MuiFilledInput-root': {
+                    backgroundColor: 'background.default',
+                    '&:hover': {
+                      backgroundColor: 'action.hover',
+                    },
+                    '&.Mui-focused': {
+                      backgroundColor: 'background.default',
+                    },
                   },
                   },
                 },
                 },
                 placeholder: commonTrans('attu.password'),
                 placeholder: commonTrans('attu.password'),
@@ -433,57 +478,96 @@ export const AuthForm = () => {
           </>
           </>
         )}
         )}
 
 
-        {/* SSL toggle */}
         <Box
         <Box
           sx={{
           sx={{
-            display: 'flex',
-            width: '100%',
-            justifyContent: 'flex-start',
+            marginTop: 'auto',
+            padding: (theme: Theme) => theme.spacing(2, 0),
           }}
           }}
         >
         >
-          <FormControlLabel
-            control={
-              <Checkbox
-                checked={authReq.ssl}
-                onChange={e => handleInputChange('ssl', e.target.checked)}
+          <Box
+            sx={{
+              display: 'flex',
+              alignItems: 'center',
+              gap: (theme: Theme) => theme.spacing(2),
+            }}
+          >
+            <CustomButton 
+              type="submit" 
+              variant="contained" 
+              disabled={btnDisabled}
+              sx={{
+                height: 36,
+                fontSize: 14,
+                fontWeight: 500,
+                flex: 1,
+              }}
+            >
+              {btnTrans(isConnecting ? 'connecting' : 'connect')}
+            </CustomButton>
+
+            <Box
+              sx={{
+                display: 'flex',
+                alignItems: 'center',
+                gap: (theme: Theme) => theme.spacing(1),
+                borderLeft: (theme: Theme) => `1px solid ${theme.palette.divider}`,
+                paddingLeft: (theme: Theme) => theme.spacing(2),
+              }}
+            >
+              <FormControlLabel
+                control={
+                  <Checkbox
+                    checked={authReq.ssl}
+                    onChange={e => handleInputChange('ssl', e.target.checked)}
+                    sx={{
+                      padding: '4px',
+                      '&.Mui-checked': {
+                        color: 'primary.main',
+                      },
+                    }}
+                  />
+                }
+                label={
+                  <Typography
+                    sx={{
+                      fontSize: 13,
+                      color: 'text.secondary',
+                    }}
+                  >
+                    {commonTrans('attu.ssl')}
+                  </Typography>
+                }
               />
               />
-            }
-            label={commonTrans('attu.ssl')}
-          />
-        </Box>
-
-        <CustomButton type="submit" variant="contained" disabled={btnDisabled}>
-          {btnTrans(isConnecting ? 'connecting' : 'connect')}
-        </CustomButton>
 
 
-        <Box
-          sx={{
-            display: 'flex',
-            alignItems: 'center',
-            marginTop: 4,
-            '& .MuiCheckbox-root': {
-              margin: 0,
-              padding: '8px 4px 8px 0',
-            },
-            '& span': {
-              cursor: 'pointer',
-              fontSize: 12,
-              fontStyle: 'italic',
-            },
-          }}
-        >
-          <label>
-            <Checkbox
-              size="small"
-              checked={authReq.checkHealth}
-              onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                handleInputChange('checkHealth', e.target.checked);
-              }}
-            />
-            <Typography component="span">
-              {commonTrans('attu.checkHealth')}
-            </Typography>
-          </label>
+              <FormControlLabel
+                control={
+                  <Checkbox
+                    size="small"
+                    checked={authReq.checkHealth}
+                    onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+                      handleInputChange('checkHealth', e.target.checked);
+                    }}
+                    sx={{
+                      padding: '4px',
+                      '&.Mui-checked': {
+                        color: 'primary.main',
+                      },
+                    }}
+                  />
+                }
+                label={
+                  <Typography
+                    sx={{
+                      fontSize: 13,
+                      color: 'text.secondary',
+                    }}
+                  >
+                    {commonTrans('attu.checkHealth')}
+                  </Typography>
+                }
+              />
+            </Box>
+          </Box>
         </Box>
         </Box>
       </Box>
       </Box>
 
 

+ 28 - 24
client/src/pages/connect/ConnectContainer.tsx

@@ -8,7 +8,6 @@ import { MilvusService } from '@/http';
 import Box from '@mui/material/Box';
 import Box from '@mui/material/Box';
 import type { Theme } from '@mui/material/styles';
 import type { Theme } from '@mui/material/styles';
 
 
-// used for user connect process
 const ConnectContainer = () => {
 const ConnectContainer = () => {
   const [version, setVersion] = useState('loading');
   const [version, setVersion] = useState('loading');
   const { t: commonTrans } = useTranslation();
   const { t: commonTrans } = useTranslation();
@@ -37,38 +36,36 @@ const ConnectContainer = () => {
           backgroundColor: 'background.default',
           backgroundColor: 'background.default',
           border: (theme: Theme) => `1px solid ${theme.palette.divider}`,
           border: (theme: Theme) => `1px solid ${theme.palette.divider}`,
           borderRadius: 2,
           borderRadius: 2,
-          boxShadow: '0px 6px 30px rgba(0, 0, 0, 0.1)',
-          minHeight: 644,
+          minHeight: 680,
         }}
         }}
       >
       >
         <Box
         <Box
           className="flex-center"
           className="flex-center"
           sx={{
           sx={{
-            width: 299,
+            width: 320,
             display: 'flex',
             display: 'flex',
             flexDirection: 'column',
             flexDirection: 'column',
-            padding: (theme: Theme) => theme.spacing(0, 3),
-            backgroundColor: 'background.default',
-            borderRadius: 2,
+            padding: (theme: Theme) => theme.spacing(4, 3),
+            backgroundColor: (theme: Theme) => theme.palette.mode === 'dark' ? theme.palette.background.default : theme.palette.neutral[50],
+            borderRadius: '12px 0 0 12px',
           }}
           }}
         >
         >
           <Icons.attu
           <Icons.attu
             sx={{
             sx={{
-              width: 64,
+              width: 72,
               height: 'auto',
               height: 'auto',
-              marginBottom: (theme: Theme) => theme.spacing(1),
+              marginBottom: (theme: Theme) => theme.spacing(2),
               display: 'block',
               display: 'block',
               color: 'primary.main',
               color: 'primary.main',
             }}
             }}
           />
           />
           <Typography
           <Typography
-            variant="body2"
+            variant="h5"
             sx={{
             sx={{
-              fontSize: 24,
-              fontWeight: 'bold',
-              color: 'text.primary',
+              fontWeight: 600,
+              color: (theme: Theme) => theme.palette.mode === 'dark' ? theme.palette.common.white : 'primary.contrastText',
               marginTop: (theme: Theme) => theme.spacing(2),
               marginTop: (theme: Theme) => theme.spacing(2),
-              height: 24,
+              height: 32,
             }}
             }}
           >
           >
             {commonTrans('attu.admin')}
             {commonTrans('attu.admin')}
@@ -78,9 +75,10 @@ const ConnectContainer = () => {
               component="sub"
               component="sub"
               sx={{
               sx={{
                 marginTop: (theme: Theme) => theme.spacing(1),
                 marginTop: (theme: Theme) => theme.spacing(1),
-                fontSize: 12,
-                color: 'text.secondary',
-                height: 12,
+                fontSize: 13,
+                color: (theme: Theme) => theme.palette.mode === 'dark' ? theme.palette.common.white : 'primary.contrastText',
+                opacity: 0.8,
+                height: 16,
               }}
               }}
             >
             >
               {commonTrans('attu.version')}: {version}
               {commonTrans('attu.version')}: {version}
@@ -89,15 +87,22 @@ const ConnectContainer = () => {
 
 
           <Box
           <Box
             sx={{
             sx={{
-              marginTop: (theme: Theme) => theme.spacing(4),
+              marginTop: (theme: Theme) => theme.spacing(6),
               display: 'flex',
               display: 'flex',
               flexDirection: 'column',
               flexDirection: 'column',
               alignItems: 'center',
               alignItems: 'center',
               justifyContent: 'center',
               justifyContent: 'center',
               width: '100%',
               width: '100%',
-              padding: (theme: Theme) => theme.spacing(2, 0),
+              gap: (theme: Theme) => theme.spacing(2),
               '& button': {
               '& button': {
-                borderColor: 'transparent',
+                borderColor: (theme: Theme) => theme.palette.mode === 'dark' ? theme.palette.common.white : 'primary.contrastText',
+                color: (theme: Theme) => theme.palette.mode === 'dark' ? theme.palette.common.white : 'primary.contrastText',
+                height: 40,
+                fontSize: 14,
+                '&:hover': {
+                  backgroundColor: 'primary.main',
+                  borderColor: 'primary.main',
+                },
               },
               },
             }}
             }}
           >
           >
@@ -138,10 +143,9 @@ const ConnectContainer = () => {
         </Box>
         </Box>
         <Box
         <Box
           sx={{
           sx={{
-            width: 481,
-            borderRadius: 2,
-            padding: (theme: Theme) => theme.spacing(5, 0),
-            boxShadow: '0px 6px 30px rgba(0, 0, 0, 0.1)',
+            width: 500,
+            borderRadius: '0 8px 8px 0',
+            padding: (theme: Theme) => theme.spacing(6, 0),
             backgroundColor: 'background.paper',
             backgroundColor: 'background.paper',
           }}
           }}
         >
         >

+ 7 - 7
client/src/pages/databases/Databases.tsx

@@ -18,7 +18,7 @@ const DEFAULT_TREE_WIDTH = 230;
 const PageWrapper = styled(Box)(({ theme }) => ({
 const PageWrapper = styled(Box)(({ theme }) => ({
   display: 'flex',
   display: 'flex',
   flexDirection: 'row',
   flexDirection: 'row',
-  padding: theme.spacing(2),
+  padding: theme.spacing(1.5),
   height: 'calc(100vh - 64px)',
   height: 'calc(100vh - 64px)',
   overflow: 'hidden',
   overflow: 'hidden',
   '&.dragging': {
   '&.dragging': {
@@ -38,10 +38,9 @@ const PageWrapper = styled(Box)(({ theme }) => ({
 }));
 }));
 
 
 const TreeSection = styled(Box)(({ theme }) => ({
 const TreeSection = styled(Box)(({ theme }) => ({
-  boxShadow: 'none',
   flexGrow: 0,
   flexGrow: 0,
   flexShrink: 0,
   flexShrink: 0,
-  height: '100%',
+  height: 'calc(100vh - 54px)',
   overflowY: 'auto',
   overflowY: 'auto',
   overflowX: 'hidden',
   overflowX: 'hidden',
   boxSizing: 'border-box',
   boxSizing: 'border-box',
@@ -69,10 +68,9 @@ const TabSection = styled(Box)(({ theme }) => ({
   flexGrow: 1,
   flexGrow: 1,
   flexShrink: 1,
   flexShrink: 1,
   overflow: 'hidden',
   overflow: 'hidden',
-  padding: theme.spacing(0, 2),
+  padding: theme.spacing(0, 1.5),
   border: `1px solid ${theme.palette.divider}`,
   border: `1px solid ${theme.palette.divider}`,
-  borderRadius: 8,
-  boxShadow: '0px 6px 30px rgba(0, 0, 0, 0.1)',
+  borderRadius: 4,
   height: '100%',
   height: '100%',
   display: 'flex',
   display: 'flex',
   flexDirection: 'column',
   flexDirection: 'column',
@@ -116,7 +114,9 @@ const Databases = () => {
       // set dragging false
       // set dragging false
       setIsDragging(false);
       setIsDragging(false);
       // highlight dragger alwasy if width === 1
       // highlight dragger alwasy if width === 1
-      draggerRef.current!.classList.toggle('tree-collapsed', treeWidth === 1);
+      if (draggerRef.current) {
+        draggerRef.current.classList.toggle('tree-collapsed', treeWidth === 1);
+      }
       document.removeEventListener('mousemove', handleMouseMove);
       document.removeEventListener('mousemove', handleMouseMove);
     };
     };
 
 

+ 1 - 1
client/src/pages/databases/StyledComponents.ts

@@ -4,7 +4,7 @@ import { Box } from '@mui/material';
 export const Root = styled(Box)(({ theme }) => ({
 export const Root = styled(Box)(({ theme }) => ({
   display: 'flex',
   display: 'flex',
   flexDirection: 'column',
   flexDirection: 'column',
-  height: 'calc(100% - 16px)',
+  height: 'calc(100%)',
 }));
 }));
 
 
 export const Toolbar = styled(Box)(({ theme }) => ({
 export const Toolbar = styled(Box)(({ theme }) => ({

+ 6 - 4
client/src/pages/databases/collections/Collections.tsx

@@ -318,7 +318,8 @@ const Collections = () => {
               to={`/databases/${database}/${collection_name}/overview`}
               to={`/databases/${database}/${collection_name}/overview`}
               style={{
               style={{
                 color: 'inherit',
                 color: 'inherit',
-                display: 'inline-block',
+                display: 'inline-flex',
+                alignItems: 'center',
                 wordBreak: 'break-all',
                 wordBreak: 'break-all',
                 whiteSpace: 'nowrap',
                 whiteSpace: 'nowrap',
                 width: 150,
                 width: 150,
@@ -354,11 +355,12 @@ const Collections = () => {
       label: collectionTrans('status'),
       label: collectionTrans('status'),
       formatter(v) {
       formatter(v) {
         return (
         return (
-          <Typography variant="body1">
+          <Typography variant="body1" component="div">
             <StatusAction
             <StatusAction
               status={v.status}
               status={v.status}
               percentage={v.loadedPercentage}
               percentage={v.loadedPercentage}
               collection={v}
               collection={v}
+              showLoadButton={true}
             />
             />
           </Typography>
           </Typography>
         );
         );
@@ -484,7 +486,7 @@ const Collections = () => {
   }, [collectionList, batchRefreshCollections]);
   }, [collectionList, batchRefreshCollections]);
 
 
   return (
   return (
-    <Root sx={{ height: 'calc(100% - 24px)' }}>
+    <Root>
       {collections.length > 0 || loading ? (
       {collections.length > 0 || loading ? (
         <AttuGrid
         <AttuGrid
           toolbarConfigs={toolbarConfigs}
           toolbarConfigs={toolbarConfigs}
@@ -497,7 +499,7 @@ const Collections = () => {
           page={currentPage}
           page={currentPage}
           onPageChange={handlePageChange}
           onPageChange={handlePageChange}
           rowsPerPage={pageSize}
           rowsPerPage={pageSize}
-          tableHeaderHeight={49}
+          tableHeaderHeight={46}
           rowHeight={43}
           rowHeight={43}
           setRowsPerPage={handlePageSize}
           setRowsPerPage={handlePageSize}
           isLoading={loading}
           isLoading={loading}

+ 237 - 155
client/src/pages/databases/collections/StatusAction.tsx

@@ -1,153 +1,131 @@
-import { FC, useMemo, MouseEvent, useContext } from 'react';
+import { FC, useMemo, useContext } from 'react';
 import { StatusActionType } from '@/components/status/Types';
 import { StatusActionType } from '@/components/status/Types';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
-import { Typography, useTheme, Chip } from '@mui/material';
+import { useTheme, Chip, Box } from '@mui/material';
 import { rootContext } from '@/context';
 import { rootContext } from '@/context';
 import { LOADING_STATE } from '@/consts';
 import { LOADING_STATE } from '@/consts';
 import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import Icons from '@/components/icons/Icons';
 import Icons from '@/components/icons/Icons';
 import CustomToolTip from '@/components/customToolTip/CustomToolTip';
 import CustomToolTip from '@/components/customToolTip/CustomToolTip';
-import CustomButton from '@/components/customButton/CustomButton';
 import LoadCollectionDialog from '@/pages/dialogs/LoadCollectionDialog';
 import LoadCollectionDialog from '@/pages/dialogs/LoadCollectionDialog';
 import ReleaseCollectionDialog from '@/pages/dialogs/ReleaseCollectionDialog';
 import ReleaseCollectionDialog from '@/pages/dialogs/ReleaseCollectionDialog';
 
 
+const StatusIndicator: FC<{ color: string; filled?: boolean }> = ({
+  color,
+  filled,
+}) => (
+  <span
+    style={{
+      display: 'inline-block',
+      width: 8,
+      height: 8,
+      borderRadius: '50%',
+      border: `1px solid ${color}`,
+      background: filled ? color : '#fff',
+      verticalAlign: 'middle',
+    }}
+  />
+);
+
 const StatusAction: FC<StatusActionType> = props => {
 const StatusAction: FC<StatusActionType> = props => {
   const {
   const {
     status,
     status,
     percentage = 0,
     percentage = 0,
     collection,
     collection,
-    action = () => {},
     showExtraAction,
     showExtraAction,
     showLoadButton,
     showLoadButton,
     createIndexElement,
     createIndexElement,
+    sx,
   } = props;
   } = props;
 
 
-  // Theme
   const theme = useTheme();
   const theme = useTheme();
-
-  // Context
   const { setDialog } = useContext(rootContext);
   const { setDialog } = useContext(rootContext);
-
-  // Translations
   const { t: commonTrans } = useTranslation();
   const { t: commonTrans } = useTranslation();
   const { t: collectionTrans } = useTranslation('collection');
   const { t: collectionTrans } = useTranslation('collection');
-  const { t: btnTrans } = useTranslation('btn');
 
 
-  // Determine status-related labels and icons
-  const { label, tooltip, icon, deleteIcon } = useMemo(() => {
-    switch (status) {
-      case LOADING_STATE.UNLOADED:
-        return {
-          label: commonTrans('status.unloaded'),
-          tooltip: collectionTrans('clickToLoad'),
-          icon: (
-            <span
-              style={{
-                display: 'inline-block',
-                width: 8,
-                height: 8,
-                borderRadius: '50%',
-                border: `1px solid ${theme.palette.primary.main}`,
-                background: '#fff',
-                verticalAlign: 'middle',
-              }}
-            />
-          ),
-          deleteIcon: <Icons.load />,
-        };
-      case LOADING_STATE.LOADED:
-        return {
-          label: commonTrans('status.loaded'),
-          tooltip: collectionTrans('clickToRelease'),
-          icon: (
-            <span
-              style={{
-                display: 'inline-block',
-                width: 8,
-                height: 8,
-                borderRadius: '50%',
-                border: `1px solid ${theme.palette.primary.main}`,
-                background: theme.palette.primary.main,
-                verticalAlign: 'middle',
-              }}
-            />
-          ),
-          deleteIcon: <Icons.release />,
-        };
-      case LOADING_STATE.LOADING:
-        return {
-          label: `${percentage}% ${commonTrans('status.loading')}`,
-          tooltip: collectionTrans('collectionIsLoading'),
-          icon: (
-            <span
-              style={{
-                display: 'inline-flex',
-                alignItems: 'center',
-                marginRight: theme.spacing(1.25),
-              }}
-            >
-              <StatusIcon type={LoadingType.CREATING} />
-            </span>
-          ),
-          deleteIcon: null, // No delete icon during loading
-        };
-      default:
-        return {
-          label: status,
-          tooltip: '',
-          icon: <span></span>,
-          deleteIcon: <Icons.release />,
-        };
-    }
-  }, [status, percentage, theme, collectionTrans]);
+  const chipStyles = {
+    paddingLeft: theme.spacing(0.5),
+  };
 
 
-  // Handle missing vector index
-  const noIndex = collection.schema && !collection.schema.hasVectorIndex;
-  const noIndexIcon = (
+  const LoadingIndicator = () => (
     <span
     <span
       style={{
       style={{
-        display: 'inline-block',
-        width: 8,
-        height: 8,
-        borderRadius: '50%',
-        border: `1px solid ${theme.palette.text.disabled}`,
-        background: '#fff',
-        verticalAlign: 'middle',
+        display: 'inline-flex',
+        alignItems: 'center',
+        marginRight: theme.spacing(1.25),
       }}
       }}
-    />
+    >
+      <StatusIcon type={LoadingType.CREATING} />
+    </span>
   );
   );
+
+  const noIndex = collection.schema && !collection.schema.hasVectorIndex;
+  const noIndexIcon = <StatusIndicator color={theme.palette.text.disabled} />;
   const noIndexTooltip = collectionTrans('noVectorIndexTooltip');
   const noIndexTooltip = collectionTrans('noVectorIndexTooltip');
 
 
-  // Handle chip click
-  const handleChipClick = (e: MouseEvent<HTMLDivElement>) => {
-    e.stopPropagation();
-    setDialog({
-      open: true,
-      type: 'custom',
-      params: {
-        component:
-          status === LOADING_STATE.UNLOADED ? (
-            <LoadCollectionDialog collection={collection} />
-          ) : (
-            <ReleaseCollectionDialog collection={collection} />
-          ),
+  type IconConfig = {
+    icon: JSX.Element | null;
+    show: boolean;
+  };
+
+  const getIconConfig = (
+    status: (typeof LOADING_STATE)[keyof typeof LOADING_STATE]
+  ): IconConfig => {
+    const iconConfigs: Partial<
+      Record<(typeof LOADING_STATE)[keyof typeof LOADING_STATE], IconConfig>
+    > = {
+      [LOADING_STATE.LOADED]: {
+        icon: (
+          <Icons.release
+            className="action-icon"
+            style={{
+              fontSize: '14px',
+              display: 'none',
+              fontWeight: 500,
+              transition: 'all 0.2s',
+              color: 'inherit',
+            }}
+          />
+        ),
+        show: true,
       },
       },
-    });
+      [LOADING_STATE.UNLOADED]: {
+        icon: noIndex ? null : (
+          <Icons.load
+            style={{
+              fontSize: '14px',
+              fontWeight: 500,
+              marginLeft: showLoadButton ? 2 : 0,
+              display: showLoadButton ? 'inline' : 'none',
+              color: 'inherit',
+            }}
+            className={!showLoadButton ? 'action-icon' : ''}
+          />
+        ),
+        show: !noIndex,
+      },
+    };
+
+    return iconConfigs[status] || { icon: null, show: false };
   };
   };
 
 
-  if (
-    collection.schema &&
-    status === LOADING_STATE.UNLOADED &&
-    collection.schema.hasVectorIndex &&
-    showLoadButton
-  ) {
-    return (
-      <CustomButton
-        startIcon={<Icons.load />}
-        sx={{ height: 24, padding: '0 8px' }}
-        variant="contained"
-        tooltip={collectionTrans('clickToLoad')}
-        onClick={() => {
+  const statusConfig = useMemo(() => {
+    const baseConfig = {
+      icon: <StatusIndicator color={theme.palette.primary.main} />,
+      variant: 'outlined' as const,
+      color: 'primary' as const,
+      onClick: undefined as (() => void) | undefined,
+    };
+
+    const configs = {
+      [LOADING_STATE.UNLOADED]: {
+        ...baseConfig,
+        label: commonTrans(
+          noIndex ? 'status.noVectorIndex' : 'status.readyToLoad'
+        ),
+        tooltip: collectionTrans('clickToLoad'),
+        variant: 'outlined' as const,
+        onClick: () => {
           setDialog({
           setDialog({
             open: true,
             open: true,
             type: 'custom',
             type: 'custom',
@@ -155,54 +133,158 @@ const StatusAction: FC<StatusActionType> = props => {
               component: <LoadCollectionDialog collection={collection} />,
               component: <LoadCollectionDialog collection={collection} />,
             },
             },
           });
           });
-        }}
-      >
-        {collectionTrans('loadTitle')}
-      </CustomButton>
+        },
+      },
+      [LOADING_STATE.LOADED]: {
+        ...baseConfig,
+        label: commonTrans('status.loaded'),
+        tooltip: collectionTrans('clickToRelease'),
+        icon: <StatusIndicator color={theme.palette.primary.main} filled />,
+        onClick: () => {
+          setDialog({
+            open: true,
+            type: 'custom',
+            params: {
+              component: <ReleaseCollectionDialog collection={collection} />,
+            },
+          });
+        },
+      },
+      [LOADING_STATE.LOADING]: {
+        ...baseConfig,
+        label: `${percentage}% ${commonTrans('status.loading')}`,
+        tooltip: collectionTrans('collectionIsLoading'),
+        icon: <LoadingIndicator />,
+      },
+    };
+
+    return (
+      configs[status] || {
+        ...baseConfig,
+        label: status,
+        tooltip: '',
+        icon: <span />,
+      }
     );
     );
-  }
+  }, [
+    status,
+    percentage,
+    theme,
+    collectionTrans,
+    commonTrans,
+    collection,
+    setDialog,
+  ]);
 
 
-  return (
-    <div style={{ display: 'flex', alignItems: 'center' }}>
-      <CustomToolTip title={noIndex ? noIndexTooltip : tooltip} placement="top">
+  const renderStatusChip = () => {
+    const iconConfig = getIconConfig(status);
+
+    const getChipStyles = () => {
+      if (noIndex) {
+        return {
+          ...chipStyles,
+          cursor: 'default',
+          fontSize: '12px',
+          borderStyle: 'dashed',
+          borderColor:
+            theme.palette.mode === 'dark'
+              ? theme.palette.grey[600]
+              : theme.palette.text.disabled,
+          backgroundColor:
+            theme.palette.mode === 'dark' ? theme.palette.grey[800] : '#fff',
+          color:
+            theme.palette.mode === 'dark'
+              ? theme.palette.grey[400]
+              : theme.palette.text.disabled,
+        };
+      }
+
+      if (status === LOADING_STATE.UNLOADED) {
+        return {
+          ...chipStyles,
+          cursor: 'pointer',
+          fontSize: '12px',
+          borderColor: theme.palette.primary.main,
+          backgroundColor: 'transparent',
+          color: theme.palette.primary.main,
+          '&:hover': {
+            backgroundColor: `${theme.palette.primary.main} !important`,
+            color: `#fff !important`,
+          },
+        };
+      }
+
+      if (status === LOADING_STATE.LOADED) {
+        return {
+          ...chipStyles,
+          cursor: 'pointer',
+          fontSize: '12px',
+          borderColor: 'transparent',
+          backgroundColor: theme.palette.primary.light,
+          '&:hover': {
+            borderColor: theme.palette.primary.main,
+            '& .action-icon': {
+              display: 'inline-flex !important',
+              color: theme.palette.text.primary,
+            },
+          },
+        };
+      }
+
+      return {
+        ...chipStyles,
+        cursor: 'default',
+        fontSize: '12px',
+      };
+    };
+
+    return (
+      <CustomToolTip
+        title={noIndex ? noIndexTooltip : statusConfig.tooltip}
+        placement="top"
+        enterDelay={1000}
+        leaveDelay={0}
+      >
         <Chip
         <Chip
-          sx={{
-            border: 'none',
-            marginRight: theme.spacing(0.5),
-            paddingLeft: theme.spacing(0.5),
-          }}
-          label={<Typography>{label}</Typography>}
-          onClick={handleChipClick}
+          sx={getChipStyles()}
+          label={
+            <Box
+              sx={{
+                display: 'flex',
+                alignItems: 'center',
+                gap: 0.5,
+              }}
+            >
+              {statusConfig.label}
+              {iconConfig.show && iconConfig.icon}
+            </Box>
+          }
+          onClick={statusConfig.onClick}
           disabled={noIndex}
           disabled={noIndex}
-          deleteIcon={<Icons.release />}
+          variant={statusConfig.variant}
+          color={statusConfig.color}
           size="small"
           size="small"
-          icon={noIndex ? noIndexIcon : icon}
+          icon={noIndex ? noIndexIcon : statusConfig.icon}
         />
         />
       </CustomToolTip>
       </CustomToolTip>
+    );
+  };
 
 
-      {showExtraAction && collection.schema && (
-        <>
-          {status === LOADING_STATE.LOADED && (
-            <CustomButton
-              startIcon={<Icons.navSearch />}
-              sx={{ height: 24, padding: '0 8px' }}
-              tooltip={collectionTrans('clickToSearch')}
-              onClick={() => {
-                const newHash = window.location.hash.replace(
-                  'schema',
-                  'search'
-                );
-                window.location.hash = newHash;
-              }}
-            >
-              {btnTrans('vectorSearch')}
-            </CustomButton>
-          )}
-
-          {!collection.schema.hasVectorIndex && createIndexElement}
-        </>
-      )}
-    </div>
+  return (
+    <Box
+      sx={{
+        display: 'flex',
+        alignItems: 'center',
+        gap: theme.spacing(0.5),
+        ...sx,
+      }}
+    >
+      {renderStatusChip()}
+      {showExtraAction &&
+        collection.schema &&
+        !collection.schema.hasVectorIndex &&
+        createIndexElement}
+    </Box>
   );
   );
 };
 };
 
 

+ 36 - 62
client/src/pages/databases/collections/data/CollectionData.tsx

@@ -38,6 +38,7 @@ import DataView from '@/components/DataView/DataView';
 import DataListView from '@/components/DataListView/DataListView';
 import DataListView from '@/components/DataListView/DataListView';
 import type { QueryState } from '../../types';
 import type { QueryState } from '../../types';
 import { CollectionFullObject } from '@server/types';
 import { CollectionFullObject } from '@server/types';
+import CustomMultiSelector from '../../../../components/customSelector/CustomMultiSelector';
 
 
 export interface CollectionDataProps {
 export interface CollectionDataProps {
   queryState: QueryState;
   queryState: QueryState;
@@ -491,13 +492,44 @@ const CollectionData = (props: CollectionDataProps) => {
             </div>
             </div>
 
 
             <div className="right">
             <div className="right">
-              <FormControl
+              <CustomMultiSelector
+                options={queryState.fields.map(field => ({
+                  label:
+                    field.name === DYNAMIC_FIELD
+                      ? searchTrans('dynamicFields')
+                      : field.name,
+                  value: field.name,
+                }))}
+                values={queryState.outputFields}
+                label={searchTrans('outputFields')}
                 variant="filled"
                 variant="filled"
-                className="outputs selector"
+                wrapperClass="outputs selector"
+                onChange={(e: { target: { value: unknown } }) => {
+                  const values = e.target.value as string[];
+                  // sort output fields by schema order
+                  const newOutputFields = [...values].sort(
+                    (a, b) =>
+                      queryState.fields.findIndex(f => f.name === a) -
+                      queryState.fields.findIndex(f => f.name === b)
+                  );
+
+                  setQueryState({
+                    ...queryState,
+                    outputFields: newOutputFields,
+                  });
+                }}
+                renderValue={(selected: unknown) => {
+                  const selectedArray = selected as string[];
+                  return (
+                    <span>{`${selectedArray.length} ${commonTrans(
+                      selectedArray.length > 1 ? 'grid.fields' : 'grid.field'
+                    )}`}</span>
+                  );
+                }}
                 sx={{
                 sx={{
-                  minWidth: 200,
                   '& .MuiSelect-select': {
                   '& .MuiSelect-select': {
                     fontSize: '14px',
                     fontSize: '14px',
+                    minHeight: '28px',
                   },
                   },
                   '& .MuiInputLabel-root': {
                   '& .MuiInputLabel-root': {
                     fontSize: '14px',
                     fontSize: '14px',
@@ -514,65 +546,7 @@ const CollectionData = (props: CollectionDataProps) => {
                     margin: '0',
                     margin: '0',
                   },
                   },
                 }}
                 }}
-              >
-                <InputLabel>{searchTrans('outputFields')}</InputLabel>
-                <Select
-                  multiple
-                  value={queryState.outputFields}
-                  label={searchTrans('outputFields')}
-                  onChange={e => {
-                    const values = e.target.value as string[];
-                    // sort output fields by schema order
-                    const newOutputFields = [...values].sort(
-                      (a, b) =>
-                        queryState.fields.findIndex(f => f.name === a) -
-                        queryState.fields.findIndex(f => f.name === b)
-                    );
-
-                    setQueryState({
-                      ...queryState,
-                      outputFields: newOutputFields,
-                    });
-                  }}
-                  renderValue={selected => (
-                    <span>{`${selected.length} ${commonTrans(
-                      selected.length > 1 ? 'grid.fields' : 'grid.field'
-                    )}`}</span>
-                  )}
-                  MenuProps={{
-                    PaperProps: {
-                      style: {
-                        maxHeight: 300,
-                      },
-                    },
-                  }}
-                >
-                  {queryState.fields.map(field => (
-                    <MenuItem
-                      key={field.name}
-                      value={field.name}
-                      sx={{
-                        padding: '0 12px',
-                      }}
-                    >
-                      <Checkbox
-                        checked={
-                          queryState.outputFields.indexOf(field.name) > -1
-                        }
-                        size="small"
-                      />
-                      <ListItemText
-                        primary={
-                          field.name === DYNAMIC_FIELD
-                            ? searchTrans('dynamicFields')
-                            : field.name
-                        }
-                        primaryTypographyProps={{ fontSize: '14px' }}
-                      />
-                    </MenuItem>
-                  ))}
-                </Select>
-              </FormControl>
+              />
               <CustomButton
               <CustomButton
                 className="btn"
                 className="btn"
                 onClick={handleFilterReset}
                 onClick={handleFilterReset}

+ 67 - 11
client/src/pages/databases/collections/schema/IndexTypeElement.tsx

@@ -1,7 +1,7 @@
 import { FC, useContext, MouseEvent } from 'react';
 import { FC, useContext, MouseEvent } from 'react';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import Chip from '@mui/material/Chip';
 import Chip from '@mui/material/Chip';
-import { Theme, Tooltip } from '@mui/material';
+import { Tooltip } from '@mui/material';
 import { IndexCreateParam, IndexExtraParam, IndexManageParam } from './Types';
 import { IndexCreateParam, IndexExtraParam, IndexManageParam } from './Types';
 import { rootContext, dataContext } from '@/context';
 import { rootContext, dataContext } from '@/context';
 import Icons from '@/components/icons/Icons';
 import Icons from '@/components/icons/Icons';
@@ -105,7 +105,15 @@ const IndexTypeElement: FC<{
 
 
   const chipComp = (
   const chipComp = (
     text = field.index.indexType,
     text = field.index.indexType,
-    icon = <Icons.delete sx={{ width: 16, height: 16 }} />,
+    icon = (
+      <Icons.delete
+        sx={{
+          width: 16,
+          height: 16,
+          color: theme => theme.palette.secondary.dark,
+        }}
+      />
+    ),
     tooltip = ''
     tooltip = ''
   ) => {
   ) => {
     let labelText = text;
     let labelText = text;
@@ -115,7 +123,34 @@ const IndexTypeElement: FC<{
     const IndexElem = () => (
     const IndexElem = () => (
       <Chip
       <Chip
         label={<span style={{ fontSize: 12 }}>{labelText}</span>}
         label={<span style={{ fontSize: 12 }}>{labelText}</span>}
-        sx={{ padding: theme.spacing(0.5) }}
+        sx={{
+          backgroundColor: theme => theme.palette.secondary.light,
+          color: theme =>
+            theme.palette.mode === 'light'
+              ? theme.palette.secondary.main
+              : '#fff',
+          height: '20px',
+          '& .MuiChip-label': {
+            px: 1,
+          },
+          border: '1px solid transparent',
+          '& .MuiChip-deleteIcon': {
+            color: theme =>
+              theme.palette.mode === 'light'
+                ? theme.palette.secondary.main
+                : '#fff',
+            '&:hover': {
+              color: theme =>
+                theme.palette.mode === 'light'
+                  ? theme.palette.secondary.main
+                  : '#fff',
+            },
+          },
+          '&:hover': {
+            border: theme => `1px solid ${theme.palette.secondary.main}`,
+            backgroundColor: theme => theme.palette.secondary.light,
+          },
+        }}
         deleteIcon={icon}
         deleteIcon={icon}
         onDelete={handleDelete}
         onDelete={handleDelete}
         disabled={disabled}
         disabled={disabled}
@@ -156,13 +191,27 @@ const IndexTypeElement: FC<{
             display: 'flex',
             display: 'flex',
             alignItems: 'center',
             alignItems: 'center',
             whiteSpace: 'nowrap',
             whiteSpace: 'nowrap',
-            color: theme.palette.primary.main,
-            height: 26,
-            fontSize: 13,
-            border: isVector
-              ? `1px dashed ${theme.palette.primary.main}`
-              : '1px solid transparent',
-            '& svg': { width: 15 },
+            backgroundColor: 'transparent',
+            borderRadius: 8,
+            color: theme => theme.palette.secondary.main,
+            fontWeight: 600,
+            fontSize: '12px',
+            height: '20px',
+            border: theme =>
+              isVector
+                ? `1px dashed ${theme.palette.secondary.main}`
+                : `1px solid ${theme.palette.secondary.main}`,
+            '& svg': {
+              width: 15,
+              color: theme => theme.palette.secondary.main,
+            },
+            '&:hover': {
+              backgroundColor: theme => theme.palette.secondary.main,
+              color: theme => theme.palette.secondary.contrastText,
+              '& svg': {
+                color: theme => theme.palette.secondary.contrastText,
+              },
+            },
           }}
           }}
           onClick={e => handleCreate(e)}
           onClick={e => handleCreate(e)}
         >
         >
@@ -194,7 +243,14 @@ const IndexTypeElement: FC<{
   };
   };
 
 
   return (
   return (
-    <span style={{ width: 'auto', display: 'inline-block' }}>
+    <span
+      style={{
+        width: 'auto',
+        display: 'inline-flex',
+        alignItems: 'center',
+        height: '100%',
+      }}
+    >
       {generateElement()}
       {generateElement()}
     </span>
     </span>
   );
   );

+ 17 - 2
client/src/pages/databases/collections/schema/Schema.tsx

@@ -24,7 +24,7 @@ import {
   NameWrapper,
   NameWrapper,
   ParamWrapper,
   ParamWrapper,
   GridWrapper,
   GridWrapper,
-} from './Styles';
+} from './StyledComponents';
 import LoadCollectionDialog from '@/pages/dialogs/LoadCollectionDialog';
 import LoadCollectionDialog from '@/pages/dialogs/LoadCollectionDialog';
 import RenameCollectionDialog from '@/pages/dialogs/RenameCollectionDialog';
 import RenameCollectionDialog from '@/pages/dialogs/RenameCollectionDialog';
 import EditMmapDialog from '@/pages/dialogs/EditMmapDialog';
 import EditMmapDialog from '@/pages/dialogs/EditMmapDialog';
@@ -87,7 +87,22 @@ const Overview = () => {
             {f.name === '$meta' && (
             {f.name === '$meta' && (
               <StyledChip size="small" label="Dynamic field" />
               <StyledChip size="small" label="Dynamic field" />
             )}
             )}
-            {f.is_primary_key && <StyledChip size="small" label="ID" />}
+            {f.is_primary_key && (
+              <StyledChip
+                size="small"
+                label="PK"
+                sx={{
+                  backgroundColor: theme => theme.palette.secondary.light,
+                  fontWeight: 600,
+                  fontSize: '12px',
+                  height: '20px',
+                  '& .MuiChip-label': {
+                    px: 1,
+                  },
+                  border: theme => `1px solid ${theme.palette.secondary.main}`,
+                }}
+              />
+            )}
             {f.is_partition_key && (
             {f.is_partition_key && (
               <StyledChip size="small" label="Partition key" />
               <StyledChip size="small" label="Partition key" />
             )}
             )}

+ 6 - 6
client/src/pages/databases/collections/schema/Styles.tsx → client/src/pages/databases/collections/schema/StyledComponents.tsx

@@ -7,15 +7,15 @@ export const Wrapper = styled(Box)(({ theme }) => ({
   flexGrow: 1,
   flexGrow: 1,
   height: '100%',
   height: '100%',
   overflow: 'auto',
   overflow: 'auto',
-  gap: theme.spacing(2),
-  padding: theme.spacing(1, 0),
+  gap: theme.spacing(1.5),
+  padding: theme.spacing(0.5, 0),
   maxWidth: '100%',
   maxWidth: '100%',
 }));
 }));
 
 
 export const InfoWrapper = styled(Box)(({ theme }) => ({
 export const InfoWrapper = styled(Box)(({ theme }) => ({
   display: 'grid',
   display: 'grid',
   gridTemplateColumns: '1.2fr 1fr 1fr',
   gridTemplateColumns: '1.2fr 1fr 1fr',
-  gap: theme.spacing(2),
+  gap: theme.spacing(1.5),
   width: '100%',
   width: '100%',
   [theme.breakpoints.down('md')]: {
   [theme.breakpoints.down('md')]: {
     gridTemplateColumns: '1fr',
     gridTemplateColumns: '1fr',
@@ -24,8 +24,8 @@ export const InfoWrapper = styled(Box)(({ theme }) => ({
 
 
 export const Card = styled(Box)(({ theme }) => ({
 export const Card = styled(Box)(({ theme }) => ({
   backgroundColor: theme.palette.background.default,
   backgroundColor: theme.palette.background.default,
-  borderRadius: 8,
-  padding: theme.spacing(2),
+  borderRadius: 2,
+  padding: theme.spacing(1.5),
   boxSizing: 'border-box',
   boxSizing: 'border-box',
   display: 'flex',
   display: 'flex',
   flexDirection: 'column',
   flexDirection: 'column',
@@ -41,7 +41,7 @@ export const Card = styled(Box)(({ theme }) => ({
 export const InfoRow = styled(Box)(({ theme }) => ({
 export const InfoRow = styled(Box)(({ theme }) => ({
   display: 'flex',
   display: 'flex',
   alignItems: 'flex-start',
   alignItems: 'flex-start',
-  gap: theme.spacing(2),
+  gap: theme.spacing(1.5),
   '&:not(:last-child)': {
   '&:not(:last-child)': {
     paddingBottom: theme.spacing(1),
     paddingBottom: theme.spacing(1),
   },
   },

+ 124 - 118
client/src/pages/databases/collections/search/Search.tsx

@@ -51,6 +51,7 @@ import {
   Explorer,
   Explorer,
   CloseButton,
   CloseButton,
   CheckboxRow,
   CheckboxRow,
+  LeftSection,
 } from './StyledComponents';
 } from './StyledComponents';
 
 
 export interface CollectionDataProps {
 export interface CollectionDataProps {
@@ -412,125 +413,127 @@ const Search = (props: CollectionDataProps) => {
     <SearchRoot>
     <SearchRoot>
       {collection && (
       {collection && (
         <InputArea>
         <InputArea>
-          <AccordionsContainer>
-            {searchParams.searchParams.map((s, index: number) => {
-              const field = s.field;
-              return (
-                <StyledAccordion
-                  key={`${collection.collection_name}-${field.name}`}
-                  expanded={s.expanded}
-                  onChange={handleExpand(field.name)}
-                  className={highlightField === field.name ? 'highlight' : ''}
-                >
-                  <AccordionSummary
-                    expandIcon={<ExpandMoreIcon />}
-                    aria-controls={`${field.name}-content`}
-                    id={`${field.name}-header`}
+          <LeftSection>
+            <AccordionsContainer>
+              {searchParams.searchParams.map((s, index: number) => {
+                const field = s.field;
+                return (
+                  <StyledAccordion
+                    key={`${collection.collection_name}-${field.name}`}
+                    expanded={s.expanded}
+                    onChange={handleExpand(field.name)}
+                    className={highlightField === field.name ? 'highlight' : ''}
                   >
                   >
-                    <CheckboxRow>
-                      {searchParams.searchParams.length > 1 && (
-                        <Checkbox
-                          size="small"
-                          checked={s.selected}
-                          onChange={handleSelect(field.name)}
-                        />
-                      )}
-                      <div className="label">
-                        <Typography
-                          className={`field-name ${s.selected ? 'bold' : ''}`}
-                        >
-                          {field.is_function_output
-                            ? `${field.name}<=${
-                                field.function!.input_field_names[0]
-                              }`
-                            : field.name}
-                        </Typography>
-                        <Typography className="vector-type">
-                          {formatFieldType(field)}
-                          <i>
-                            {field.index &&
-                              `${field.index.indexType}(${field.index.metricType})`}
-                          </i>
-                        </Typography>
-                      </div>
-                    </CheckboxRow>
-                  </AccordionSummary>
-                  <StyledAccordionDetails>
-                    <VectorInputBox
-                      searchParams={s}
-                      onChange={onSearchInputChange}
-                      collection={collection}
-                      type={field.is_function_output ? 'text' : 'vector'}
-                    />
-
-                    <SearchParams
-                      sx={{ pt: 1, mb: 1 }}
-                      indexType={field.index.indexType}
-                      searchParamsForm={s.params}
-                      handleFormChange={(updates: {
-                        [key in string]: number | string | boolean;
-                      }) => {
-                        updateSearchParamCallback(updates as any, index);
-                      }}
-                    />
-                  </StyledAccordionDetails>
-                </StyledAccordion>
-              );
-            })}
-
-            {enablePartitionsFilter && (
-              <PartitionsSelector
-                collectionName={collectionName}
-                selected={searchParams.partitions}
-                setSelected={onPartitionsChange}
-              />
-            )}
-          </AccordionsContainer>
-
-          <SearchControls>
-            <SearchGlobalParams
-              onSlideChange={(field: string) => {
-                setHighlightField(field);
-              }}
-              onSlideChangeCommitted={() => {
-                setHighlightField('');
-              }}
-              searchParams={searchParams}
-              handleFormChange={(params: any) => {
-                searchParams.globalParams = params;
-                setSearchParams({ ...searchParams });
-              }}
-            />
-
-            <CustomButton
-              onClick={genRandomVectors}
-              size="small"
-              disabled={false}
-              className="genBtn"
-              sx={{
-                mb: 1,
-              }}
-            >
-              {btnTrans('example')}
-            </CustomButton>
-
-            <CustomButton
-              variant="contained"
-              size="small"
-              className="genBtn"
-              disabled={disableSearch}
-              tooltip={disableSearchTooltip}
-              tooltipPlacement="top"
-              onClick={onSearchClicked}
-            >
-              {btnTrans('searchMulti', {
-                number:
-                  searchParams.collection.schema.vectorFields.length > 1
-                    ? `(${selectedFields.length})`
-                    : '',
+                    <AccordionSummary
+                      expandIcon={<ExpandMoreIcon />}
+                      aria-controls={`${field.name}-content`}
+                      id={`${field.name}-header`}
+                    >
+                      <CheckboxRow>
+                        {searchParams.searchParams.length > 1 && (
+                          <Checkbox
+                            size="small"
+                            checked={s.selected}
+                            onChange={handleSelect(field.name)}
+                          />
+                        )}
+                        <div className="label">
+                          <Typography
+                            className={`field-name ${s.selected ? 'bold' : ''}`}
+                          >
+                            {field.is_function_output
+                              ? `${field.name}<=${
+                                  field.function!.input_field_names[0]
+                                }`
+                              : field.name}
+                          </Typography>
+                          <Typography className="vector-type">
+                            {formatFieldType(field)}
+                            <i>
+                              {field.index &&
+                                `${field.index.indexType}(${field.index.metricType})`}
+                            </i>
+                          </Typography>
+                        </div>
+                      </CheckboxRow>
+                    </AccordionSummary>
+                    <StyledAccordionDetails>
+                      <VectorInputBox
+                        searchParams={s}
+                        onChange={onSearchInputChange}
+                        collection={collection}
+                        type={field.is_function_output ? 'text' : 'vector'}
+                      />
+
+                      <SearchParams
+                        sx={{ pt: 1, mb: 1 }}
+                        indexType={field.index.indexType}
+                        searchParamsForm={s.params}
+                        handleFormChange={(updates: {
+                          [key in string]: number | string | boolean;
+                        }) => {
+                          updateSearchParamCallback(updates as any, index);
+                        }}
+                      />
+                    </StyledAccordionDetails>
+                  </StyledAccordion>
+                );
               })}
               })}
-            </CustomButton>
-          </SearchControls>
+
+              {enablePartitionsFilter && (
+                <PartitionsSelector
+                  collectionName={collectionName}
+                  selected={searchParams.partitions}
+                  setSelected={onPartitionsChange}
+                />
+              )}
+            </AccordionsContainer>
+
+            <SearchControls>
+              <SearchGlobalParams
+                onSlideChange={(field: string) => {
+                  setHighlightField(field);
+                }}
+                onSlideChangeCommitted={() => {
+                  setHighlightField('');
+                }}
+                searchParams={searchParams}
+                handleFormChange={(params: any) => {
+                  searchParams.globalParams = params;
+                  setSearchParams({ ...searchParams });
+                }}
+              />
+
+              <CustomButton
+                onClick={genRandomVectors}
+                size="small"
+                disabled={false}
+                className="genBtn"
+                sx={{
+                  mb: 1,
+                }}
+              >
+                {btnTrans('example')}
+              </CustomButton>
+
+              <CustomButton
+                variant="contained"
+                size="small"
+                className="genBtn"
+                disabled={disableSearch}
+                tooltip={disableSearchTooltip}
+                tooltipPlacement="top"
+                onClick={onSearchClicked}
+              >
+                {btnTrans('searchMulti', {
+                  number:
+                    searchParams.collection.schema.vectorFields.length > 1
+                      ? `(${selectedFields.length})`
+                      : '',
+                })}
+              </CustomButton>
+            </SearchControls>
+          </LeftSection>
 
 
           <SearchResults>
           <SearchResults>
             <Toolbar>
             <Toolbar>
@@ -633,6 +636,9 @@ const Search = (props: CollectionDataProps) => {
                 searchParams.searchResult.length > 0) ||
                 searchParams.searchResult.length > 0) ||
               tableLoading ? (
               tableLoading ? (
               <AttuGrid
               <AttuGrid
+                sx={{
+                  height: 'calc(100% - 64px)',
+                }}
                 toolbarConfigs={[]}
                 toolbarConfigs={[]}
                 colDefinitions={colDefinitions}
                 colDefinitions={colDefinitions}
                 rows={result}
                 rows={result}
@@ -640,7 +646,7 @@ const Search = (props: CollectionDataProps) => {
                 primaryKey="rank"
                 primaryKey="rank"
                 page={currentPage}
                 page={currentPage}
                 tableHeaderHeight={46}
                 tableHeaderHeight={46}
-                rowHeight={39}
+                rowHeight={41}
                 openCheckBox={false}
                 openCheckBox={false}
                 onPageChange={handlePageChange}
                 onPageChange={handlePageChange}
                 rowsPerPage={pageSize}
                 rowsPerPage={pageSize}

+ 1 - 12
client/src/pages/databases/collections/search/SearchInputBox.tsx

@@ -19,21 +19,10 @@ import { styled } from '@mui/material/styles';
 
 
 const SearchInputBoxWrapper = styled('div')(({ theme }) => ({
 const SearchInputBoxWrapper = styled('div')(({ theme }) => ({
   height: '124px',
   height: '124px',
-  margin: '0 0 8px 0',
+  margin: 0,
   overflow: 'auto',
   overflow: 'auto',
   backgroundColor: theme.palette.background.default,
   backgroundColor: theme.palette.background.default,
   cursor: 'text',
   cursor: 'text',
-  boxShadow: '0 1px 0 transparent',
-  transition: 'box-shadow 0.3s ease',
-  '&:hover': {
-    boxShadow: '0 1px 0 #000',
-  },
-  '&:active': {
-    boxShadow: `0 1px 0 ${theme.palette.primary.main}`,
-  },
-  '&.focused': {
-    boxShadow: `0 2px 0 ${theme.palette.primary.main}`,
-  },
 }));
 }));
 
 
 export type SearchInputBoxProps = {
 export type SearchInputBoxProps = {

+ 1 - 1
client/src/pages/databases/collections/search/SearchParams.tsx

@@ -106,7 +106,7 @@ const SearchParams: FC<SearchParamsProps> = ({
         ...sx,
         ...sx,
         display: 'flex',
         display: 'flex',
         flexDirection: 'column',
         flexDirection: 'column',
-        gap: 2,
+        gap: 1.5,
       }}
       }}
     >
     >
       {paramList.map(param => {
       {paramList.map(param => {

+ 23 - 29
client/src/pages/databases/collections/search/StyledComponents.ts

@@ -11,20 +11,27 @@ export const InputArea = styled(Box)({
   display: 'flex',
   display: 'flex',
   flexDirection: 'row',
   flexDirection: 'row',
   width: '100%',
   width: '100%',
-  height: 'max-content',
+  height: '100%',
   padding: 0,
   padding: 0,
+  overflow: 'hidden',
 });
 });
 
 
+export const LeftSection = styled(Box)(({ theme }) => ({
+  display: 'flex',
+  flexDirection: 'row',
+  position: 'relative',
+  paddingRight: '8px',
+  marginBottom: '8px',
+  borderRight: `1px solid ${theme.palette.divider}`,
+}));
+
 export const AccordionsContainer = styled(Box)(({ theme }) => ({
 export const AccordionsContainer = styled(Box)(({ theme }) => ({
   display: 'flex',
   display: 'flex',
   width: '260px',
   width: '260px',
   flexDirection: 'column',
   flexDirection: 'column',
   flexShrink: 0,
   flexShrink: 0,
-  padding: '0 8px 8px 0',
-  minHeight: 'calc(100vh - 164px)',
-  height: 'calc(100vh - 164px)',
   overflow: 'auto',
   overflow: 'auto',
-  borderRight: `1px solid ${theme.palette.divider}`,
+  maxHeight: '100%',
   '& .MuiAccordion-root.Mui-expanded': {
   '& .MuiAccordion-root.Mui-expanded': {
     margin: 0,
     margin: 0,
   },
   },
@@ -36,17 +43,17 @@ export const AccordionsContainer = styled(Box)(({ theme }) => ({
 export const StyledAccordion = styled(Accordion)(({ theme }) => ({
 export const StyledAccordion = styled(Accordion)(({ theme }) => ({
   boxShadow: 'none',
   boxShadow: 'none',
   padding: '0',
   padding: '0',
-  border: '1px solid transparent',
 
 
+  border: '1px solid transparent',
   '&.highlight': {
   '&.highlight': {
     border: `1px solid ${theme.palette.secondary.main}`,
     border: `1px solid ${theme.palette.secondary.main}`,
-    borderRadius: 8,
+    borderRadius: 4,
   },
   },
 
 
   '& .MuiAccordionSummary-root': {
   '& .MuiAccordionSummary-root': {
     minHeight: '48px',
     minHeight: '48px',
     height: '48px',
     height: '48px',
-    padding: '0 12px 0 0',
+    padding: '0 8px',
     transition: 'none',
     transition: 'none',
     '&.Mui-expanded': {
     '&.Mui-expanded': {
       minHeight: '48px',
       minHeight: '48px',
@@ -100,19 +107,7 @@ export const SearchInputBox = styled(Box)(({ theme }) => ({
   height: '124px',
   height: '124px',
   margin: '0 0 8px 0',
   margin: '0 0 8px 0',
   overflow: 'auto',
   overflow: 'auto',
-  backgroundColor: theme.palette.background.default,
   cursor: 'text',
   cursor: 'text',
-  boxShadow: '0 1px 0 transparent',
-  transition: 'box-shadow 0.3s ease',
-  '&:hover': {
-    boxShadow: '0 1px 0 #000',
-  },
-  '&:active': {
-    boxShadow: `0 1px 0 ${theme.palette.primary.main}`,
-  },
-  '&.focused': {
-    boxShadow: `0 2px 0 ${theme.palette.primary.main}`,
-  },
 }));
 }));
 
 
 export const SearchControls = styled(Box)(({ theme }) => ({
 export const SearchControls = styled(Box)(({ theme }) => ({
@@ -120,9 +115,10 @@ export const SearchControls = styled(Box)(({ theme }) => ({
   flexDirection: 'column',
   flexDirection: 'column',
   width: 120,
   width: 120,
   minWidth: 120,
   minWidth: 120,
-  padding: '0 8px',
-  borderRight: `1px solid ${theme.palette.divider}`,
-
+  padding: '0',
+  height: 'fit-content',
+  alignSelf: 'flex-start',
+  marginLeft: '8px',
   '& .selector': {
   '& .selector': {
     marginBottom: '8px',
     marginBottom: '8px',
   },
   },
@@ -137,7 +133,7 @@ export const SearchResults = styled(Box)({
   flexDirection: 'column',
   flexDirection: 'column',
   flexGrow: 1,
   flexGrow: 1,
   paddingLeft: 8,
   paddingLeft: 8,
-  overflow: 'auto',
+  overflow: 'hidden',
 });
 });
 
 
 export const Toolbar = styled(Box)(({ theme }) => ({
 export const Toolbar = styled(Box)(({ theme }) => ({
@@ -206,8 +202,7 @@ export const NodeInfo = styled(Paper)(({ theme }) => ({
   padding: '8px',
   padding: '8px',
   backgroundColor: theme.palette.background.paper,
   backgroundColor: theme.palette.background.paper,
   border: `1px solid ${theme.palette.divider}`,
   border: `1px solid ${theme.palette.divider}`,
-  borderRadius: 8,
-  boxShadow: '0px 6px 30px rgba(0, 0, 0, 0.1)',
+  borderRadius: 4,
   maxWidth: 240,
   maxWidth: 240,
   overflow: 'auto',
   overflow: 'auto',
   zIndex: 1,
   zIndex: 1,
@@ -237,7 +232,7 @@ export const SelectedNodes = styled(Box)(({ theme }) => ({
   flexDirection: 'column',
   flexDirection: 'column',
   top: 200,
   top: 200,
   right: 36,
   right: 36,
-  borderRadius: 8,
+  borderRadius: 4,
   gap: 8,
   gap: 8,
   height: '70%',
   height: '70%',
   overflow: 'auto',
   overflow: 'auto',
@@ -293,8 +288,7 @@ export const DataExplorerRoot = styled(Box)(({ theme }) => ({
     padding: '8px',
     padding: '8px',
     backgroundColor: theme.palette.background.paper,
     backgroundColor: theme.palette.background.paper,
     border: `1px solid ${theme.palette.divider}`,
     border: `1px solid ${theme.palette.divider}`,
-    borderRadius: 8,
-    boxShadow: '0px 6px 30px rgba(0, 0, 0, 0.1)',
+    borderRadius: 4,
     maxWidth: 240,
     maxWidth: 240,
     overflow: 'auto',
     overflow: 'auto',
     zIndex: 1,
     zIndex: 1,

+ 2 - 4
client/src/pages/databases/tree/index.tsx

@@ -49,7 +49,6 @@ interface FlatTreeItem {
   originalNode: OriginalDatabaseTreeItem; // Keep original node ref if needed
   originalNode: OriginalDatabaseTreeItem; // Keep original node ref if needed
 }
 }
 
 
-// ... existing CollectionNode component (can be reused or integrated) ...
 const CollectionNode: React.FC<{ data: CollectionObject }> = ({ data }) => {
 const CollectionNode: React.FC<{ data: CollectionObject }> = ({ data }) => {
   const { t: commonTrans } = useTranslation();
   const { t: commonTrans } = useTranslation();
   const hasIndex = data.schema && data.schema.hasVectorIndex;
   const hasIndex = data.schema && data.schema.hasVectorIndex;
@@ -346,11 +345,10 @@ const DatabaseTree: React.FC<DatabaseTreeProps> = props => {
       <Box
       <Box
         ref={parentRef}
         ref={parentRef}
         sx={{
         sx={{
-          height: treeHeight, // Adjust this height based on your layout requirements
+          height: treeHeight,
           overflow: 'auto',
           overflow: 'auto',
           fontSize: '15px',
           fontSize: '15px',
           color: theme => theme.palette.text.primary,
           color: theme => theme.palette.text.primary,
-          backgroundColor: theme => theme.palette.background.default,
           '& .MuiSvgIcon-root': {
           '& .MuiSvgIcon-root': {
             fontSize: '14px',
             fontSize: '14px',
             color: theme => theme.palette.text.primary,
             color: theme => theme.palette.text.primary,
@@ -472,7 +470,7 @@ const DatabaseTree: React.FC<DatabaseTreeProps> = props => {
         sx={{ pointerEvents: 'none' }}
         sx={{ pointerEvents: 'none' }}
         slotProps={{
         slotProps={{
           paper: {
           paper: {
-            sx: { pointerEvents: 'auto', boxShadow: 4, borderRadius: 2 },
+            sx: { pointerEvents: 'auto', borderRadius: 2 },
           },
           },
         }}
         }}
       >
       >

+ 38 - 57
client/src/pages/dialogs/EditMmapDialog.tsx

@@ -32,21 +32,24 @@ interface FieldMmapState {
   hasIndex: boolean;
   hasIndex: boolean;
 }
 }
 
 
-const EditMmapDialog: FC<EditMmapProps> = props => {
-  const { collection, cb } = props;
-
+const EditMmapDialog: FC<EditMmapProps> = ({ collection, cb }) => {
   const { handleCloseDialog, openSnackBar } = useContext(rootContext);
   const { handleCloseDialog, openSnackBar } = useContext(rootContext);
   const { fetchCollection } = useContext(dataContext);
   const { fetchCollection } = useContext(dataContext);
-
   const { t: dialogTrans } = useTranslation('dialog');
   const { t: dialogTrans } = useTranslation('dialog');
   const { t: btnTrans } = useTranslation('btn');
   const { t: btnTrans } = useTranslation('btn');
   const { t: successTrans } = useTranslation('success');
   const { t: successTrans } = useTranslation('success');
   const { t: collectionTrans } = useTranslation('collection');
   const { t: collectionTrans } = useTranslation('collection');
   const { t: indexTrans } = useTranslation('index');
   const { t: indexTrans } = useTranslation('index');
 
 
-  // Current state of all fields (initial state)
-  const [fieldsState, setFieldsState] = useState<FieldMmapState[]>(() => {
-    return collection.schema!.fields.map(field => ({
+  const isCollectionMmapEnabled = collection?.properties!.some(
+    p => p.key === 'mmap.enabled' && p.value === 'true'
+  );
+  const [pendingCollectionMmap, setPendingCollectionMmap] = useState(
+    isCollectionMmapEnabled
+  );
+  const [pendingChanges, setPendingChanges] = useState<MmapChanges[]>([]);
+  const [fieldsState, setFieldsState] = useState<FieldMmapState[]>(() =>
+    collection.schema!.fields.map(field => ({
       id: field.fieldID as string,
       id: field.fieldID as string,
       name: field.name,
       name: field.name,
       indexName: field.index?.index_name,
       indexName: field.index?.index_name,
@@ -57,37 +60,22 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
         ? findKeyValue(field.index!.params, 'mmap.enabled') === 'true'
         ? findKeyValue(field.index!.params, 'mmap.enabled') === 'true'
         : false,
         : false,
       hasIndex: !!field.index,
       hasIndex: !!field.index,
-    }));
-  });
-
-  const isCollectionMmapEnabled = collection?.properties!.some((p: any) => {
-    return p.key === 'mmap.enabled' && p.value === 'true';
-  });
-
-  // Track changes that will be applied on confirm
-  const [pendingChanges, setPendingChanges] = useState<MmapChanges[]>([]);
-  const [pendingCollectionMmap, setPendingCollectionMmap] = useState<boolean>(
-    isCollectionMmapEnabled
+    }))
   );
   );
 
 
   const handleRawMmapChange = (fieldId: string, enabled: boolean) => {
   const handleRawMmapChange = (fieldId: string, enabled: boolean) => {
     const field = fieldsState.find(f => f.id === fieldId)!;
     const field = fieldsState.find(f => f.id === fieldId)!;
-
     setFieldsState(prev =>
     setFieldsState(prev =>
       prev.map(f => (f.id === fieldId ? { ...f, rawMmapEnabled: enabled } : f))
       prev.map(f => (f.id === fieldId ? { ...f, rawMmapEnabled: enabled } : f))
     );
     );
-
     setPendingChanges(prev => {
     setPendingChanges(prev => {
-      // Remove any existing changes for this field
       const filtered = prev.filter(change => change.fieldName !== field.name);
       const filtered = prev.filter(change => change.fieldName !== field.name);
-      // Add the new change
       return [
       return [
         ...filtered,
         ...filtered,
         {
         {
           fieldName: field.name,
           fieldName: field.name,
           indexName: field.indexName,
           indexName: field.indexName,
           rawMmapEnabled: enabled,
           rawMmapEnabled: enabled,
-          // Preserve existing index change if it exists
           indexMmapEnabled: prev.find(c => c.fieldName === field.name)
           indexMmapEnabled: prev.find(c => c.fieldName === field.name)
             ?.indexMmapEnabled,
             ?.indexMmapEnabled,
         },
         },
@@ -97,23 +85,18 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
 
 
   const handleIndexMmapChange = (fieldId: string, enabled: boolean) => {
   const handleIndexMmapChange = (fieldId: string, enabled: boolean) => {
     const field = fieldsState.find(f => f.id === fieldId)!;
     const field = fieldsState.find(f => f.id === fieldId)!;
-
     setFieldsState(prev =>
     setFieldsState(prev =>
       prev.map(f =>
       prev.map(f =>
         f.id === fieldId ? { ...f, indexMmapEnabled: enabled } : f
         f.id === fieldId ? { ...f, indexMmapEnabled: enabled } : f
       )
       )
     );
     );
-
     setPendingChanges(prev => {
     setPendingChanges(prev => {
-      // Remove any existing changes for this field
       const filtered = prev.filter(change => change.fieldName !== field.name);
       const filtered = prev.filter(change => change.fieldName !== field.name);
-      // Add the new change
       return [
       return [
         ...filtered,
         ...filtered,
         {
         {
           fieldName: field.name,
           fieldName: field.name,
           indexName: field.indexName,
           indexName: field.indexName,
-          // Preserve existing raw change if it exists
           rawMmapEnabled: prev.find(c => c.fieldName === field.name)
           rawMmapEnabled: prev.find(c => c.fieldName === field.name)
             ?.rawMmapEnabled,
             ?.rawMmapEnabled,
           indexMmapEnabled: enabled,
           indexMmapEnabled: enabled,
@@ -123,7 +106,6 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
   };
   };
 
 
   const handleConfirm = async () => {
   const handleConfirm = async () => {
-    // Make the API call to update mmap settings
     try {
     try {
       if (pendingCollectionMmap !== isCollectionMmapEnabled) {
       if (pendingCollectionMmap !== isCollectionMmapEnabled) {
         await CollectionService.setProperty(collection.collection_name, {
         await CollectionService.setProperty(collection.collection_name, {
@@ -135,7 +117,6 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
           collection.collection_name,
           collection.collection_name,
           pendingChanges
           pendingChanges
         );
         );
-
         openSnackBar(
         openSnackBar(
           successTrans('updateMmap', { name: collection.collection_name }),
           successTrans('updateMmap', { name: collection.collection_name }),
           'success'
           'success'
@@ -157,24 +138,27 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
 
 
   return (
   return (
     <DialogTemplate
     <DialogTemplate
-      sx={{
-        minWidth: '600px',
-        maxWidth: '800px',
-      }}
+      sx={{ minWidth: '600px', maxWidth: '800px' }}
       title={dialogTrans('manageMmapTitle', {
       title={dialogTrans('manageMmapTitle', {
         type: collection.collection_name,
         type: collection.collection_name,
       })}
       })}
       handleClose={handleCloseDialog}
       handleClose={handleCloseDialog}
+      confirmDisabled={noChange || notReleased}
+      confirmLabel={btnTrans('confirm')}
+      confirmDisabledTooltip={
+        notReleased ? collectionTrans('mmapCollectionNotReleasedTooltip') : ''
+      }
+      handleConfirm={handleConfirm}
       children={
       children={
         <Box>
         <Box>
           <Typography
           <Typography
             variant="body2"
             variant="body2"
-            sx={{ margin: '8px 0 16px 0', fontSize: '14px' }}
+            sx={{ m: '8px 0 16px', fontSize: '14px' }}
             dangerouslySetInnerHTML={{ __html: dialogTrans('editMmapInfo') }}
             dangerouslySetInnerHTML={{ __html: dialogTrans('editMmapInfo') }}
           />
           />
           <Box
           <Box
             sx={{
             sx={{
-              margin: '8px 0 0 0',
+              m: '8px 0 0',
               fontSize: '13px',
               fontSize: '13px',
               fontWeight: 800,
               fontWeight: 800,
               display: 'flex',
               display: 'flex',
@@ -184,9 +168,7 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
             {collectionTrans('collectionMMapSettingsLabel')}
             {collectionTrans('collectionMMapSettingsLabel')}
             <Switch
             <Switch
               checked={pendingCollectionMmap}
               checked={pendingCollectionMmap}
-              onChange={e => {
-                setPendingCollectionMmap(e.target.checked);
-              }}
+              onChange={e => setPendingCollectionMmap(e.target.checked)}
               color="primary"
               color="primary"
               sx={{ ml: 1 }}
               sx={{ ml: 1 }}
             />
             />
@@ -194,34 +176,39 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
           <br />
           <br />
           <Table
           <Table
             sx={{
             sx={{
-              marginTop: 0,
+              mt: 0,
               '& th': { fontWeight: 'bold' },
               '& th': { fontWeight: 'bold' },
+              '& .MuiTableRow-root': { height: '40px' },
             }}
             }}
           >
           >
             <TableHead>
             <TableHead>
               <TableRow>
               <TableRow>
-                <TableCell>{collectionTrans('fieldName')}</TableCell>
-                <TableCell>{collectionTrans('rawData')}</TableCell>
-                <TableCell>{indexTrans('index')}</TableCell>
+                <TableCell sx={{ py: 1 }}>
+                  {collectionTrans('fieldName')}
+                </TableCell>
+                <TableCell sx={{ py: 1 }}>
+                  {collectionTrans('rawData')}
+                </TableCell>
+                <TableCell sx={{ py: 1 }}>{indexTrans('index')}</TableCell>
               </TableRow>
               </TableRow>
             </TableHead>
             </TableHead>
             <TableBody>
             <TableBody>
               {fieldsState.map(field => (
               {fieldsState.map(field => (
-                <TableRow key={field.id}>
-                  <TableCell>
+                <TableRow
+                  key={field.id}
+                  sx={{ '&:last-child td': { borderBottom: 0 } }}
+                >
+                  <TableCell sx={{ py: 1 }}>
                     <Box sx={{ display: 'flex', flexDirection: 'column' }}>
                     <Box sx={{ display: 'flex', flexDirection: 'column' }}>
                       <span>{field.name}</span>
                       <span>{field.name}</span>
                       <span
                       <span
-                        style={{
-                          color: 'rgba(0,0,0,0.6)',
-                          fontSize: '0.8rem',
-                        }}
+                        style={{ color: 'rgba(0,0,0,0.6)', fontSize: '0.8rem' }}
                       >
                       >
                         {field.dataType}
                         {field.dataType}
                       </span>
                       </span>
                     </Box>
                     </Box>
                   </TableCell>
                   </TableCell>
-                  <TableCell>
+                  <TableCell sx={{ py: 1 }}>
                     <Tooltip
                     <Tooltip
                       title={
                       title={
                         pendingCollectionMmap
                         pendingCollectionMmap
@@ -244,7 +231,7 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
                       </span>
                       </span>
                     </Tooltip>
                     </Tooltip>
                   </TableCell>
                   </TableCell>
-                  <TableCell>
+                  <TableCell sx={{ py: 1 }}>
                     {field.hasIndex ? (
                     {field.hasIndex ? (
                       <Switch
                       <Switch
                         checked={field.indexMmapEnabled}
                         checked={field.indexMmapEnabled}
@@ -265,12 +252,6 @@ const EditMmapDialog: FC<EditMmapProps> = props => {
           </Table>
           </Table>
         </Box>
         </Box>
       }
       }
-      confirmDisabled={noChange || notReleased}
-      confirmLabel={btnTrans('confirm')}
-      confirmDisabledTooltip={
-        notReleased ? collectionTrans('mmapCollectionNotReleasedTooltip') : ''
-      }
-      handleConfirm={handleConfirm}
     />
     />
   );
   );
 };
 };

+ 1 - 0
client/src/pages/dialogs/create/rows/ScalarFieldRow.tsx

@@ -121,6 +121,7 @@ const ScalarFieldRow: FC<ScalarFieldRowProps> = ({
           onChange={(id, max_capacity, isValid) => {
           onChange={(id, max_capacity, isValid) => {
             onFieldChange(id, { max_capacity }, isValid);
             onFieldChange(id, { max_capacity }, isValid);
           }}
           }}
+          label={collectionTrans('maxCapacity')}
         />
         />
       )}
       )}
 
 

+ 0 - 1
client/src/pages/dialogs/insert/Dialog.tsx

@@ -1,4 +1,3 @@
-import { Theme } from '@mui/material';
 import {
 import {
   FC,
   FC,
   ReactElement,
   ReactElement,

+ 11 - 10
client/src/pages/home/DatabaseCard.tsx

@@ -41,7 +41,6 @@ const DatabaseCard: FC<DatabaseCardProps> = ({
   const theme = useTheme();
   const theme = useTheme();
   const DbIcon = icons.database;
   const DbIcon = icons.database;
   const DeleteIcon = icons.delete;
   const DeleteIcon = icons.delete;
-  const PlusIcon = icons.add;
   const ZillizIcon = icons.zilliz;
   const ZillizIcon = icons.zilliz;
 
 
   const onClick = async () => {
   const onClick = async () => {
@@ -72,31 +71,33 @@ const DatabaseCard: FC<DatabaseCardProps> = ({
           color: theme => theme.palette.text.primary,
           color: theme => theme.palette.text.primary,
           padding: 2,
           padding: 2,
           border: theme => `1px solid ${theme.palette.divider}`,
           border: theme => `1px solid ${theme.palette.divider}`,
-          minWidth: '168px',
-          minHeight: '168px',
+          minWidth: '128px',
+          minHeight: '128px',
           cursor: 'pointer',
           cursor: 'pointer',
           borderRadius: 2,
           borderRadius: 2,
           '&:hover': {
           '&:hover': {
-            boxShadow: '0px 0px 4px 0px #00000029',
             borderColor: theme => theme.palette.primary.main,
             borderColor: theme => theme.palette.primary.main,
           },
           },
           ...(isActive && {
           ...(isActive && {
-            boxShadow: '0px 0px 4px 0px #00000029',
             borderColor: theme => theme.palette.primary.main,
             borderColor: theme => theme.palette.primary.main,
           }),
           }),
         }}
         }}
         onClick={onClick}
         onClick={onClick}
       >
       >
         <>
         <>
-          {isManaged ? <ZillizIcon /> : <DbIcon />}
+          {isManaged ? (
+            <ZillizIcon />
+          ) : (
+            <DbIcon sx={{ width: 24, height: 24 }} />
+          )}
           <Typography
           <Typography
             variant="h3"
             variant="h3"
             sx={{
             sx={{
-              fontSize: '20px',
-              lineHeight: '24px',
-              fontWeight: 'bold',
+              fontSize: '16px',
+              lineHeight: '1.3',
+              fontWeight: '500',
               mb: 1,
               mb: 1,
-              maxWidth: '168px',
+              maxWidth: '128px',
               wordBreak: 'break-all',
               wordBreak: 'break-all',
               '& svg': {
               '& svg': {
                 verticalAlign: '-3px',
                 verticalAlign: '-3px',

+ 4 - 3
client/src/pages/home/Home.tsx

@@ -16,6 +16,7 @@ import CreateDatabaseDialog from '../dialogs/CreateDatabaseDialog';
 import icons from '@/components/icons/Icons';
 import icons from '@/components/icons/Icons';
 import SysCard from './SysCard';
 import SysCard from './SysCard';
 import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
+import Wrapper from '@/components/layout/Wrapper';
 
 
 const Home = () => {
 const Home = () => {
   useNavigationHook(ALL_ROUTER_TYPES.HOME);
   useNavigationHook(ALL_ROUTER_TYPES.HOME);
@@ -83,7 +84,7 @@ const Home = () => {
   };
   };
 
 
   return (
   return (
-    <Box className="page-wrapper" sx={{ color: 'inherit' }}>
+    <Wrapper className="page-wrapper">
       <Box
       <Box
         sx={{
         sx={{
           width: '90%',
           width: '90%',
@@ -140,7 +141,7 @@ const Home = () => {
               display: 'flex',
               display: 'flex',
               flexWrap: 'wrap',
               flexWrap: 'wrap',
               flexGrow: 0,
               flexGrow: 0,
-              gap: 2,
+              gap: 1.5,
             }}
             }}
           >
           >
             {databases.map(db => {
             {databases.map(db => {
@@ -248,7 +249,7 @@ const Home = () => {
           )}
           )}
         </>
         </>
       )}
       )}
-    </Box>
+    </Wrapper>
   );
   );
 };
 };
 
 

+ 0 - 3
client/src/pages/home/SysCard.tsx

@@ -21,9 +21,6 @@ const SysCard = (data: {
         flexDirection: 'column',
         flexDirection: 'column',
         alignItems: 'flex-start',
         alignItems: 'flex-start',
         transition: 'box-shadow 0.2s',
         transition: 'box-shadow 0.2s',
-        '&:hover': {
-          boxShadow: '0px 0px 4px 0px #00000029',
-        },
         '& a': {
         '& a': {
           textDecoration: 'none',
           textDecoration: 'none',
           color: theme.palette.text.primary,
           color: theme.palette.text.primary,

+ 0 - 6
client/src/pages/index.tsx

@@ -95,12 +95,6 @@ function Index() {
         <Box
         <Box
           sx={{
           sx={{
             display: 'flex',
             display: 'flex',
-            '& .active path': {
-              fill: theme => theme.palette.text.primary,
-            },
-            '& .normal path': {
-              fill: theme => theme.palette.primary.main,
-            },
           }}
           }}
         >
         >
           <NavMenu
           <NavMenu

+ 4 - 2
client/src/pages/play/Play.tsx

@@ -167,7 +167,7 @@ const Play: FC = () => {
         overflow: 'hidden',
         overflow: 'hidden',
         borderRadius: 8,
         borderRadius: 8,
         height: '100vh',
         height: '100vh',
-        padding: theme.spacing(2),
+        padding: theme.spacing(1.5),
       }}
       }}
     >
     >
       <Paper
       <Paper
@@ -177,6 +177,7 @@ const Play: FC = () => {
           padding: 0,
           padding: 0,
           display: 'flex',
           display: 'flex',
           flexDirection: 'column',
           flexDirection: 'column',
+          border: `1px solid ${theme.palette.divider}`,
         }}
         }}
       >
       >
         <Box
         <Box
@@ -199,9 +200,10 @@ const Play: FC = () => {
         elevation={0}
         elevation={0}
         sx={{
         sx={{
           flex: 1,
           flex: 1,
-          marginLeft: theme.spacing(2),
+          marginLeft: theme.spacing(1.5),
           display: 'flex',
           display: 'flex',
           overflow: 'hidden',
           overflow: 'hidden',
+          border: `1px solid ${theme.palette.divider}`,
         }}
         }}
       >
       >
         <JSONEditor value={content || `{}`} editable={false} />
         <JSONEditor value={content || `{}`} editable={false} />

+ 2 - 2
client/src/pages/system/NodeListView.tsx

@@ -160,7 +160,7 @@ const NodeListView: FC<NodeListViewProps> = props => {
     <Box
     <Box
       sx={{
       sx={{
         overflow: 'hidden',
         overflow: 'hidden',
-        padding: '0 16px',
+        padding: '0 12px',
         display: 'flex',
         display: 'flex',
         flexDirection: 'column',
         flexDirection: 'column',
         border: `1px solid ${theme.palette.divider}`,
         border: `1px solid ${theme.palette.divider}`,
@@ -188,7 +188,7 @@ const NodeListView: FC<NodeListViewProps> = props => {
       </Box>
       </Box>
       <Box
       <Box
         sx={{
         sx={{
-          height: `calc(100vh - 120px)`,
+          height: `calc(100vh - 106px)`,
           display: 'flex',
           display: 'flex',
           gap: 1, // theme.spacing(1) is 8px by default, so 1 means 8px
           gap: 1, // theme.spacing(1) is 8px by default, so 1 means 8px
         }}
         }}

+ 1 - 3
client/src/pages/system/SystemView.tsx

@@ -46,14 +46,13 @@ const SystemView: any = () => {
   return (
   return (
     <Box
     <Box
       sx={theme => ({
       sx={theme => ({
-        margin: '16px',
+        margin: '12px',
         position: 'relative',
         position: 'relative',
         display: 'flex',
         display: 'flex',
         height: 'calc(100vh - 80px)',
         height: 'calc(100vh - 80px)',
         overflow: 'hidden',
         overflow: 'hidden',
         border: `1px solid ${theme.palette.divider}`,
         border: `1px solid ${theme.palette.divider}`,
         borderRadius: 2,
         borderRadius: 2,
-        boxShadow: '0 0 10px 0 rgba(0,0,0,0.1)',
       })}
       })}
     >
     >
       <Box
       <Box
@@ -69,7 +68,6 @@ const SystemView: any = () => {
             width: '70%',
             width: '70%',
             background: theme.palette.background.paper,
             background: theme.palette.background.paper,
             borderRadius: 2,
             borderRadius: 2,
-            boxShadow: '0 0 10px 0 rgba(0,0,0,0.1)',
           })}
           })}
         >
         >
           <Topo
           <Topo

+ 1 - 4
client/src/pages/user/PrivilegeGroups.tsx

@@ -196,10 +196,7 @@ const PrivilegeGroups = () => {
   };
   };
 
 
   return (
   return (
-    <Wrapper
-      sx={{ height: 'calc(100vh - 160px)' }}
-      hasPermission={hasPermission}
-    >
+    <Wrapper hasPermission={hasPermission}>
       <AttuGrid
       <AttuGrid
         toolbarConfigs={[]}
         toolbarConfigs={[]}
         colDefinitions={colDefinitions}
         colDefinitions={colDefinitions}

+ 13 - 13
client/src/pages/user/Roles.tsx

@@ -1,5 +1,4 @@
 import { useContext, useEffect, useState } from 'react';
 import { useContext, useEffect, useState } from 'react';
-import { Theme } from '@mui/material';
 import { List, ListItemButton, ListItemText, Box } from '@mui/material';
 import { List, ListItemButton, ListItemText, Box } from '@mui/material';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import { UserService } from '@/http';
 import { UserService } from '@/http';
@@ -213,24 +212,20 @@ const Roles = () => {
   };
   };
 
 
   return (
   return (
-    <Wrapper
-      sx={{ display: 'flex', flexDirection: 'column', overflow: 'auto' }}
-      hasPermission={hasPermission}
-    >
+    <Wrapper hasPermission={hasPermission}>
       <CustomToolBar toolbarConfigs={toolbarConfigs} />
       <CustomToolBar toolbarConfigs={toolbarConfigs} />
 
 
-      <Box sx={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
+      <Box sx={{ display: 'flex', flexDirection: 'row', gap: 1 }}>
         <Box
         <Box
           sx={theme => ({
           sx={theme => ({
-            border: `1px solid ${(theme as any).palette.divider}`,
-            borderRadius: '8px',
-            backgroundColor: (theme as any).palette.background.light,
+            borderRadius: theme.shape.borderRadius,
+            backgroundColor: theme.palette.background.lightGrey,
             width: '16%',
             width: '16%',
-            height: 'calc(100vh - 200px)',
-            overflow: 'auto',
-            color: (theme as any).palette.text.primary,
-            boxShadow: (theme as any).shadows[1],
             minWidth: '200px',
             minWidth: '200px',
+            height: 'calc(100vh - 202px)',
+            overflow: 'auto',
+            color: theme.palette.text.primary,
+            padding: theme.spacing(1),
           })}
           })}
         >
         >
           <List>
           <List>
@@ -242,6 +237,10 @@ const Roles = () => {
                   selectedRole[0].roleName === role.roleName
                   selectedRole[0].roleName === role.roleName
                 }
                 }
                 onClick={() => handleRoleClick(role)}
                 onClick={() => handleRoleClick(role)}
+                sx={theme => ({
+                  borderRadius: theme.shape.borderRadius,
+                  mb: 0.5,
+                })}
               >
               >
                 <ListItemText primary={role.roleName} />
                 <ListItemText primary={role.roleName} />
               </ListItemButton>
               </ListItemButton>
@@ -252,6 +251,7 @@ const Roles = () => {
           sx={{
           sx={{
             overflow: 'auto',
             overflow: 'auto',
             width: 'calc(84% - 16px)',
             width: 'calc(84% - 16px)',
+            flexGrow: 1,
           }}
           }}
         >
         >
           <D3PrivilegeTree
           <D3PrivilegeTree

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

@@ -249,10 +249,7 @@ const Users = () => {
   };
   };
 
 
   return (
   return (
-    <Wrapper
-      sx={{ height: 'calc(100vh - 160px)' }}
-      hasPermission={hasPermission}
-    >
+    <Wrapper hasPermission={hasPermission}>
       <AttuGrid
       <AttuGrid
         toolbarConfigs={toolbarConfigs}
         toolbarConfigs={toolbarConfigs}
         colDefinitions={colDefinitions}
         colDefinitions={colDefinitions}

+ 1 - 2
client/src/pages/user/UsersAndRoles.tsx

@@ -45,8 +45,7 @@ const Users = () => {
         display: 'flex',
         display: 'flex',
         flexDirection: 'row',
         flexDirection: 'row',
         background: theme.palette.background.paper,
         background: theme.palette.background.paper,
-        padding: theme.spacing(0.5, 2),
-        boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.1)',
+        padding: theme.spacing(0.5, 1.5),
         borderRadius: 2,
         borderRadius: 2,
         border: `1px solid ${theme.palette.divider}`,
         border: `1px solid ${theme.palette.divider}`,
       })}
       })}

+ 1 - 9
client/src/styles/common.css

@@ -1,11 +1,3 @@
-/* reset some elements styles */
-fieldset {
-  border: 0;
-  padding: 0;
-  margin: 0;
-  min-width: 0;
-}
-
 /* horizontal and vertical center */
 /* horizontal and vertical center */
 .flex-center {
 .flex-center {
   display: flex;
   display: flex;
@@ -25,7 +17,7 @@ fieldset {
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
 
 
-  margin: 16px;
+  margin: 12px;
 }
 }
 
 
 .page-empty-card {
 .page-empty-card {

+ 183 - 40
client/src/styles/theme.ts

@@ -1,5 +1,4 @@
 import { PaletteMode } from '@mui/material';
 import { PaletteMode } from '@mui/material';
-import { grey } from '@mui/material/colors';
 import { Theme } from '@mui/material/styles';
 import { Theme } from '@mui/material/styles';
 import { ButtonProps } from '@mui/material/Button';
 import { ButtonProps } from '@mui/material/Button';
 
 
@@ -17,43 +16,110 @@ declare module '@mui/material/styles' {
   }
   }
   interface Palette {
   interface Palette {
     background: TypeBackground;
     background: TypeBackground;
+    neutral: {
+      50: string;
+      100: string;
+      200: string;
+      300: string;
+      400: string;
+      500: string;
+      600: string;
+      700: string;
+      800: string;
+      900: string;
+    };
   }
   }
 }
 }
 
 
 const colors = {
 const colors = {
   primary: {
   primary: {
-    main: '#0ACE82',
+    main: '#09B572',
     light: {
     light: {
       light: '#f0fdf4',
       light: '#f0fdf4',
       dark: '#1b4332',
       dark: '#1b4332',
     },
     },
     dark: {
     dark: {
-      light: '#08a568',
-      dark: '#078b63',
+      light: '#07925E',
+      dark: '#067A50',
     },
     },
   },
   },
   secondary: {
   secondary: {
-    main: '#1890FF',
+    main: '#1272CC',
     light: {
     light: {
       light: '#E6F4FF',
       light: '#E6F4FF',
       dark: '#003A8C',
       dark: '#003A8C',
     },
     },
     dark: {
     dark: {
-      light: '#096DD9',
-      dark: '#0050B3',
+      light: '#0D5AA3',
+      dark: '#0A4680',
     },
     },
   },
   },
   error: {
   error: {
-    main: '#ff4605',
+    main: '#D93C00',
     light: {
     light: {
-      light: '#ff8f68',
-      dark: '#ff6a3a',
+      light: '#FFEBE6',
+      dark: '#7A1C00',
     },
     },
     dark: {
     dark: {
-      light: '#cd3804',
-      dark: '#b33900',
+      light: '#B33200',
+      dark: '#8A2700',
     },
     },
   },
   },
+  warning: {
+    main: '#FF9800',
+    light: {
+      light: '#FFF4E5',
+      dark: '#7A4A00',
+    },
+    dark: {
+      light: '#E68A00',
+      dark: '#B36B00',
+    },
+  },
+  info: {
+    main: '#2196F3',
+    light: {
+      light: '#E6F4FF',
+      dark: '#0D3C61',
+    },
+    dark: {
+      light: '#1A7BC9',
+      dark: '#145FA0',
+    },
+  },
+  success: {
+    main: '#4CAF50',
+    light: {
+      light: '#E8F5E9',
+      dark: '#1B5E20',
+    },
+    dark: {
+      light: '#3D8B40',
+      dark: '#2E7D32',
+    },
+  },
+  neutral: {
+    50: '#F9FAFB',
+    100: '#F3F4F6',
+    200: '#E5E7EB',
+    300: '#D1D5DB',
+    400: '#9CA3AF',
+    500: '#6B7280',
+    600: '#4B5563',
+    700: '#374151',
+    800: '#1F2937',
+    900: '#111827',
+  },
+  background: {
+    default: '#F3F4F6',
+    paper: '#FFFFFF',
+  },
+  text: {
+    primary: '#111827',
+    secondary: '#4B5563',
+    disabled: '#9CA3AF',
+  },
+  divider: '#E5E7EB',
 };
 };
 
 
 const spacing = (factor: number) => `${8 * factor}px`;
 const spacing = (factor: number) => `${8 * factor}px`;
@@ -124,7 +190,7 @@ const typography = {
   button: {
   button: {
     textTransform: 'initial',
     textTransform: 'initial',
     lineHeight: '16px',
     lineHeight: '16px',
-    fontWeight: 'bold',
+    fontWeight: '700',
   },
   },
 };
 };
 
 
@@ -158,12 +224,44 @@ const getCommonThemes = (mode: PaletteMode) => ({
         mode === 'light' ? colors.error.light.light : colors.error.light.dark,
         mode === 'light' ? colors.error.light.light : colors.error.light.dark,
       dark: mode === 'light' ? colors.error.dark.light : colors.error.dark.dark,
       dark: mode === 'light' ? colors.error.dark.light : colors.error.dark.dark,
     },
     },
+    warning: {
+      main: colors.warning.main,
+      light:
+        mode === 'light'
+          ? colors.warning.light.light
+          : colors.warning.light.dark,
+      dark:
+        mode === 'light' ? colors.warning.dark.light : colors.warning.dark.dark,
+    },
+    info: {
+      main: colors.info.main,
+      light:
+        mode === 'light' ? colors.info.light.light : colors.info.light.dark,
+      dark: mode === 'light' ? colors.info.dark.light : colors.info.dark.dark,
+    },
+    success: {
+      main: colors.success.main,
+      light:
+        mode === 'light'
+          ? colors.success.light.light
+          : colors.success.light.dark,
+      dark:
+        mode === 'light' ? colors.success.dark.light : colors.success.dark.dark,
+    },
+    neutral: colors.neutral,
     background: {
     background: {
-      default: mode === 'light' ? '#f5f5f5' : '#121212',
-      paper: mode === 'light' ? '#ffffff' : '#1e1e1e',
-      grey: mode === 'light' ? grey[200] : grey[800],
-      lightGrey: mode === 'light' ? grey[100] : grey[800],
+      default:
+        mode === 'light' ? colors.background.default : colors.neutral[900],
+      paper: mode === 'light' ? colors.background.paper : colors.neutral[800],
+      grey: mode === 'light' ? colors.neutral[200] : colors.neutral[700],
+      lightGrey: mode === 'light' ? colors.neutral[100] : colors.neutral[800],
+    },
+    text: {
+      primary: mode === 'light' ? colors.text.primary : colors.neutral[50],
+      secondary: mode === 'light' ? colors.text.secondary : colors.neutral[400],
+      disabled: mode === 'light' ? colors.text.disabled : colors.neutral[600],
     },
     },
+    divider: mode === 'light' ? colors.divider : colors.neutral[700],
   },
   },
   spacing,
   spacing,
 });
 });
@@ -181,6 +279,9 @@ export const getAttuTheme = (mode: PaletteMode) => {
         },
         },
       },
       },
       MuiButton: {
       MuiButton: {
+        defaultProps: {
+          disableRipple: true,
+        },
         styleOverrides: {
         styleOverrides: {
           root: ({
           root: ({
             theme,
             theme,
@@ -233,6 +334,46 @@ export const getAttuTheme = (mode: PaletteMode) => {
           },
           },
         ],
         ],
       },
       },
+      MuiTab: {
+        defaultProps: {
+          disableRipple: true,
+        },
+      },
+      MuiMenuItem: {
+        defaultProps: {
+          disableRipple: true,
+        },
+        styleOverrides: {
+          root: {
+            fontSize: '14px',
+            padding: '8px 16px',
+            minHeight: '36px',
+            transition: 'background-color 0.2s ease',
+            '&:hover': {
+              backgroundColor: isLight
+                ? 'rgba(10, 206, 130, 0.08)'
+                : 'rgba(10, 206, 130, 0.16)',
+            },
+            '&.Mui-selected': {
+              backgroundColor: isLight
+                ? 'rgba(10, 206, 130, 0.16)'
+                : 'rgba(10, 206, 130, 0.24)',
+              '&:hover': {
+                backgroundColor: isLight
+                  ? 'rgba(10, 206, 130, 0.24)'
+                  : 'rgba(10, 206, 130, 0.32)',
+              },
+            },
+            '&.Mui-disabled': {
+              opacity: 0.6,
+            },
+            '& .MuiListItemIcon-root': {
+              color: isLight ? '#666' : '#aaa',
+              minWidth: '36px',
+            },
+          },
+        },
+      },
       MuiDialog: {
       MuiDialog: {
         styleOverrides: {
         styleOverrides: {
           paper: {
           paper: {
@@ -403,34 +544,36 @@ export const getAttuTheme = (mode: PaletteMode) => {
           },
           },
         },
         },
       },
       },
-      MuiMenuItem: {
+      MuiSnackbar: {
         styleOverrides: {
         styleOverrides: {
           root: {
           root: {
-            fontSize: '14px',
-            padding: '8px 16px',
-            minHeight: '36px',
-            transition: 'background-color 0.2s ease',
-            '&:hover': {
-              backgroundColor: isLight
-                ? 'rgba(10, 206, 130, 0.08)'
-                : 'rgba(10, 206, 130, 0.16)',
+            '&.MuiSnackbar-anchorOriginTopCenter': {
+              top: { xs: 56, md: 72 },
             },
             },
-            '&.Mui-selected': {
-              backgroundColor: isLight
-                ? 'rgba(10, 206, 130, 0.16)'
-                : 'rgba(10, 206, 130, 0.24)',
-              '&:hover': {
-                backgroundColor: isLight
-                  ? 'rgba(10, 206, 130, 0.24)'
-                  : 'rgba(10, 206, 130, 0.32)',
-              },
+            '&.MuiSnackbar-anchorOriginTopRight': {
+              top: { xs: 56, md: 72 },
+              right: (theme: Theme) => theme.spacing(1),
             },
             },
-            '&.Mui-disabled': {
-              opacity: 0.6,
+          },
+        },
+      },
+      MuiAlert: {
+        styleOverrides: {
+          root: {
+            padding: '0 12px',
+            borderRadius: '4px',
+            display: 'flex',
+            alignItems: 'center',
+            color: '#fff',
+            gap: '4px',
+            '& .MuiAlert-action': {
+              padding: '0',
             },
             },
-            '& .MuiListItemIcon-root': {
-              color: isLight ? '#666' : '#aaa',
-              minWidth: '36px',
+            '& .MuiAlert-icon': {
+              marginRight: '4px',
+            },
+            '& svg': {
+              fontSize: '16px',
             },
             },
           },
           },
         },
         },