diff --git a/config/routes.ts b/config/routes.ts index 2b692ae9..2d59e9e0 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -9,13 +9,14 @@ export default [ selectedIcon: 'icon-dashboard-filled', defaultIcon: 'icon-dashboard', access: 'canSeeAdmin', - component: './dashboard' + component: './dashboard', + routes: [] }, { name: 'playground', - icon: 'icon-experiment', - selectedIcon: 'icon-experiment-filled', - defaultIcon: 'icon-experiment', + // icon: 'icon-experiment', + // selectedIcon: 'icon-experiment-filled', + // defaultIcon: 'icon-experiment', path: '/playground', key: 'playground', routes: [ @@ -28,7 +29,9 @@ export default [ title: 'Chat', path: '/playground/chat', key: 'chat', - icon: 'Comment', + icon: 'icon-chat', + selectedIcon: 'icon-chat-filled', + defaultIcon: 'icon-chat', component: './playground/index' }, { @@ -36,7 +39,9 @@ export default [ title: 'Text2Images', path: keepAliveRoutes.text2images, key: 'text2images', - icon: 'Comment', + icon: 'icon-image1', + selectedIcon: 'icon-image-filled', + defaultIcon: 'icon-image1', component: './playground/images' }, { @@ -44,7 +49,9 @@ export default [ title: 'Speech', path: keepAliveRoutes.speech, key: 'speech', - icon: 'Comment', + icon: 'icon-audio1', + selectedIcon: 'icon-audio-filled', + defaultIcon: 'icon-audio1', component: './playground/speech' }, { @@ -52,7 +59,9 @@ export default [ title: 'embedding', path: '/playground/embedding', key: 'embedding', - icon: 'Comment', + icon: 'icon-embedding', + selectedIcon: 'icon-embedding-filled', + defaultIcon: 'icon-embedding', component: './playground/embedding' }, { @@ -60,60 +69,124 @@ export default [ title: 'Rerank', path: '/playground/rerank', key: 'rerank', - icon: 'Comment', + icon: 'icon-reranker', + selectedIcon: 'icon-reranker-filled', + defaultIcon: 'icon-reranker', component: './playground/rerank' } ] }, - { - name: 'modelCatalog', - path: '/models/catalog', - key: 'modelsCatalog', - icon: 'icon-layers', - selectedIcon: 'icon-layers-filled', - defaultIcon: 'icon-layers', - access: 'canSeeAdmin', - component: './llmodels/catalog' - }, { name: 'models', - path: '/models/list', + path: '/models', key: 'models', - icon: 'icon-model', - selectedIcon: 'icon-model-filled', - defaultIcon: 'icon-model', - access: 'canSeeAdmin', - component: './llmodels/index' + routes: [ + { + path: '/models', + redirect: '/models/deployment' + }, + { + name: 'modelCatalog', + path: '/models/catalog', + key: 'modelsCatalog', + icon: 'icon-layers', + selectedIcon: 'icon-layers-filled', + defaultIcon: 'icon-layers', + access: 'canSeeAdmin', + component: './llmodels/catalog' + }, + { + name: 'deployment', + path: '/models/deployment', + key: 'modelDeployments', + icon: 'icon-model', + selectedIcon: 'icon-model-filled', + defaultIcon: 'icon-model', + access: 'canSeeAdmin', + component: './llmodels/index' + } + ] }, { name: 'resources', path: '/resources', key: 'resources', - icon: 'icon-resources', - selectedIcon: 'icon-resources-filled', - defaultIcon: 'icon-resources', access: 'canSeeAdmin', - component: './resources' + routes: [ + { + path: '/resources', + redirect: '/resources/workers' + }, + { + name: 'workers', + path: '/resources/workers', + key: 'workers', + icon: 'icon-resources', + selectedIcon: 'icon-resources-filled', + defaultIcon: 'icon-resources', + component: './resources/components/workers' + }, + { + name: 'gpus', + path: '/resources/gpus', + key: 'gpus', + icon: 'icon-gpu1', + selectedIcon: 'icon-gpu-filled', + defaultIcon: 'icon-gpu1', + component: './resources/components/gpus' + }, + { + name: 'modelfiles', + path: '/resources/modelfiles', + key: 'modelfiles', + icon: 'icon-files', + selectedIcon: 'icon-files-filled', + defaultIcon: 'icon-files', + component: './resources/components/model-files' + } + ] + }, + // { + // name: 'users', + // path: '/users', + // key: 'users', + // icon: 'icon-users', + // selectedIcon: 'icon-users-filled', + // defaultIcon: 'icon-users', + // access: 'canSeeAdmin', + // component: './users' + // }, + { + name: 'accessControl', + path: '/access-control', + key: 'accessControl', + routes: [ + { + path: '/access-control', + redirect: '/access-control/users' + }, + { + name: 'users', + path: '/access-control/users', + key: 'users', + icon: 'icon-users', + selectedIcon: 'icon-users-filled', + defaultIcon: 'icon-users', + access: 'canSeeAdmin', + component: './users' + } + ] }, { name: 'apikeys', path: '/api-keys', key: 'apikeys', + hideInMenu: true, selectedIcon: 'icon-key-filled', icon: 'icon-key', defaultIcon: 'icon-key', component: './api-keys' }, - { - name: 'users', - path: '/users', - key: 'users', - icon: 'icon-users', - selectedIcon: 'icon-users-filled', - defaultIcon: 'icon-users', - access: 'canSeeAdmin', - component: './users' - }, { name: 'profile', path: '/profile', diff --git a/src/app.tsx b/src/app.tsx index 86e4cf6a..958bfff1 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -23,7 +23,7 @@ const checkDefaultPage = async (userInfo: any) => { if (isFirstLogin === null && isOnline()) { writeState(IS_FIRST_LOGIN, true); if (userInfo && userInfo?.is_admin) { - history.push('/models/list'); + history.push('/models/deployment'); } } }; diff --git a/src/atoms/settings.ts b/src/atoms/settings.ts index 2caa3135..c8031fab 100644 --- a/src/atoms/settings.ts +++ b/src/atoms/settings.ts @@ -7,13 +7,15 @@ type UserSettings = { mode: 'light' | 'realDark' | 'auto'; colorPrimary: string; isDarkTheme: boolean; + collapsed: boolean; }; const defaultSettings: UserSettings = { theme: 'light', mode: 'auto', isDarkTheme: false, - colorPrimary: colorPrimary + colorPrimary: colorPrimary, + collapsed: false }; export const getStorageUserSettings = () => { diff --git a/src/components/icon-font/index.tsx b/src/components/icon-font/index.tsx index 2c4fbc7b..c1e96374 100644 --- a/src/components/icon-font/index.tsx +++ b/src/components/icon-font/index.tsx @@ -1,8 +1,8 @@ import { createFromIconfontCN } from '@ant-design/icons'; -import './iconfont/iconfont.js'; +// import './iconfont/iconfont.js'; const IconFont = createFromIconfontCN({ - scriptUrl: '' + scriptUrl: '//at.alicdn.com/t/c/font_4613488_35np53id3ax.js' }); export default IconFont; diff --git a/src/config/theme/dark.ts b/src/config/theme/dark.ts index 1c928462..5c2ac79e 100644 --- a/src/config/theme/dark.ts +++ b/src/config/theme/dark.ts @@ -32,7 +32,7 @@ export default { iconSize: 16, iconMarginInlineEnd: 12, itemBorderRadius: 4, - itemHeight: 36, + itemHeight: 32, itemSelectedColor: '#007BFF', darkItemSelectedBg: '#141414', darkItemHoverBg: 'rgba(255, 255, 255, 0.03)', diff --git a/src/config/theme/light.ts b/src/config/theme/light.ts index fe43d0cd..817d1fac 100644 --- a/src/config/theme/light.ts +++ b/src/config/theme/light.ts @@ -33,7 +33,7 @@ export default { iconMarginInlineEnd: 12, itemBorderRadius: 4, itemSelectedColor: '#007BFF', - itemHeight: 36, + itemHeight: 32, groupTitleColor: 'rgba(0,0,0,1)', itemHoverColor: 'rgba(0,0,0,1)', itemColor: 'rgba(0,0,0,1)', diff --git a/src/global.less b/src/global.less index 7fc6666a..84688976 100644 --- a/src/global.less +++ b/src/global.less @@ -252,7 +252,8 @@ body { } .ant-pro-sider .ant-layout-sider-children { - background-color: var(--color-fill-sider); + // background-color: var(--color-fill-sider); + border-right: 1px solid var(--ant-color-split); } } @@ -292,6 +293,10 @@ body { } } + .ant-pro-sider-actions-list-collapsed { + margin-block-end: 0; + } + .ant-pro-page-container-children-container { padding-block: var(--layout-content-blockpadding); padding-inline: var(--layout-content-inlinepadding); @@ -334,6 +339,10 @@ body { // color: var(--ant-color-primary) !important; font-weight: 400; } + + .ant-menu-item-group-title.hide-submenu + .ant-menu-item-group-list { + display: none; + } } } } diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx index 52023208..a4c7a67c 100644 --- a/src/layouts/index.tsx +++ b/src/layouts/index.tsx @@ -28,7 +28,7 @@ import { useNavigate, type IRoute } from '@umijs/max'; -import { Button, ConfigProvider, Modal, theme } from 'antd'; +import { Button, ConfigProvider, Modal, Tooltip, theme } from 'antd'; import 'driver.js/dist/driver.css'; import { useAtom } from 'jotai'; import 'overlayscrollbars/overlayscrollbars.css'; @@ -39,6 +39,7 @@ import { LogoIcon, SLogoIcon } from './Logo'; import ErrorBoundary from './error-boundary'; import { getRightRenderContent } from './rightRender'; import { patchRoutes } from './runtime'; +import SiderMenu from './sider-menu'; const loginPath = '/login'; @@ -102,7 +103,8 @@ export default (props: any) => { defer: false }); const [modal, contextHolder] = Modal.useModal(); - const { themeData, setTheme, userSettings, isDarkTheme } = useUserSettings(); + const { themeData, setTheme, setUserSettings, userSettings, isDarkTheme } = + useUserSettings(); const { saveScrollHeight, restoreScrollHeight } = useBodyScroll(); const { initialize: initializeMenu } = useOverlayScroller(); const [userInfo] = useAtom(userAtom); @@ -113,8 +115,9 @@ export default (props: any) => { const navigate = useNavigate(); const intl = useIntl(); const { clientRoutes, pluginManager } = useAppData(); - const [collapsed, setCollapsed] = useState(false); + // const [collapsed, setCollapsed] = useState(userSettings.collapsed || false); const [collapseValue, setCollapseValue] = useState(false); + const [collapseKeys, setCollapseKeys] = useState>(new Set()); const initialInfo = (useModel && useModel('@@initialState')) || { initialState: undefined, @@ -187,7 +190,11 @@ export default (props: any) => { const handleToggleCollapse = (e: any) => { e.stopPropagation(); - setCollapsed(!collapsed); + // setCollapsed(!collapsed); + setUserSettings({ + ...userSettings, + collapsed: !userSettings.collapsed + }); }; const newRoutes = filterRoutes( @@ -203,6 +210,8 @@ export default (props: any) => { const role = initialState?.currentUser?.is_admin ? 'admin' : 'user'; const [route] = useAccessMarkedRoutes(mapRoutes(newRoutes, role)); + console.log('route============', route); + patchRoutes({ routes: route.children, initialState: initialInfo.initialState @@ -213,6 +222,24 @@ export default (props: any) => { [location.pathname] ); + const allRouteKeys = useMemo(() => { + const keys = new Set(); + const childrenRoutes = route?.children || []; + const traverseRoutes = (routes) => { + routes.forEach((r) => { + if (r.path) { + keys.add(r.path); + } + if (r.children) { + traverseRoutes(r.children); + } + }); + }; + traverseRoutes(childrenRoutes); + + return keys; + }, [route?.children]); + const showUpgrade = useMemo(() => { return ( initialState?.currentUser?.is_admin && @@ -256,13 +283,17 @@ export default (props: any) => { return () => clearTimeout(timeout); }, [initializeMenu, matchedRoute, location]); + const collapsed = useMemo(() => { + return userSettings.collapsed || false; + }, [userSettings.collapsed]); + const renderMenuHeader = (logo, title) => { return ( <> {logo}