Browse Source

feat(database): update home page UI and ensure 'default' database always appears first, others sorted by created_timestamp desc (#880)

Signed-off-by: ryjiang <jiangruiyi@gmail.com>
ryjiang 1 month ago
parent
commit
38121ac0b6

+ 0 - 44
client/src/pages/home/DatabaseCard.tsx

@@ -6,8 +6,6 @@ import { MilvusService, DatabaseService } from '@/http';
 import icons from '@/components/icons/Icons';
 import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
 import { rootContext, authContext } from '@/context';
-import CreateDatabaseDialog from '../dialogs/CreateDatabaseDialog';
-import { CREATE_DB } from './Home';
 import type { DatabaseObject } from '@server/types';
 import IconButton from '@mui/material/IconButton';
 import Tooltip from '@mui/material/Tooltip';
@@ -61,48 +59,6 @@ const DatabaseCard: FC<DatabaseCardProps> = ({
     handleCloseDialog();
   };
 
-  // empty database => create new database
-  if (database.name === CREATE_DB.name) {
-    return (
-      <Box
-        component="section"
-        className={wrapperClass}
-        sx={{
-          position: 'relative',
-          display: 'flex',
-          flexDirection: 'column',
-          gap: 1,
-          backgroundColor: theme => theme.palette.background.paper,
-          color: theme => theme.palette.text.primary,
-          padding: 2,
-          border: theme => `1px dashed ${theme.palette.primary.main}`,
-          minWidth: '168px',
-          minHeight: '168px',
-          cursor: 'pointer',
-          borderRadius: 2,
-          justifyContent: 'center',
-          alignItems: 'center',
-        }}
-        onClick={() => {
-          if (isServerless) {
-            window.open('https://cloud.zilliz.com/', '_blank');
-            return;
-          }
-          setDialog({
-            open: true,
-            type: 'custom',
-            params: {
-              component: <CreateDatabaseDialog />,
-            },
-          });
-        }}
-      >
-        <PlusIcon />
-        <Typography variant="h6">{dbTrans('createTitle')}</Typography>
-      </Box>
-    );
-  }
-
   return (
     <Box component="section" className={wrapperClass}>
       <Box

+ 125 - 58
client/src/pages/home/Home.tsx

@@ -1,46 +1,21 @@
 import { useContext, useMemo } from 'react';
-import { Theme, Typography } from '@mui/material';
+import { Typography, Box, Button } from '@mui/material';
 import { useTranslation } from 'react-i18next';
 import dayjs from 'dayjs';
-import { dataContext, systemContext } from '@/context';
+import {
+  dataContext,
+  systemContext,
+  authContext,
+  rootContext,
+} from '@/context';
 import { MILVUS_DEPLOY_MODE } from '@/consts';
 import { useNavigationHook } from '@/hooks';
 import { ALL_ROUTER_TYPES } from '@/router/consts';
 import DatabaseCard from './DatabaseCard';
+import CreateDatabaseDialog from '../dialogs/CreateDatabaseDialog';
+import icons from '@/components/icons/Icons';
 import SysCard from './SysCard';
 import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
-import { makeStyles } from '@mui/styles';
-
-const useStyles = makeStyles((theme: Theme) => ({
-  homeWrapper: {
-    gap: theme.spacing(2),
-    '& h4': {
-      marginBottom: theme.spacing(2),
-    },
-    color: theme.palette.text.primary,
-  },
-
-  section: {
-    width: '85%',
-    marginBottom: theme.spacing(2),
-  },
-  cardWrapper: {
-    display: 'flex',
-    flexWrap: 'wrap',
-    flexGrow: 0,
-    gap: theme.spacing(2),
-  },
-}));
-
-export const CREATE_DB = {
-  name: '___new___',
-  collections: [],
-  createdTime: 0,
-  db_name: '___new___',
-  properties: [],
-  created_timestamp: 0,
-  dbID: 0,
-};
 
 const Home = () => {
   useNavigationHook(ALL_ROUTER_TYPES.HOME);
@@ -53,7 +28,6 @@ const Home = () => {
     fetchDatabases,
   } = useContext(dataContext);
   const { data } = useContext(systemContext);
-  const classes = useStyles();
   const { t: homeTrans } = useTranslation('home');
   const { t: databaseTrans } = useTranslation('database');
 
@@ -90,16 +64,86 @@ const Home = () => {
     return `${duration.toFixed(2)} ${unit}`;
   }, [data.rootCoord]);
 
+  const { isServerless } = useContext(authContext);
+  const { setDialog } = useContext(rootContext);
+  const PlusIcon = icons.add;
+
+  const handleCreateDbClick = () => {
+    if (isServerless) {
+      window.open('https://cloud.zilliz.com/', '_blank');
+      return;
+    }
+    setDialog({
+      open: true,
+      type: 'custom',
+      params: {
+        component: <CreateDatabaseDialog />,
+      },
+    });
+  };
+
   return (
-    <section className={`page-wrapper  ${classes.homeWrapper}`}>
-      <section className={classes.section}>
-        <Typography variant="h4">{databaseTrans('databases')}</Typography>
+    <Box className="page-wrapper" sx={{ color: 'inherit' }}>
+      <Box
+        sx={{
+          width: '90%',
+          mb: 2,
+        }}
+      >
+        <Box display="flex" alignItems="center" mb={2}>
+          <Box display="flex" alignItems="center">
+            <Typography
+              variant="h4"
+              sx={{
+                mr: 1,
+                position: 'relative',
+                top: 8,
+                mb: 2,
+                color: theme => theme.palette.text.primary,
+              }}
+            >
+              {databaseTrans('databases')}
+            </Typography>
+            <Typography
+              component="span"
+              variant="subtitle1"
+              color="textSecondary"
+              sx={{ position: 'relative', top: 1, mr: 2 }}
+            >
+              ({databases.length})
+            </Typography>
+          </Box>
+          <Button
+            variant="contained"
+            color="primary"
+            size="small"
+            onClick={handleCreateDbClick}
+            sx={{
+              ml: 0,
+              minWidth: 24,
+              width: 24,
+              height: 24,
+              p: 0,
+              display: 'flex',
+              alignItems: 'center',
+              justifyContent: 'center',
+            }}
+          >
+            <PlusIcon sx={{ fontSize: 20 }} />
+          </Button>
+        </Box>
         {loadingDatabases ? (
           <StatusIcon type={LoadingType.CREATING} />
         ) : (
-          <div className={classes.cardWrapper}>
+          <Box
+            sx={{
+              display: 'flex',
+              flexWrap: 'wrap',
+              flexGrow: 0,
+              gap: 2,
+            }}
+          >
             {databases.map(db => {
-              // if the database is the current database, using client side collections data to avoid more requests
               if (db.name === database) {
                 db.collections = collections.map(c => c.collection_name);
               }
@@ -113,21 +157,32 @@ const Home = () => {
                 />
               );
             })}
-            <DatabaseCard
-              database={CREATE_DB}
-              setDatabase={setDatabase}
-              fetchDatabases={fetchDatabases}
-              key={CREATE_DB.name}
-            />
-          </div>
+          </Box>
         )}
-      </section>
+      </Box>
 
       {data?.systemInfo && (
         <>
-          <section className={classes.section}>
-            <Typography variant="h4">{homeTrans('sysInfo')}</Typography>
-            <div className={classes.cardWrapper}>
+          <Box
+            sx={{
+              width: '90%',
+              marginBottom: 2,
+            }}
+          >
+            <Typography
+              variant="h4"
+              sx={{ mb: 2, color: theme => theme.palette.text.primary }}
+            >
+              {homeTrans('sysInfo')}
+            </Typography>
+            <Box
+              sx={{
+                display: 'flex',
+                flexWrap: 'wrap',
+                flexGrow: 0,
+                gap: 2,
+              }}
+            >
               <SysCard
                 title={'Milvus Version'}
                 count={data?.systemInfo?.build_version}
@@ -155,12 +210,24 @@ const Home = () => {
                 count={data?.roles?.length}
                 link="roles"
               />
-            </div>
-          </section>
+            </Box>
+          </Box>
 
           {data?.deployMode === MILVUS_DEPLOY_MODE.DISTRIBUTED && (
-            <section className={classes.section}>
-              <div className={classes.cardWrapper}>
+            <Box
+              sx={{
+                width: '90%',
+                marginBottom: 2,
+              }}
+            >
+              <Box
+                sx={{
+                  display: 'flex',
+                  flexWrap: 'wrap',
+                  flexGrow: 0,
+                  gap: 2,
+                }}
+              >
                 <SysCard
                   title={homeTrans('dataNodes')}
                   count={data?.dataNodes?.length}
@@ -176,12 +243,12 @@ const Home = () => {
                   count={data?.queryNodes?.length}
                   link="system"
                 />
-              </div>
-            </section>
+              </Box>
+            </Box>
           )}
         </>
       )}
-    </section>
+    </Box>
   );
 };
 

+ 13 - 10
server/src/database/databases.controller.ts

@@ -52,16 +52,19 @@ export class DatabasesController {
   async listDatabases(req: Request, res: Response, next: NextFunction) {
     try {
       const result = await this.databasesService.listDatabase(req.clientId);
-      result.sort((a: DatabaseObject, b: DatabaseObject) => {
-        if (a.name === 'default') {
-          return -1; // 'default' comes before other strings
-        } else if (b.name === 'default') {
-          return 1; // 'default' comes after other strings
-        } else {
-          return a.name.localeCompare(b.name); // sort other strings alphabetically
-        }
-      });
-      res.send(result);
+
+      const defaultDb = result.find(
+        (db: DatabaseObject) => db.name === 'default'
+      );
+      const otherDbs = result
+        .filter((db: DatabaseObject) => db.name !== 'default')
+        .sort((a: DatabaseObject, b: DatabaseObject) => {
+          return Number(b.created_timestamp) - Number(a.created_timestamp);
+        });
+
+      const sortedResult = defaultDb ? [defaultDb, ...otherDbs] : otherDbs;
+
+      res.send(sortedResult);
     } catch (error) {
       next(error);
     }