Browse Source

refactor: refactor UI route (#903)

* part1

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

* finish refactor

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

---------

Signed-off-by: shanghaikid <jiangruiyi@gmail.com>
ryjiang 1 month ago
parent
commit
64dc0d5201

+ 0 - 1
client/src/components/menu/NavMenu.tsx

@@ -151,5 +151,4 @@ const NavMenu: FC<NavMenuType> = props => {
     </List>
   );
 };
-
 export default NavMenu;

+ 14 - 12
client/src/components/menu/Types.ts

@@ -2,19 +2,21 @@ type CustomIcon = (
   props?: any
 ) => React.ReactElement<any, string | React.JSXElementConstructor<any>>;
 
-export type NavMenuItem = {
-  icon: CustomIcon;
-  iconActiveClass?: string;
-  iconNormalClass?: string;
+export interface NavMenuItem {
+  icon: any;
   label: string;
+  key?: string;
   onClick?: () => void;
-  children?: NavMenuItem[];
-};
+  iconActiveClass?: string;
+  iconNormalClass?: string;
+}
 
-export type NavMenuType = {
-  defaultActive?: string;
-  defaultOpen?: { [x: string]: boolean };
-  width: string;
+export interface NavMenuType {
   data: NavMenuItem[];
-  versionInfo: { attu: string; sdk: string };
-};
+  defaultActive?: string;
+  defaultOpen?: Record<string, boolean>;
+  width?: string;
+  versionInfo: {
+    attu: string;
+  };
+}

+ 268 - 0
client/src/config/routes.ts

@@ -0,0 +1,268 @@
+import { ReactNode } from 'react';
+import { NavMenuItem } from '@/components/menu/Types';
+import icons from '@/components/icons/Icons';
+import Databases from '@/pages/databases/Databases';
+import Users from '@/pages/user/UsersAndRoles';
+import System from '@/pages/system/SystemView';
+import Play from '@/pages/play/Play';
+import Overview from '@/pages/home/Home';
+
+// Route path constants
+export const ROUTE_PATHS = {
+  HOME: '/',
+  DATABASES: 'databases',
+  COLLECTIONS: 'collections',
+  COLLECTION_DETAIL: 'collection-detail',
+  USERS: 'users',
+  ROLES: 'roles',
+  PRIVILEGE_GROUPS: 'privilege-groups',
+  PLAY: 'play',
+  SYSTEM: 'system',
+  CONNECT: 'connect',
+} as const;
+
+export type RoutePath = (typeof ROUTE_PATHS)[keyof typeof ROUTE_PATHS];
+
+// Default navigation configuration
+const DEFAULT_NAV_CONFIG: NavConfig = {
+  showDatabaseSelector: false,
+  navTitleKey: '',
+  useCollectionNameAsTitle: false,
+  backPath: '',
+};
+
+export interface RouteConfig {
+  path: string;
+  element: ReactNode;
+  children?: RouteConfig[];
+}
+
+export interface NavConfig {
+  showDatabaseSelector?: boolean;
+  navTitleKey?: string;
+  useCollectionNameAsTitle?: boolean;
+  backPath?: string;
+}
+
+export interface RouteItem {
+  path: string;
+  element: React.ComponentType;
+  children?: RouteItem[];
+  showInMenu?: boolean;
+  menuConfig?: {
+    icon: any;
+    label: string;
+    key: string;
+  };
+  requiresAuth?: boolean;
+  showWhenNotManagedOrDedicated?: boolean;
+  showWhenNotManaged?: boolean;
+  navConfig?: NavConfig;
+  routerType: RoutePath;
+}
+
+// Database routes configuration
+const databaseRoutes: RouteItem[] = [
+  {
+    path: ROUTE_PATHS.DATABASES,
+    element: Databases,
+    showInMenu: true,
+    menuConfig: {
+      icon: icons.database,
+      label: 'database',
+      key: 'databases',
+    },
+    routerType: ROUTE_PATHS.DATABASES,
+    navConfig: {
+      showDatabaseSelector: true,
+      useCollectionNameAsTitle: true,
+    },
+    children: [
+      {
+        path: ':databaseName',
+        element: Databases,
+        routerType: ROUTE_PATHS.COLLECTIONS,
+        navConfig: {
+          showDatabaseSelector: true,
+          navTitleKey: 'collections',
+        },
+      },
+      {
+        path: ':databaseName/:databasePage',
+        element: Databases,
+        routerType: ROUTE_PATHS.DATABASES,
+        navConfig: {
+          showDatabaseSelector: true,
+          navTitleKey: 'dbAdmin',
+        },
+      },
+      {
+        path: ':databaseName/:collectionName/:collectionPage',
+        element: Databases,
+        routerType: ROUTE_PATHS.COLLECTION_DETAIL,
+        navConfig: {
+          showDatabaseSelector: true,
+          useCollectionNameAsTitle: true,
+        },
+      },
+    ],
+  },
+];
+
+// User management routes
+const userRoutes: RouteItem[] = [
+  {
+    path: ROUTE_PATHS.USERS,
+    element: Users,
+    showInMenu: true,
+    menuConfig: {
+      icon: icons.navPerson,
+      label: 'user',
+      key: 'users',
+    },
+    routerType: ROUTE_PATHS.USERS,
+    navConfig: {
+      navTitleKey: 'user',
+    },
+    showWhenNotManagedOrDedicated: true,
+  },
+  {
+    path: ROUTE_PATHS.ROLES,
+    element: Users,
+    showInMenu: false,
+    routerType: ROUTE_PATHS.USERS,
+    navConfig: {
+      navTitleKey: 'user',
+      backPath: `/${ROUTE_PATHS.USERS}`,
+    },
+    showWhenNotManagedOrDedicated: true,
+  },
+  {
+    path: ROUTE_PATHS.PRIVILEGE_GROUPS,
+    element: Users,
+    showInMenu: false,
+    routerType: ROUTE_PATHS.USERS,
+    navConfig: {
+      navTitleKey: 'user',
+      backPath: `/${ROUTE_PATHS.USERS}`,
+    },
+    showWhenNotManagedOrDedicated: true,
+  },
+];
+
+// Other routes
+const otherRoutes: RouteItem[] = [
+  {
+    path: ROUTE_PATHS.HOME,
+    element: Overview,
+    showInMenu: true,
+    menuConfig: {
+      icon: icons.attu,
+      label: 'overview',
+      key: 'overview',
+    },
+    routerType: ROUTE_PATHS.HOME,
+    navConfig: {
+      navTitleKey: 'welcome',
+    },
+  },
+  {
+    path: ROUTE_PATHS.PLAY,
+    element: Play,
+    showInMenu: true,
+    menuConfig: {
+      icon: icons.code,
+      label: 'play',
+      key: 'play',
+    },
+    routerType: ROUTE_PATHS.PLAY,
+    navConfig: {
+      navTitleKey: 'play',
+    },
+  },
+  {
+    path: ROUTE_PATHS.SYSTEM,
+    element: System,
+    showInMenu: true,
+    menuConfig: {
+      icon: icons.navSystem,
+      label: 'system',
+      key: 'system',
+    },
+    routerType: ROUTE_PATHS.SYSTEM,
+    navConfig: {
+      navTitleKey: 'system',
+    },
+    showWhenNotManaged: true,
+  },
+  {
+    path: ROUTE_PATHS.CONNECT,
+    element: () => null,
+    showInMenu: false,
+    requiresAuth: false,
+    routerType: ROUTE_PATHS.HOME,
+  },
+];
+
+// Combine all routes
+export const routes: RouteItem[] = [
+  // Home should be first
+  ...otherRoutes.filter(route => route.path === ROUTE_PATHS.HOME),
+  // Then databases
+  ...databaseRoutes,
+  // Then users
+  ...userRoutes,
+  // Then other routes (excluding home)
+  ...otherRoutes.filter(route => route.path !== ROUTE_PATHS.HOME),
+];
+
+// Helper function to merge navigation config with defaults
+export const mergeNavConfig = (config?: NavConfig): NavConfig => ({
+  ...DEFAULT_NAV_CONFIG,
+  ...config,
+});
+
+export const getMenuItems = (
+  isManaged: boolean,
+  isDedicated: boolean,
+  database: string,
+  navTrans: (key: string) => string,
+  navigate: (path: string) => void,
+  authReq?: { address: string }
+): NavMenuItem[] => {
+  return routes
+    .filter(route => {
+      if (!route.showInMenu) return false;
+      if (route.showWhenNotManagedOrDedicated && !(!isManaged || isDedicated))
+        return false;
+      if (route.showWhenNotManaged && isManaged) return false;
+      return true;
+    })
+    .map(route => {
+      const menuItem: NavMenuItem = {
+        icon: route.menuConfig?.icon,
+        label: navTrans(route.menuConfig?.label || ''),
+        key: route.menuConfig?.key,
+        onClick: () => {
+          if (route.path === ROUTE_PATHS.DATABASES) {
+            navigate(`/${ROUTE_PATHS.DATABASES}/${database}/collections`);
+          } else {
+            navigate(`/${route.path}`);
+          }
+        },
+      };
+      return menuItem;
+    });
+};
+
+export const getRoutes = (
+  isManaged: boolean,
+  isDedicated: boolean
+): RouteItem[] => {
+  return routes.filter(route => {
+    if (route.showWhenNotManagedOrDedicated && !(!isManaged || isDedicated))
+      return false;
+    if (route.showWhenNotManaged && isManaged) return false;
+    return true;
+  });
+};

+ 15 - 66
client/src/hooks/Navigation.tsx

@@ -2,10 +2,10 @@ import { useContext, useEffect } from 'react';
 import { useTranslation } from 'react-i18next';
 import { navContext } from '@/context';
 import { NavInfo } from '@/router/Types';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { routes, mergeNavConfig, RoutePath } from '@/config/routes';
 
 export const useNavigationHook = (
-  type: ALL_ROUTER_TYPES,
+  type: RoutePath,
   extraParam?: {
     databaseName?: string;
     collectionName?: string;
@@ -18,72 +18,21 @@ export const useNavigationHook = (
   const { collectionName = '', extra } = extraParam || {};
 
   useEffect(() => {
-    const baseNavInfo: Omit<NavInfo, 'navTitle'> = {
-      backPath: '',
-      showDatabaseSelector: false,
-    };
-
-    const navConfigMap: Record<ALL_ROUTER_TYPES, () => NavInfo | undefined> = {
-      [ALL_ROUTER_TYPES.HOME]: () => ({
-        ...baseNavInfo,
-        navTitle: navTrans('welcome'),
-      }),
-
-      [ALL_ROUTER_TYPES.DATABASES]: () => ({
-        ...baseNavInfo,
-        navTitle: collectionName,
-        showDatabaseSelector: true,
-        ...(collectionName ? { extra } : {}),
-      }),
-
-      [ALL_ROUTER_TYPES.COLLECTIONS]: () => ({
-        ...baseNavInfo,
-        navTitle: navTrans('collections'),
-        showDatabaseSelector: true,
-      }),
-
-      [ALL_ROUTER_TYPES.COLLECTION_DETAIL]: () => ({
-        ...baseNavInfo,
-        navTitle: collectionName || navTrans('collection'),
-        showDatabaseSelector: true,
-        ...(collectionName ? { extra } : {}),
-      }),
-
-      [ALL_ROUTER_TYPES.SEARCH]: () => ({
-        ...baseNavInfo,
-        navTitle: navTrans('search'),
-        showDatabaseSelector: true,
-      }),
-
-      [ALL_ROUTER_TYPES.SYSTEM]: () => ({
-        ...baseNavInfo,
-        navTitle: navTrans('system'),
-      }),
-
-      [ALL_ROUTER_TYPES.USER]: () => ({
-        ...baseNavInfo,
-        navTitle: navTrans('user'),
-      }),
-
-      [ALL_ROUTER_TYPES.DB_ADMIN]: () => ({
-        ...baseNavInfo,
-        navTitle: navTrans('dbAdmin'),
-        showDatabaseSelector: true,
-      }),
+    const route = routes.find(r => r.routerType === type);
+    if (!route) {
+      return;
+    }
 
-      [ALL_ROUTER_TYPES.PLAY]: () => ({
-        ...baseNavInfo,
-        navTitle: navTrans('play'),
-      }),
+    const navConfig = mergeNavConfig(route.navConfig);
+    const navInfo: NavInfo = {
+      backPath: navConfig.backPath || '',
+      showDatabaseSelector: navConfig.showDatabaseSelector || false,
+      navTitle: navConfig.useCollectionNameAsTitle
+        ? collectionName || navTrans(navConfig.navTitleKey || '')
+        : navTrans(navConfig.navTitleKey || ''),
+      ...(collectionName ? { extra } : {}),
     };
 
-    const getNavInfo = Object.prototype.hasOwnProperty.call(navConfigMap, type)
-      ? navConfigMap[type as ALL_ROUTER_TYPES]
-      : navConfigMap[ALL_ROUTER_TYPES.HOME];
-    const navInfo = getNavInfo();
-
-    if (navInfo) {
-      setNavInfo(navInfo);
-    }
+    setNavInfo(navInfo);
   }, [type, navTrans, setNavInfo, collectionName, extra]);
 };

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

@@ -5,7 +5,7 @@ import DatabaseTree from '@/pages/databases/tree';
 import { dataContext } from '@/context';
 import StatusIcon from '@/components/status/StatusIcon';
 import { ConsistencyLevelEnum, DYNAMIC_FIELD } from '@/consts';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import { LoadingType } from '@/components/status/StatusIcon';
 import type { SearchParams, QueryState } from './types';
 import { DatabasesTab } from './DatabasesTab';
@@ -285,7 +285,7 @@ const Databases = () => {
   } = params;
 
   // update navigation
-  useNavigationHook(ALL_ROUTER_TYPES.DATABASES, {
+  useNavigationHook(ROUTE_PATHS.DATABASES, {
     collectionName,
     databaseName,
   });

+ 2 - 2
client/src/pages/home/Home.tsx

@@ -10,7 +10,7 @@ import {
 } from '@/context';
 import { MILVUS_DEPLOY_MODE } from '@/consts';
 import { useNavigationHook } from '@/hooks';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import DatabaseCard from './DatabaseCard';
 import CreateDatabaseDialog from '../dialogs/CreateDatabaseDialog';
 import icons from '@/components/icons/Icons';
@@ -19,7 +19,7 @@ import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import Wrapper from '@/components/layout/Wrapper';
 
 const Home = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.HOME);
+  useNavigationHook(ROUTE_PATHS.HOME);
   const {
     databases,
     database,

+ 14 - 62
client/src/pages/index.tsx

@@ -4,11 +4,10 @@ import { useTranslation } from 'react-i18next';
 import GlobalEffect from '@/components/layout/GlobalEffect';
 import Header from '@/components/layout/Header';
 import NavMenu from '@/components/menu/NavMenu';
-import { NavMenuItem } from '@/components/menu/Types';
-import icons from '@/components/icons/Icons';
 import { authContext, rootContext, dataContext } from '@/context';
 import Overview from '@/pages/home/Home';
 import Box from '@mui/material/Box';
+import { getMenuItems } from '@/config/routes';
 
 function Index() {
   const { isAuth, isManaged, isDedicated, authReq } = useContext(authContext);
@@ -18,67 +17,20 @@ function Index() {
   const navigate = useNavigate();
   const location = useLocation();
 
-  const navMap = [
-    { key: 'databases', label: 'database' },
-    { key: 'search', label: 'search' },
-    { key: 'system', label: 'system' },
-    { key: 'users', label: 'user' },
-    { key: 'roles', label: 'user' },
-    { key: 'privilege-groups', label: 'user' },
-    { key: 'play', label: 'play' },
-  ];
-  const defaultActive = useMemo(() => {
-    const found = navMap.find(item => location.pathname.includes(item.key));
-    return navTrans(found?.label || 'overview');
-  }, [location.pathname, navTrans]);
-
-  const baseMenu: NavMenuItem[] = [
-    {
-      icon: icons.attu,
-      label: navTrans('overview'),
-      onClick: () => navigate('/'),
-    },
-    {
-      icon: icons.database,
-      label: navTrans('database'),
-      onClick: () => navigate(`/databases/${database}/collections`),
-    },
-    {
-      icon: icons.code,
-      label: navTrans('play'),
-      onClick: () => navigate('/play'),
-    },
-  ];
-
-  const menuItems = [...baseMenu];
-
-  if (!isManaged || isDedicated) {
-    menuItems.push({
-      icon: icons.navPerson,
-      label: navTrans('user'),
-      onClick: () => navigate('/users'),
-    });
-  }
+  const menuItems = getMenuItems(
+    isManaged,
+    isDedicated,
+    database,
+    navTrans,
+    navigate,
+    authReq
+  );
 
-  if (!isManaged) {
-    menuItems.push(
-      {
-        icon: icons.navSystem,
-        label: navTrans('system'),
-        onClick: () => navigate('/system'),
-      },
-      {
-        icon: icons.newWindow,
-        label: 'Milvus WebUI',
-        onClick: () => {
-          window.open(
-            `http://${authReq.address.split(':')[0]}:9091/webui`,
-            '_blank'
-          );
-        },
-      }
-    );
-  }
+  const defaultActive = useMemo(() => {
+    const path = location.pathname.split('/')[1] || 'overview';
+    const menuItem = menuItems.find(item => item.key === path);
+    return menuItem?.label || navTrans('overview');
+  }, [location.pathname, menuItems, navTrans]);
 
   if (!isAuth) {
     return <Navigate to="/connect" />;

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

@@ -13,7 +13,7 @@ import {
 import { ATTU_PLAY_CODE, ATTU_PLAY_RESULT } from '@/consts';
 import { authContext, dataContext } from '@/context';
 import { useNavigationHook } from '@/hooks';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import {
   DEFAULT_CODE_VALUE,
   DEFAULT_FOLD_LINE_RANGES,
@@ -39,7 +39,7 @@ import {
 const Play: FC = () => {
   // hooks
   const theme = useTheme();
-  useNavigationHook(ALL_ROUTER_TYPES.PLAY);
+  useNavigationHook(ROUTE_PATHS.PLAY);
   const [result, setResult] = useState(() => {
     const savedResult = localStorage.getItem(ATTU_PLAY_RESULT);
     return savedResult || '{}';

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

@@ -5,7 +5,7 @@ import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
 import AttuGrid from '@/components/grid/Grid';
 import { ColDefinitionsType } from '@/components/grid/Types';
 import { useNavigationHook } from '@/hooks';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import MiniTopo from './MiniTopology';
 import { getByteString, formatByteSize } from '@/utils';
 import DataCard from './DataCard';
@@ -26,7 +26,7 @@ type GridNode = {
 };
 
 const NodeListView: FC<NodeListViewProps> = props => {
-  useNavigationHook(ALL_ROUTER_TYPES.SYSTEM);
+  useNavigationHook(ROUTE_PATHS.SYSTEM);
   const { t } = useTranslation('systemView');
   const { t: commonTrans } = useTranslation();
   const capacityTrans: { [key in string]: string } = commonTrans(

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

@@ -1,7 +1,7 @@
 import { useState, useEffect, useRef } from 'react';
 import { Box } from '@mui/material';
 import { useNavigationHook, useInterval } from '@/hooks';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import { MilvusService } from '@/http';
 import { parseJson } from '@/utils';
 import Topo from './Topology';
@@ -9,7 +9,7 @@ import NodeListView from './NodeListView';
 import DataCard from './DataCard';
 
 const SystemView: any = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.SYSTEM);
+  useNavigationHook(ROUTE_PATHS.SYSTEM);
   // const { t } = useTranslation('systemView');
 
   const INTERVAL = 60000;

+ 2 - 2
client/src/pages/user/PrivilegeGroups.tsx

@@ -8,13 +8,13 @@ import AttuGrid from '@/components/grid/Grid';
 import { ColDefinitionsType, ToolBarConfig } from '@/components/grid/Types';
 import Wrapper from '@/components/layout/Wrapper';
 import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import UpdatePrivilegeGroupDialog from './dialogs/UpdatePrivilegeGroupDialog';
 import { PrivilegeGroup } from '@server/types';
 import { getLabelDisplayedRows } from '@/pages/search/Utils';
 
 const PrivilegeGroups = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.USER);
+  useNavigationHook(ROUTE_PATHS.USERS);
 
   // ui states
   const [groups, setGroups] = useState<PrivilegeGroup[]>([]);

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

@@ -6,7 +6,7 @@ import { rootContext, dataContext } from '@/context';
 import { useNavigationHook } from '@/hooks';
 import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
 import UpdateRoleDialog from './dialogs/UpdateRoleDialog';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import CustomToolBar from '@/components/grid/ToolBar';
 import type { ToolBarConfig } from '@/components/grid/Types';
 import Wrapper from '@/components/layout/Wrapper';
@@ -15,7 +15,7 @@ import type { RolesWithPrivileges, RBACOptions } from '@server/types';
 import D3PrivilegeTree from './D3PrivilegeTree';
 
 const Roles = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.USER);
+  useNavigationHook(ROUTE_PATHS.USERS);
   // context
   const { database } = useContext(dataContext);
   const { setDialog, handleCloseDialog, openSnackBar } =

+ 2 - 2
client/src/pages/user/User.tsx

@@ -15,13 +15,13 @@ import { useNavigationHook, usePaginationHook } from '@/hooks';
 import CreateUser from './dialogs/CreateUserDialog';
 import UpdateUserRole from './dialogs/UpdateUserRole';
 import UpdateUser from './dialogs/UpdateUserPassDialog';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import type { UserWithRoles } from '@server/types';
 import { getLabelDisplayedRows } from '@/pages/search/Utils';
 import { Typography } from '@mui/material';
 
 const Users = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.USER);
+  useNavigationHook(ROUTE_PATHS.USERS);
 
   // ui states
   const [users, setUsers] = useState<UserWithRoles[]>([]);

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

@@ -1,7 +1,7 @@
 import { useLocation } from 'react-router-dom';
 import { useTranslation } from 'react-i18next';
 import { useNavigationHook } from '@/hooks';
-import { ALL_ROUTER_TYPES } from '@/router/consts';
+import { ROUTE_PATHS } from '@/config/routes';
 import RouteTabList from '@/components/customTabList/RouteTabList';
 import User from './User';
 import Roles from './Roles';
@@ -10,7 +10,7 @@ import Box from '@mui/material/Box';
 import type { ITab } from '@/components/customTabList/Types';
 
 const Users = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.USER);
+  useNavigationHook(ROUTE_PATHS.USERS);
 
   const location = useLocation();
   const currentPath = location.pathname.slice(1);

+ 15 - 27
client/src/router/Router.tsx

@@ -1,45 +1,33 @@
 import { HashRouter as Router, Routes, Route } from 'react-router-dom';
 import { useContext } from 'react';
 import { authContext } from '@/context';
-import Databases from '@/pages/databases/Databases';
 import Connect from '@/pages/connect/Connect';
-import Users from '@/pages/user/UsersAndRoles';
 import Index from '@/pages/index';
-import System from '@/pages/system/SystemView';
-import Play from '@/pages/play/Play';
+import { getRoutes } from '@/config/routes';
 
 const RouterComponent = () => {
   const { isManaged, isDedicated } = useContext(authContext);
 
-  const enableManageUsers = !isManaged || isDedicated;
+  const routes = getRoutes(isManaged, isDedicated);
+
+  const renderRoutes = (routes: any[]) => {
+    return routes.map(route => {
+      const Element = route.element;
+      return (
+        <Route key={route.path} path={route.path} element={<Element />}>
+          {route.children && renderRoutes(route.children)}
+        </Route>
+      );
+    });
+  };
 
   return (
     <Router>
       <Routes>
+        <Route path="connect" element={<Connect />} />
         <Route path="/" element={<Index />}>
-          <Route path="databases" element={<Databases />} />
-          <Route path="databases/:databaseName" element={<Databases />} />
-          <Route
-            path="databases/:databaseName/:databasePage"
-            element={<Databases />}
-          />
-
-          <Route
-            path="databases/:databaseName/:collectionName/:collectionPage"
-            element={<Databases />}
-          />
-
-          {enableManageUsers && (
-            <>
-              <Route path="users" element={<Users />} />
-              <Route path="roles" element={<Users />} />
-              <Route path="privilege-groups" element={<Users />} />
-            </>
-          )}
-          <Route path="play" element={<Play />} />
-          {!isManaged && <Route path="system" element={<System />} />}
+          {renderRoutes(routes)}
         </Route>
-        <Route path="connect" element={<Connect />} />
       </Routes>
     </Router>
   );

+ 0 - 16
client/src/router/consts.ts

@@ -1,16 +0,0 @@
-export enum ALL_ROUTER_TYPES {
-  // '/'
-  HOME = 'home',
-  // '/collections'
-  COLLECTIONS = 'collections',
-  // '/collections/:collectionId'
-  COLLECTION_DETAIL = 'collection_detail',
-  // 'search'
-  SEARCH = 'search',
-  // 'system'
-  SYSTEM = 'system',
-  USER = 'user',
-  DATABASES = 'databases',
-  DB_ADMIN = 'db-admin',
-  PLAY = 'play',
-}