refactor: page layout

This commit is contained in:
jialin
2025-11-05 10:02:25 +08:00
parent 219f9871a7
commit 4c22d08da5
43 changed files with 784 additions and 513 deletions
+4
View File
@@ -253,6 +253,10 @@
font-weight: var(--font-weight-bold);
}
.text-primary {
color: var(--ant-color-text);
}
.text-secondary {
color: var(--ant-color-text-secondary);
}
+6 -7
View File
@@ -126,7 +126,6 @@ export default function useChartConfig() {
type: 'bar',
barMaxWidth: 20,
barMinWidth: 8,
// stack: 'total',
barGap: '30%',
barCategoryGap: '50%'
};
@@ -154,7 +153,7 @@ export default function useChartConfig() {
progress: {
show: true,
roundCap: false,
width: 10
width: 12
},
pointer: {
length: '80%',
@@ -166,7 +165,7 @@ export default function useChartConfig() {
axisLine: {
roundCap: false,
lineStyle: {
width: 10,
width: 12,
color: [
[0.5, 'rgba(84, 204, 152, 80%)'],
[0.8, 'rgba(250, 173, 20, 80%)'],
@@ -175,8 +174,8 @@ export default function useChartConfig() {
}
},
axisTick: {
distance: -10,
length: 5,
distance: -11,
length: 6,
splitNumber: 5,
lineStyle: {
width: 1.5,
@@ -209,13 +208,13 @@ export default function useChartConfig() {
rich: {
value: {
fontSize: 16,
fontWeight: '600',
fontWeight: 500,
color: chartColorMap.titleColor
},
unit: {
fontSize: 14,
color: chartColorMap.titleColor,
fontWeight: '600',
fontWeight: 500,
padding: [0, 0, 0, 2]
}
}
+11 -4
View File
@@ -24,8 +24,10 @@ const GaugeChart: React.FC<Omit<ChartProps, 'seriesData' | 'xAxisData'>> = (
} = useChartConfig();
const { value, height, width, labelFormatter, title, color, gaugeConfig } =
props;
const titleText = typeof title === 'string' ? title : title?.text;
if (!value && value !== 0) {
return <EmptyData height={height} title={title}></EmptyData>;
return <EmptyData height={height} title={titleText}></EmptyData>;
}
const setDataOptions = () => {
@@ -41,14 +43,15 @@ const GaugeChart: React.FC<Omit<ChartProps, 'seriesData' | 'xAxisData'>> = (
return {
title: {
...titleConfig,
text: title,
text: titleText,
textStyle: {
fontSize: 12,
color: chartColorMap.colorSecondary,
fontWeight: 400
},
top: '0',
left: 'center'
top: 10,
left: 'center',
...(typeof title === 'object' ? title : {})
},
series: [
{
@@ -68,6 +71,10 @@ const GaugeChart: React.FC<Omit<ChartProps, 'seriesData' | 'xAxisData'>> = (
},
detail: {
...combineGaugeConfig.detail,
borderColor: colorValue,
lineHeight: 20,
height: 18,
width: 50,
formatter: labelFormatter || gaugeItemConfig.detail.formatter
},
data: [{ value }]
+1 -1
View File
@@ -21,7 +21,7 @@ export interface ChartProps {
tooltipValueFormatter?: (val: any) => string;
height: string | number;
width?: string | number;
title?: string;
title?: string | TitleComponentOption;
titleOptions?: {
[K in keyof TitleComponentOption]?: TitleComponentOption[K];
};
+1 -1
View File
@@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
// import './iconfont/iconfont.js';
const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_4613488_ab78o2vlum.js'
scriptUrl: '//at.alicdn.com/t/c/font_4613488_nb1thiz3t9.js'
});
export default IconFont;
+1 -1
View File
@@ -167,7 +167,7 @@ export const FilterBar: React.FC<FilterBarProps> = (props) => {
return (
<PageTools
marginBottom={marginBottom}
marginTop={marginTop}
marginTop={0}
left={
<Space>
<Input
+1 -1
View File
@@ -1 +1 @@
export const HEADER_HEIGHT = 72;
export const HEADER_HEIGHT = 56;
+1 -1
View File
@@ -22,7 +22,7 @@ declare namespace Global {
require_password_change: boolean;
id: number;
source: string;
avatar_url?: string;
avatar: string;
}
type EmptyObject = Record<never, never>;
+6
View File
@@ -118,6 +118,12 @@ body {
width: 0;
}
.ant-pro-page-container-affix {
.ant-affix {
top: 0 !important;
}
}
.ant-modal-confirm-title {
display: none;
}
+298
View File
@@ -0,0 +1,298 @@
import { GPUStackVersionAtom, UpdateCheckAtom } from '@/atoms/user';
import DropDownActions from '@/components/drop-down-actions';
import IconFont from '@/components/icon-font';
import VersionInfo, { modalConfig } from '@/components/version-info';
import externalLinks from '@/constants/external-links';
import useBodyScroll from '@/hooks/use-body-scroll';
import { logout } from '@/pages/login/apis';
import { useModel } from '@@/plugin-model';
import {
DiscordOutlined,
GithubOutlined,
HomeOutlined,
InfoCircleOutlined,
LogoutOutlined,
ReadOutlined,
SettingOutlined
} from '@ant-design/icons';
import { history, useIntl, useNavigate } from '@umijs/max';
import { Avatar, Divider, Modal } from 'antd';
import { useAtom } from 'jotai';
import { useMemo } from 'react';
import styled from 'styled-components';
const IconWrapper = styled.span`
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--ant-color-text-secondary);
`;
const Wrapper = styled.div`
display: flex;
align-items: center;
gap: 24px;
height: 40px;
`;
const DropdownWrapper = styled.div`
min-width: 160px;
box-shadow: var(--ant-box-shadow-secondary);
background-color: var(--ant-color-bg-elevated);
border-radius: var(--ant-border-radius-lg);
padding: var(--ant-padding-xs);
.ant-dropdown-menu {
padding: 0;
box-shadow: none;
background-color: transparent;
border-radius: 0;
a {
color: var(--ant-color-text);
}
}
`;
const CustomItem = styled.div`
display: flex;
align-items: center;
gap: 8px;
height: 32px;
justify-content: flex-start;
height: 32px;
padding: 0 var(--ant-padding-xs);
cursor: pointer;
&.user-info {
cursor: default;
justify-content: space-between;
.user-name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: 100px;
}
}
&:not(.user-info):hover {
background-color: var(--ant-control-item-bg-hover);
}
background-color: var(--ant-color-bg-elevated);
`;
export const ExtraContent = () => {
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
const [modal, contextHolder] = Modal.useModal();
const [version] = useAtom(GPUStackVersionAtom);
const [updateCheck] = useAtom(UpdateCheckAtom);
const intl = useIntl();
const initialInfo = useModel('@@initialState') || {
initialState: undefined,
loading: false,
setInitialState: null
};
const { initialState } = initialInfo;
const navigate = useNavigate();
const loginPath = '/login';
const showUpgrade = useMemo(() => {
return (
initialState?.currentUser?.is_admin &&
updateCheck.latest_version &&
updateCheck.latest_version !== version?.version &&
updateCheck.latest_version?.indexOf('0.0.0') === -1 &&
updateCheck.latest_version?.indexOf('rc') === -1
);
}, [
updateCheck.latest_version,
version.version,
initialState?.currentUser?.is_admin
]);
const showVersion = () => {
saveScrollHeight();
modal.info({
...modalConfig,
width: 460,
content: <VersionInfo intl={intl} />,
onCancel: restoreScrollHeight
});
};
const handleLogout = async () => {
await logout();
navigate(loginPath);
};
const helpList = [
{
key: 'site',
icon: <HomeOutlined />,
label: 'GPUStack',
url: externalLinks.site
},
{
key: 'github',
icon: <GithubOutlined />,
label: intl.formatMessage({ id: 'common.issue.report' }),
url: externalLinks.reportIssue
},
{
key: 'faq',
icon: <IconFont type="icon-fankuifaqs"></IconFont>,
label: intl.formatMessage({ id: 'common.button.faq' }),
url: externalLinks.faq
},
{
key: 'Discord',
icon: <DiscordOutlined />,
label: 'Discord',
url: externalLinks.discord
},
{
key: 'docs',
icon: <ReadOutlined />,
label: intl.formatMessage({ id: 'common.button.docs' }),
url: externalLinks.documentation
},
{
key: 'version',
icon: <InfoCircleOutlined />,
label: intl.formatMessage({ id: 'common.button.version' })
}
];
const helpMenu = {
items: helpList.map((item) => ({
key: item.key,
label: (
<span className="flex flex-center">
{item.icon}
{item.key === 'version' ? (
<>
<a className="m-l-8">{item.label}</a>
{showUpgrade && (
<span className="new-icon">
<span className="text">
{intl.formatMessage({ id: 'common.text.new' })}
</span>
</span>
)}
</>
) : (
<a
className="m-l-8 "
href={item.url}
target="_blank"
rel="noreferrer"
>
{item.label}
</a>
)}
</span>
),
onClick() {
if (item.key === 'version') {
showVersion();
}
}
}))
};
const userMenu = {
items: [
{
key: 'apikeys',
label: (
<span className="flex flex-center">
<IconFont type="icon-key" />
<span className="m-l-8" style={{ marginLeft: 8 }}>
{intl?.formatMessage?.({ id: 'menu.apikeys' })}
</span>
</span>
),
onClick: () => {
history.push('/api-keys');
}
},
{
key: 'settings',
label: (
<span className="flex flex-center">
<SettingOutlined />
<span className="m-l-8" style={{ marginLeft: 8 }}>
{intl?.formatMessage?.({ id: 'common.button.settings' })}
</span>
</span>
),
onClick: () => {
history.push('/profile');
}
}
]
};
const userPopupRender = (originNode: React.ReactNode) => {
return (
<DropdownWrapper>
<CustomItem className="user-info border-bottom">
<span className="flex-center gap-8">
<Avatar
size={24}
src={initialState?.currentUser?.avatar}
icon={
<IconFont type="icon-user-filled" className="font-size-24" />
}
/>
<span className="user-name">
{initialState?.currentUser?.username}
</span>
</span>
</CustomItem>
<Divider style={{ marginBlock: 4 }} />
{originNode}
<Divider style={{ marginBlock: 4 }} />
<CustomItem onClick={handleLogout} className="border-top">
<LogoutOutlined />
<span>{intl?.formatMessage?.({ id: 'common.button.logout' })}</span>
</CustomItem>
</DropdownWrapper>
);
};
const helpPopupRender = (originNode: React.ReactNode) => {
return <DropdownWrapper>{originNode}</DropdownWrapper>;
};
return (
<Wrapper>
{contextHolder}
<DropDownActions menu={{ ...helpMenu }} popupRender={helpPopupRender}>
<IconWrapper>
<IconFont type="icon-help" className="font-size-20" />
{showUpgrade && (
<span
className="m-l-5"
style={{
display: 'flex',
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: 'var(--ant-orange-5)'
}}
></span>
)}
</IconWrapper>
</DropDownActions>
<DropDownActions menu={{ ...userMenu }} popupRender={userPopupRender}>
<IconWrapper>
<Avatar
size={24}
src={initialState?.currentUser?.avatar}
icon={<IconFont type="icon-user-filled" className="font-size-24" />}
/>
</IconWrapper>
</DropDownActions>
</Wrapper>
);
};
+33 -32
View File
@@ -33,14 +33,26 @@ import 'driver.js/dist/driver.css';
import { useAtom } from 'jotai';
import 'overlayscrollbars/overlayscrollbars.css';
import { useEffect, useMemo, useState } from 'react';
import { PageContainerInner } from '../pages/_components/page-box';
import Exception from './Exception';
import './Layout.css';
import { LogoIcon, SLogoIcon } from './Logo';
import ErrorBoundary from './error-boundary';
import { ExtraContent } from './extraRender';
import { getRightRenderContent } from './rightRender';
import { patchRoutes } from './runtime';
import SiderMenu from './sider-menu';
const NO_CONTAINER_PAGES = [
'chat',
'rerank',
'embedding',
'speech',
'image',
'clusterDetail',
'clusterCreate'
];
const loginPath = '/login';
type InitialStateType = {
@@ -205,8 +217,6 @@ 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
@@ -217,6 +227,12 @@ export default (props: any) => {
[location.pathname]
);
const isNoContainerPage = useMemo(() => {
return NO_CONTAINER_PAGES.includes(matchedRoute?.name);
}, [matchedRoute]);
console.log('matchedRoute=========', matchedRoute, route);
const allRouteKeys = useMemo(() => {
const keys = new Set<string>();
const childrenRoutes = route?.children || [];
@@ -257,27 +273,6 @@ export default (props: any) => {
}
}, [initialize]);
useEffect(() => {
const checkAndInitialize = () => {
const menuWrap = window.document.querySelector(
'.ant-menu.ant-menu-root'
)?.parentElement;
if (menuWrap) {
try {
initializeMenu(menuWrap);
} catch (error) {
console.error('Failed to initialize menu:', error);
}
} else {
console.warn('Menu wrapper not found.');
}
};
const timeout = setTimeout(checkAndInitialize, 500);
return () => clearTimeout(timeout);
}, [initializeMenu, matchedRoute, location]);
const collapsed = useMemo(() => {
return userSettings.collapsed || false;
}, [userSettings.collapsed]);
@@ -326,7 +321,6 @@ export default (props: any) => {
};
const actionRender = (layoutProps) => {
console.log('actionRender', layoutProps);
const dom = getRightRenderContent({
runtimeConfig,
loading,
@@ -334,8 +328,8 @@ export default (props: any) => {
setInitialState,
intl,
isDarkTheme: userSettings.isDarkTheme,
siderWidth: layoutProps.siderWidth,
collapsed: layoutProps.collapsed,
siderWidth: layoutProps?.siderWidth,
collapsed: layoutProps?.collapsed,
showUpgrade
});
@@ -479,6 +473,12 @@ export default (props: any) => {
return data;
}, [userSettings.isDarkTheme, themeData]);
const outlet = runtimeConfig.childrenRender ? (
runtimeConfig.childrenRender(<Outlet />, props)
) : (
<Outlet />
);
return (
<ConfigProvider
componentSize="large"
@@ -492,6 +492,9 @@ export default (props: any) => {
>
<DarkMask></DarkMask>
<ProLayout
fixSiderbar
fixedHeader
breadcrumbRender={false}
route={route}
location={location}
title={userConfig.title}
@@ -510,6 +513,7 @@ export default (props: any) => {
onCollapse={onCollapse}
onMenuHeaderClick={onMenuHeaderClick}
menuHeaderRender={renderMenuHeader}
extra={[<ExtraContent key="extra-content" />]}
collapsed={userSettings.collapsed}
onPageChange={onPageChange}
formatMessage={formatMessage}
@@ -521,10 +525,7 @@ export default (props: any) => {
logo={collapsed ? SLogoIcon : LogoIcon}
menuContentRender={menuContentRender}
disableContentMargin
fixSiderbar
fixedHeader
{...runtimeConfig}
actionsRender={actionRender}
ErrorBoundary={ErrorBoundary}
>
<Exception
@@ -534,10 +535,10 @@ export default (props: any) => {
unAccessible={runtimeConfig?.unAccessible}
noAccessible={runtimeConfig?.noAccessible}
>
{runtimeConfig.childrenRender ? (
runtimeConfig.childrenRender(<Outlet />, props)
{isNoContainerPage ? (
outlet
) : (
<Outlet />
<PageContainerInner>{outlet}</PageContainerInner>
)}
</Exception>
</ProLayout>
+2 -8
View File
@@ -280,14 +280,8 @@ export const getRightRenderContent = (opts: {
return (
<>
<Menu {...helpMenu} style={getMenuStyle(collapsed, siderWidth)} />
<Menu
{...userMenu}
style={getMenuStyle(collapsed, siderWidth, {
marginTop: 8,
marginBottom: 0
})}
/>
<Menu {...helpMenu} mode="vertical" />
<Menu {...userMenu} mode="vertical" />
</>
);
};
+49
View File
@@ -0,0 +1,49 @@
import {
PageContainer,
type PageContainerProps
} from '@ant-design/pro-components';
import styled from 'styled-components';
const paddingInlinePageContainerContent = 32;
const StyledPageContainer = styled(PageContainer)`
.ant-affix {
top: 0 !important;
height: auto;
}
.ant-page-header {
padding-block-end: 8px;
.ant-page-header-heading {
padding-block-start: 0;
}
}
.ant-pro-page-container-warp-page-header {
padding-inline: ${paddingInlinePageContainerContent}px;
}
.ant-page-header-heading-title {
font-size: 16px;
}
`;
export const PageContainerInner: React.FC<PageContainerProps> = ({
children,
...rest
}) => {
return (
<StyledPageContainer
{...rest}
fixedHeader
token={{
paddingInlinePageContainerContent: paddingInlinePageContainerContent
}}
>
{children}
</StyledPageContainer>
);
};
const PageBox: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return <div>{children}</div>;
};
export default PageBox;
@@ -0,0 +1,27 @@
import IconFont from '@/components/icon-font';
import { Breadcrumb, type BreadcrumbProps } from 'antd';
import React from 'react';
import styled from 'styled-components';
const StyledBreadcrumb = styled(Breadcrumb)`
.ant-breadcrumb-link {
font-size: 16px;
font-weight: 500;
a {
background: unset;
}
}
.ant-breadcrumb-separator {
display: flex;
align-items: center;
}
`;
const App: React.FC<BreadcrumbProps> = ({ items }) => (
<StyledBreadcrumb
separator={<IconFont type="icon-down2" rotate={-90} />}
items={items}
/>
);
export default App;
@@ -0,0 +1,20 @@
import { PageContainerProps } from '@ant-design/pro-components';
import { createContext, useContext } from 'react';
interface PageContainerContextProps extends Partial<PageContainerProps> {
[key: string]: any;
}
export const PageContainerContext = createContext<PageContainerContextProps>(
{}
);
export function usePageContainerContext() {
const context = useContext(PageContainerContext);
if (!context) {
throw new Error(
'usePageContainerContext must be used within a PageContainerProvider'
);
}
return context;
}
+3 -13
View File
@@ -4,12 +4,12 @@ import { FilterBar } from '@/components/page-tools';
import { PageAction } from '@/config';
import type { PageActionType } from '@/config/types';
import useTableFetch from '@/hooks/use-table-fetch';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
import { Button, ConfigProvider, Table } from 'antd';
import { useState } from 'react';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import { deleteApisKey, queryApisKeysList } from './apis';
import AddAPIKeyModal from './components/add-apikey-modal';
import { ListItem } from './config/types';
@@ -123,17 +123,7 @@ const APIKeys: React.FC = () => {
return (
<>
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'apikeys.title' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<FilterBar
marginBottom={22}
marginTop={30}
@@ -163,7 +153,7 @@ const APIKeys: React.FC = () => {
}}
></Table>
</ConfigProvider>
</PageContainer>
</PageBox>
<AddAPIKeyModal
open={openAddModal.open}
action={openAddModal.action}
+3 -13
View File
@@ -3,7 +3,6 @@ import IconFont from '@/components/icon-font';
import { FilterBar } from '@/components/page-tools';
import { PageActionType } from '@/config/types';
import useTableFetch from '@/hooks/use-table-fetch';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
import { Button } from 'antd';
@@ -11,6 +10,7 @@ import _ from 'lodash';
import { useState } from 'react';
import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import {
createBackend,
createBackendFromYAML,
@@ -170,17 +170,7 @@ const BackendList = () => {
});
return (
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'menu.resources.backendsList' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<FilterBar
showDeleteButton={false}
marginBottom={22}
@@ -255,7 +245,7 @@ const BackendList = () => {
}
></VersionInfoModal>
<DeleteModal ref={modalRef}></DeleteModal>
</PageContainer>
</PageBox>
);
};
+20 -35
View File
@@ -1,10 +1,11 @@
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
import { PageContainer } from '@ant-design/pro-components';
import PageBreadcrumb from '@/pages/_components/page-breadcrumb';
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
import _ from 'lodash';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import { PageContainerInner } from '../_components/page-box';
import { createCluster, queryClusterToken, queryCredentialList } from './apis';
import ClusterSteps from './components/cluster-steps';
import FooterButtons from './components/footer-buttons';
@@ -25,7 +26,6 @@ const Container = styled.div`
const Nav = styled.div`
display: flex;
align-items: center;
height: 72px;
font-weight: 400;
font-size: 20px;
color: var(--ant-color-text-tertiary);
@@ -280,9 +280,18 @@ const ClusterCreate = () => {
navigate(-1);
};
const breadcrumbItems = [
{
title: <a>{intl.formatMessage({ id: 'clusters.title' })}</a>,
onClick: () => navigate(-1)
},
{
title: intl.formatMessage({ id: 'common.button.create' })
}
];
return (
<PageContainer
ghost
<PageContainerInner
footer={[
<FooterButtons
key="buttons"
@@ -294,38 +303,14 @@ const ClusterCreate = () => {
/>
]}
header={{
title: false,
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
title: <PageBreadcrumb items={breadcrumbItems} />
}}
pageHeaderRender={() => (
<HeaderContainer>
<Nav>
<span className="level-1">
{intl.formatMessage({ id: 'clusters.title' })}
</span>
<span
style={{
marginInline: 20,
color: 'var(--ant-color-split)'
}}
>
/
</span>
<span className="level-2">
{intl.formatMessage({ id: 'common.button.create' })}
</span>
</Nav>
<ClusterSteps
steps={steps}
currentStep={currentStep}
onChange={handleStepChange}
></ClusterSteps>
</HeaderContainer>
)}
>
<ClusterSteps
steps={steps}
currentStep={currentStep}
onChange={handleStepChange}
></ClusterSteps>
{currentStep === startStep && (
<ProviderCatalog
dataList={providerList}
@@ -339,7 +324,7 @@ const ClusterCreate = () => {
<Container>
<Content>{renderForms()}</Content>
</Container>
</PageContainer>
</PageContainerInner>
);
};
+19 -16
View File
@@ -1,30 +1,33 @@
import { PageContainer } from '@ant-design/pro-components';
import { useSearchParams } from '@umijs/max';
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
import { PageContainerInner } from '../_components/page-box';
import PageBreadcrumb from '../_components/page-breadcrumb';
import ClusterMetrics from './components/cluster-metrics';
const ClusterDetailModal = () => {
const navigate = useNavigate();
const intl = useIntl();
const [searchParams] = useSearchParams();
const provider = searchParams.get('provider');
const clusterName = searchParams.get('name');
const breadcrumbItems = [
{
title: <a>{intl.formatMessage({ id: 'clusters.title' })}</a>,
onClick: () => navigate(-1)
},
{
title: clusterName
}
];
return (
<PageContainer
ghost
<PageContainerInner
header={{
title: (
<span className="flex-center">
<span>{clusterName}</span>
</span>
),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
title: <PageBreadcrumb items={breadcrumbItems} />
}}
extra={[]}
>
<ClusterMetrics />
{/* {provider === ProviderValueMap.DigitalOcean && <WorkerPools />} */}
</PageContainer>
</PageContainerInner>
);
};
+3 -15
View File
@@ -10,13 +10,13 @@ import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
import useTableFetch from '@/hooks/use-table-fetch';
import useWatchList from '@/hooks/use-watch-list';
import AddWorker from '@/pages/cluster-management/components/add-worker';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Button, message } from 'antd';
import { useAtom } from 'jotai';
import { useEffect, useState } from 'react';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import {
CLUSTERS_API,
createWorkerPool,
@@ -327,19 +327,7 @@ const Clusters: React.FC = () => {
return (
<>
<PageContainer
ghost
header={{
title: intl.formatMessage({
id: 'menu.clusterManagement.clusters'
}),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<FilterBar
showSelect={false}
showPrimaryButton={true}
@@ -404,7 +392,7 @@ const Clusters: React.FC = () => {
}}
></SealTable>
</TableContext.Provider>
</PageContainer>
</PageBox>
<AddCluster
provider={openAddModal.provider}
open={openAddModal.open}
@@ -53,6 +53,15 @@ interface ClusterDetailProps {
data: ClusterListItem | null;
}
const titleConfig = {
textStyle: {
color: '#000',
fontSize: 14,
fontWeight: 600
},
top: -5
};
const gaugeConfig = {
radius: '100%',
progress: {
@@ -140,7 +149,10 @@ const ClusterMetrics = () => {
<Row gutter={16} style={{ width: '100%' }}>
<Col span={6}>
<GaugeChart
title="GPU Utilization"
title={{
text: 'GPU Utilization',
...titleConfig
}}
value={formatValue(detailContent.current.gpu)}
height={chartHeight}
gaugeConfig={gaugeConfig}
@@ -148,7 +160,10 @@ const ClusterMetrics = () => {
</Col>
<Col span={6}>
<GaugeChart
title="CPU Utilization"
title={{
text: 'CPU Utilization',
...titleConfig
}}
value={formatValue(detailContent.current.cpu)}
height={chartHeight}
gaugeConfig={gaugeConfig}
@@ -156,7 +171,10 @@ const ClusterMetrics = () => {
</Col>
<Col span={6}>
<GaugeChart
title="RAM Utilization"
title={{
text: 'RAM Utilization',
...titleConfig
}}
value={formatValue(detailContent.current.ram)}
height={chartHeight}
gaugeConfig={gaugeConfig}
@@ -164,7 +182,10 @@ const ClusterMetrics = () => {
</Col>
<Col span={6}>
<GaugeChart
title="VRAM Utilization"
title={{
text: 'VRAM Utilization',
...titleConfig
}}
value={formatValue(detailContent.current.vram)}
height={chartHeight}
gaugeConfig={gaugeConfig}
+4 -16
View File
@@ -5,13 +5,13 @@ import { FilterBar } from '@/components/page-tools';
import { PageAction } from '@/config';
import type { PageActionType } from '@/config/types';
import useTableFetch from '@/hooks/use-table-fetch';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Button, ConfigProvider, Table, message } from 'antd';
import { useAtom } from 'jotai';
import { useState } from 'react';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import {
createCredential,
deleteCredential,
@@ -178,26 +178,14 @@ const Credentials: React.FC = () => {
return (
<>
<PageContainer
ghost
header={{
title: intl.formatMessage({
id: 'menu.clusterManagement.credentials'
}),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<FilterBar
actionItems={addActions}
actionType="dropdown"
showSelect={false}
showPrimaryButton={true}
marginBottom={22}
marginTop={30}
marginTop={0}
buttonText={intl.formatMessage({
id: 'clusters.button.addCredential'
})}
@@ -228,7 +216,7 @@ const Credentials: React.FC = () => {
}}
></Table>
</ConfigProvider>
</PageContainer>
</PageBox>
<AddModal
provider={openModalStatus.provider}
open={openModalStatus.open}
@@ -55,6 +55,7 @@ const SystemLoad = () => {
<Row style={{ height: largeChartHeight }}>
<Col span={12} style={{ height: smallChartHeight }}>
<GaugeChart
name="GPU"
height={smallChartHeight}
value={chartData.gpu.data}
title={intl.formatMessage({
@@ -64,6 +65,7 @@ const SystemLoad = () => {
</Col>
<Col span={12} style={{ height: smallChartHeight }}>
<GaugeChart
name="VRAM"
title={intl.formatMessage({
id: 'dashboard.vramutilization'
})}
@@ -73,6 +75,7 @@ const SystemLoad = () => {
</Col>
<Col span={12} style={{ height: smallChartHeight }}>
<GaugeChart
name="CPU"
title={intl.formatMessage({
id: 'dashboard.cpuutilization'
})}
@@ -82,6 +85,7 @@ const SystemLoad = () => {
</Col>
<Col span={12} style={{ height: smallChartHeight }}>
<GaugeChart
name="RAM"
title={intl.formatMessage({
id: 'dashboard.memoryutilization'
})}
+3 -11
View File
@@ -1,6 +1,6 @@
import { PageContainer } from '@ant-design/pro-components';
import { Spin } from 'antd';
import { useState } from 'react';
import PageBox from '../_components/page-box';
import DashboardInner from './components/dahboard-inner';
const Dashboard: React.FC = () => {
@@ -8,19 +8,11 @@ const Dashboard: React.FC = () => {
return (
<>
<PageContainer
ghost
extra={[]}
header={{
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
}
}}
>
<PageBox>
<Spin spinning={loading}>
<DashboardInner setLoading={setLoading} />
</Spin>
</PageContainer>
</PageBox>
</>
);
};
+4 -13
View File
@@ -7,7 +7,6 @@ import useBodyScroll from '@/hooks/use-body-scroll';
import { ScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context';
import { IS_FIRST_LOGIN, writeState } from '@/utils/localstore/index';
import { SearchOutlined, SyncOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Button, Input, Space, message } from 'antd';
@@ -16,6 +15,7 @@ import _ from 'lodash';
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import { createModel, queryCatalogList } from './apis';
import CatalogList from './components/catalog-list';
import DelopyBuiltInModal from './components/deploy-builtin-modal';
@@ -219,19 +219,10 @@ const Catalog: React.FC = () => {
}, [fetchData]);
return (
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'menu.modelCatalog' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<PageTools
marginBottom={22}
marginTop={0}
left={
<Space>
<Input
@@ -311,7 +302,7 @@ const Catalog: React.FC = () => {
onCancel={handleDeployModalCancel}
onOk={handleCreateModel}
></DelopyBuiltInModal>
</PageContainer>
</PageBox>
);
};
+4 -14
View File
@@ -14,10 +14,10 @@ import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
import useTableRowSelection from '@/hooks/use-table-row-selection';
import useTableSort from '@/hooks/use-table-sort';
import NoResult from '@/pages/_components/no-result';
import PageBox from '@/pages/_components/page-box';
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
import { handleBatchRequest } from '@/utils';
import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Button, Input, Space, message } from 'antd';
@@ -596,20 +596,10 @@ const Models: React.FC<ModelsProps> = ({
return (
<>
<PageContainer
className="models-page-container"
ghost
header={{
title: intl.formatMessage({ id: 'menu.models.deployment' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<PageTools
marginBottom={22}
marginTop={0}
left={
<Space>
<Input
@@ -742,7 +732,7 @@ const Models: React.FC<ModelsProps> = ({
onChange: handlePageChange
}}
></SealTable>
</PageContainer>
</PageBox>
<UpdateModelModal
open={openAddModal}
action={PageAction.EDIT}
+3 -3
View File
@@ -5,13 +5,13 @@ import CardList from '@/components/templates/card-list';
import CardSkeleton from '@/components/templates/card-skelton';
import useTableFetch from '@/hooks/use-table-fetch';
import { SyncOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate } from '@umijs/max';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
import { Button, Input, Space } from 'antd';
import React, { useCallback, useMemo } from 'react';
import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import { MY_MODELS_API, queryMyModels } from './apis';
import ModelItem from './components/model-item';
import {
@@ -172,7 +172,7 @@ const UserModels: React.FC = () => {
}, [dataSource.dataList, status]);
return (
<PageContainer
<PageBox
ghost
header={{
title: intl.formatMessage({ id: 'menu.models.userModels' }),
@@ -261,7 +261,7 @@ const UserModels: React.FC = () => {
subTitle={intl.formatMessage({ id: 'noresult.mymodels.subTitle' })}
></NoResult>
</ScrollerContext.Provider>
</PageContainer>
</PageBox>
);
};
+1 -1
View File
@@ -23,7 +23,7 @@ export const login = async (
});
};
export const logout = async (userInfo: any) => {
export const logout = async (userInfo?: any) => {
await request(`${AUTH_API}/logout`, {
method: 'POST'
});
@@ -5,6 +5,7 @@ import AudioPlayer from '@/components/audio-player';
import CopyButton from '@/components/copy-button';
import IconFont from '@/components/icon-font';
import UploadAudio from '@/components/upload-audio';
import { HEADER_HEIGHT } from '@/config/constants';
import routeCachekey from '@/config/route-cachekey';
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import { useCancelToken } from '@/hooks/use-request-token';
@@ -13,7 +14,6 @@ import { SendOutlined } from '@ant-design/icons';
import { useIntl, useSearchParams } from '@umijs/max';
import { Button, Spin, Tooltip } from 'antd';
import classNames from 'classnames';
import 'overlayscrollbars/overlayscrollbars.css';
import React, {
forwardRef,
useCallback,
@@ -289,7 +289,7 @@ const GroundSTT: React.FC<MessageProps> = forwardRef((props, ref) => {
<div
className="ground-left-wrapper"
style={{
height: 'calc(100vh - 72px)'
height: `calc(100vh - ${HEADER_HEIGHT}px)`
}}
>
<div className="ground-left">
@@ -1,6 +1,6 @@
import { HEADER_HEIGHT } from '@/config/constants';
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import CompareContext from '../../config/compare-context';
import {
@@ -39,7 +39,7 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList, loaded }) => {
const modelsCounterMap = useRef<Record<string, number>>({});
const modelRefs = useRef<any>({});
const chatListScrollRef = useRef<any>(null);
const boxHeight = 'calc(100vh - 72px)';
const boxHeight = `calc(100vh - ${HEADER_HEIGHT}px)`;
const [actions, setActions] = useState<MessageItemAction[]>([
'upload',
'delete',
@@ -0,0 +1,40 @@
import { useIntl } from '@umijs/max';
import { Button, Space } from 'antd';
import React from 'react';
import IconFont from '../../../components/icon-font';
const ViewCodeButtons: React.FC<{
handleViewCode: () => void;
handleToggleCollapse: () => void;
activeKey: string;
}> = ({ handleViewCode, handleToggleCollapse, activeKey }) => {
const intl = useIntl();
if (activeKey === 'compare') {
return null;
}
return (
<Space key="buttons" style={{ marginRight: 8 }}>
<Button
size="middle"
onClick={handleViewCode}
icon={<IconFont type="icon-code" className="font-size-16"></IconFont>}
>
{intl.formatMessage({ id: 'playground.viewcode' })}
</Button>
<Button
size="middle"
onClick={handleToggleCollapse}
icon={
<IconFont
type="icon-a-layout6-line"
className="font-size-16"
></IconFont>
}
></Button>
</Space>
);
};
export default ViewCodeButtons;
+26 -43
View File
@@ -1,15 +1,17 @@
import IconFont from '@/components/icon-font';
import HotKeys from '@/config/hotkeys';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { Button, Space } from 'antd';
import { useMemoizedFn } from 'ahooks';
import { Divider } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { PageContainerInner } from '../_components/page-box';
import { queryModelsList } from './apis';
import GroundEmbedding from './components/ground-embedding';
import ViewCodeButtons from './components/view-code-buttons';
import useCollapseLayout from './hooks/use-collapse-layout';
import './style/play-ground.less';
@@ -27,12 +29,12 @@ const PlaygroundEmbedding: React.FC = () => {
triggeredRef: groundLeftRef.current
});
const handleViewCode = useCallback(() => {
const handleViewCode = useMemoizedFn(() => {
groundLeftRef.current?.viewCode?.();
}, [groundLeftRef.current]);
const handleToggleCollapse = useCallback(() => {
});
const handleToggleCollapse = useMemoizedFn(() => {
groundLeftRef.current?.setCollapse?.();
}, [groundLeftRef.current]);
});
useEffect(() => {
const getModelListByEmbedding = async () => {
@@ -66,30 +68,6 @@ const PlaygroundEmbedding: React.FC = () => {
fetchData();
}, []);
const renderExtra = () => {
return (
<Space key="buttons">
<Button
size="middle"
onClick={handleViewCode}
icon={<IconFont type="icon-code" className="font-size-16"></IconFont>}
>
{intl.formatMessage({ id: 'playground.viewcode' })}
</Button>
<Button
size="middle"
onClick={handleToggleCollapse}
icon={
<IconFont
type="icon-a-layout6-line"
className="font-size-16"
></IconFont>
}
></Button>
</Space>
);
};
useHotkeys(
HotKeys.RIGHT.join(','),
() => {
@@ -101,17 +79,22 @@ const PlaygroundEmbedding: React.FC = () => {
);
return (
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'menu.playground.embedding' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={renderExtra()}
<PageContainerInner
className={classNames('playground-container chat')}
extra={[
<ViewCodeButtons
activeKey=""
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
key="view-code-buttons"
/>,
<Divider
key="divider"
type="vertical"
style={{ height: 24, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
>
<div className="play-ground">
<div className="chat">
@@ -122,7 +105,7 @@ const PlaygroundEmbedding: React.FC = () => {
></GroundEmbedding>
</div>
</div>
</PageContainer>
</PageContainerInner>
);
};
+27 -41
View File
@@ -1,19 +1,21 @@
import IconFont from '@/components/icon-font';
import breakpoints from '@/config/breakpoints';
import HotKeys from '@/config/hotkeys';
import useWindowResize from '@/hooks/use-window-resize';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { DiffOutlined, HighlightOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { Button, Segmented, Space, Tabs, TabsProps } from 'antd';
import { useMemoizedFn } from 'ahooks';
import { Divider, Segmented, Tabs, TabsProps } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { PageContainerInner } from '../_components/page-box';
import { queryModelsList } from './apis';
import GroundImages from './components/ground-images';
import ImageEdit from './components/image-edit';
import ViewCodeButtons from './components/view-code-buttons';
import './style/play-ground.less';
const TabsValueMap = {
@@ -44,21 +46,21 @@ const TextToImages: React.FC = () => {
];
}, [intl]);
const handleViewCode = useCallback(() => {
const handleViewCode = useMemoizedFn(() => {
if (activeKey === TabsValueMap.Tab1) {
groundTabRef1.current?.viewCode?.();
} else if (activeKey === TabsValueMap.Tab2) {
groundTabRef2.current?.viewCode?.();
}
}, [activeKey]);
});
const handleToggleCollapse = useCallback(() => {
const handleToggleCollapse = useMemoizedFn(() => {
if (activeKey === TabsValueMap.Tab1) {
groundTabRef1.current?.setCollapse?.();
return;
}
groundTabRef2.current?.setCollapse?.();
}, [activeKey]);
});
const items: TabsProps['items'] = useMemo(() => {
return [
@@ -124,30 +126,6 @@ const TextToImages: React.FC = () => {
fetchData();
}, []);
const renderExtra = useMemo(() => {
return (
<Space key="buttons">
<Button
size="middle"
onClick={handleViewCode}
icon={<IconFont type="icon-code" className="font-size-16"></IconFont>}
>
{intl.formatMessage({ id: 'playground.viewcode' })}
</Button>
<Button
size="middle"
onClick={handleToggleCollapse}
icon={
<IconFont
type="icon-a-layout6-line"
className="font-size-16"
></IconFont>
}
></Button>
</Space>
);
}, [intl, handleViewCode, handleToggleCollapse]);
const header = useMemo(() => {
return {
title: (
@@ -164,11 +142,7 @@ const TextToImages: React.FC = () => {
></Segmented>
}
</div>
),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
)
};
}, [optionsList]);
@@ -183,10 +157,22 @@ const TextToImages: React.FC = () => {
);
return (
<PageContainer
ghost
<PageContainerInner
header={header}
extra={renderExtra}
extra={[
<ViewCodeButtons
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
activeKey={activeKey}
key="view-code-buttons"
></ViewCodeButtons>,
<Divider
key="divider"
type="vertical"
style={{ height: 24, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
className={classNames('playground-container chat')}
>
<div className="play-ground">
@@ -194,7 +180,7 @@ const TextToImages: React.FC = () => {
<Tabs items={items} activeKey={activeKey}></Tabs>
</div>
</div>
</PageContainer>
</PageContainerInner>
);
};
+39 -45
View File
@@ -1,21 +1,32 @@
import IconFont from '@/components/icon-font';
import breakpoints from '@/config/breakpoints';
import HotKeys from '@/config/hotkeys';
import useWindowResize from '@/hooks/use-window-resize';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { MessageOutlined, OneToOneOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { Button, Segmented, Space, Tabs, TabsProps } from 'antd';
import { useMemoizedFn } from 'ahooks';
import { Divider, Segmented, Tabs, TabsProps } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import styled from 'styled-components';
import { PageContainerInner } from '../_components/page-box';
import { queryModelsList } from './apis';
import GroundLeft from './components/ground-left';
import MultipleChat from './components/multiple-chat';
import ViewCodeButtons from './components/view-code-buttons';
import './style/play-ground.less';
const Header = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 16px;
padding-inline: 32px;
`;
const Playground: React.FC = () => {
const intl = useIntl();
const { size } = useWindowResize();
@@ -40,27 +51,28 @@ const Playground: React.FC = () => {
];
}, [intl]);
const handleViewCode = useCallback(() => {
const handleViewCode = useMemoizedFn(() => {
if (activeKey === 'reranker') {
groundRerankerRef.current?.viewCode?.();
} else if (activeKey === 'chat') {
groundLeftRef.current?.viewCode?.();
}
}, [activeKey]);
});
const handleToggleCollapse = useCallback(() => {
const handleToggleCollapse = useMemoizedFn(() => {
if (activeKey === 'reranker') {
groundRerankerRef.current?.setCollapse?.();
return;
}
groundLeftRef.current?.setCollapse?.();
}, [activeKey]);
});
const items: TabsProps['items'] = useMemo(() => {
return [
{
key: 'chat',
label: 'Chat',
icon: <MessageOutlined />,
children: (
<GroundLeft ref={groundLeftRef} modelList={modelList}></GroundLeft>
)
@@ -68,6 +80,7 @@ const Playground: React.FC = () => {
{
key: 'compare',
label: 'Compare',
icon: <OneToOneOutlined />,
children: <MultipleChat modelList={modelList} loaded={loaded} />
}
];
@@ -105,33 +118,6 @@ const Playground: React.FC = () => {
fetchData();
}, []);
const renderExtra = useMemo(() => {
if (activeKey === 'compare') {
return false;
}
return (
<Space key="buttons">
<Button
size="middle"
onClick={handleViewCode}
icon={<IconFont type="icon-code" className="font-size-16"></IconFont>}
>
{intl.formatMessage({ id: 'playground.viewcode' })}
</Button>
<Button
size="middle"
onClick={handleToggleCollapse}
icon={
<IconFont
type="icon-a-layout6-line"
className="font-size-16"
></IconFont>
}
></Button>
</Space>
);
}, [activeKey, intl, handleViewCode, handleToggleCollapse]);
const header = useMemo(() => {
return {
title: (
@@ -148,11 +134,7 @@ const Playground: React.FC = () => {
></Segmented>
}
</div>
),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
)
};
}, [optionsList]);
@@ -169,21 +151,33 @@ const Playground: React.FC = () => {
);
return (
<PageContainer
ghost
header={header}
extra={renderExtra}
<PageContainerInner
className={classNames('playground-container', {
compare: activeKey === 'compare',
chat: activeKey !== 'compare'
})}
header={header}
extra={[
<ViewCodeButtons
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
activeKey={activeKey}
key="view-code-buttons"
/>,
<Divider
key="divider"
type="vertical"
style={{ height: 24, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
>
<div className="play-ground">
<div className="chat">
<Tabs items={items} activeKey={activeKey}></Tabs>
</div>
</div>
</PageContainer>
</PageContainerInner>
);
};
+26 -44
View File
@@ -1,21 +1,22 @@
import IconFont from '@/components/icon-font';
import HotKeys from '@/config/hotkeys';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { Button, Space } from 'antd';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
import { Divider } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { PageContainerInner } from '../_components/page-box';
import { queryModelsList } from './apis';
import GroundReranker from './components/ground-reranker';
import ViewCodeButtons from './components/view-code-buttons';
import useCollapseLayout from './hooks/use-collapse-layout';
import './style/play-ground.less';
const PlaygroundRerank: React.FC = () => {
const intl = useIntl();
const groundLeftRef = useRef<any>(null);
const groundRerankerRef = useRef<any>(null);
const [rerankerModelList, setRerankerModelList] = useState<
Global.BaseOption<string>[]
@@ -29,13 +30,13 @@ const PlaygroundRerank: React.FC = () => {
triggeredRef: groundRerankerRef.current
});
const handleViewCode = useCallback(() => {
const handleViewCode = useMemoizedFn(() => {
groundRerankerRef.current?.viewCode?.();
}, [groundRerankerRef]);
});
const handleToggleCollapse = useCallback(() => {
const handleToggleCollapse = useMemoizedFn(() => {
groundRerankerRef.current?.setCollapse?.();
}, [groundRerankerRef]);
});
useEffect(() => {
const getModelListByReranker = async () => {
@@ -71,30 +72,6 @@ const PlaygroundRerank: React.FC = () => {
fetchData();
}, []);
const renderExtra = () => {
return (
<Space key="buttons">
<Button
size="middle"
onClick={handleViewCode}
icon={<IconFont type="icon-code" className="font-size-16"></IconFont>}
>
{intl.formatMessage({ id: 'playground.viewcode' })}
</Button>
<Button
size="middle"
onClick={handleToggleCollapse}
icon={
<IconFont
type="icon-a-layout6-line"
className="font-size-16"
></IconFont>
}
></Button>
</Space>
);
};
useHotkeys(
HotKeys.RIGHT.join(','),
() => {
@@ -106,17 +83,22 @@ const PlaygroundRerank: React.FC = () => {
);
return (
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'menu.playground.rerank' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={renderExtra()}
<PageContainerInner
className={classNames('playground-container chat')}
extra={[
<ViewCodeButtons
activeKey=""
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
key="view-code-buttons"
></ViewCodeButtons>,
<Divider
key="divider"
type="vertical"
style={{ height: 24, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
>
<div className="play-ground">
<div className="chat">
@@ -127,7 +109,7 @@ const PlaygroundRerank: React.FC = () => {
></GroundReranker>
</div>
</div>
</PageContainer>
</PageContainerInner>
);
};
+27 -40
View File
@@ -2,18 +2,21 @@ import IconFont from '@/components/icon-font';
import breakpoints from '@/config/breakpoints';
import HotKeys from '@/config/hotkeys';
import useWindowResize from '@/hooks/use-window-resize';
import { ExtraContent } from '@/layouts/extraRender';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { AudioOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useSearchParams } from '@umijs/max';
import { Button, Segmented, Space, Tabs, TabsProps } from 'antd';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
import { Divider, Segmented, Tabs, TabsProps } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { PageContainerInner } from '../_components/page-box';
import { queryModelsList } from './apis';
import GroundSTT from './components/ground-stt';
import GroundTTS from './components/ground-tts';
import ViewCodeButtons from './components/view-code-buttons';
import './style/play-ground.less';
const TabsValueMap = {
@@ -53,21 +56,21 @@ const Playground: React.FC = () => {
];
}, [intl]);
const handleViewCode = useCallback(() => {
const handleViewCode = useMemoizedFn(() => {
if (activeKey === TabsValueMap.Tab1) {
groundTabRef1.current?.viewCode?.();
} else if (activeKey === TabsValueMap.Tab2) {
groundTabRef2.current?.viewCode?.();
}
}, [activeKey]);
});
const handleToggleCollapse = useCallback(() => {
const handleToggleCollapse = useMemoizedFn(() => {
if (activeKey === TabsValueMap.Tab1) {
groundTabRef1.current?.setCollapse?.();
return;
}
groundTabRef2.current?.setCollapse?.();
}, [activeKey]);
});
const items: TabsProps['items'] = useMemo(() => {
return [
@@ -160,30 +163,6 @@ const Playground: React.FC = () => {
fetchData();
}, []);
const renderExtra = useMemo(() => {
return (
<Space key="buttons">
<Button
size="middle"
onClick={handleViewCode}
icon={<IconFont type="icon-code" className="font-size-16"></IconFont>}
>
{intl.formatMessage({ id: 'playground.viewcode' })}
</Button>
<Button
size="middle"
onClick={handleToggleCollapse}
icon={
<IconFont
type="icon-a-layout6-line"
className="font-size-16"
></IconFont>
}
></Button>
</Space>
);
}, [handleToggleCollapse, handleViewCode, intl]);
const header = useMemo(() => {
return {
title: (
@@ -201,11 +180,7 @@ const Playground: React.FC = () => {
></Segmented>
}
</div>
),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
)
};
}, [activeKey, optionsList]);
@@ -220,10 +195,22 @@ const Playground: React.FC = () => {
);
return (
<PageContainer
ghost
<PageContainerInner
header={header}
extra={renderExtra}
extra={[
<ViewCodeButtons
activeKey=""
handleViewCode={handleViewCode}
handleToggleCollapse={handleToggleCollapse}
key="view-code-buttons"
></ViewCodeButtons>,
<Divider
key="divider"
type="vertical"
style={{ height: 24, marginInline: 16 }}
/>,
<ExtraContent key="extra-content" />
]}
className={classNames('playground-container', {
compare: activeKey === 'compare',
chat: activeKey !== 'compare'
@@ -234,7 +221,7 @@ const Playground: React.FC = () => {
<Tabs items={items} activeKey={activeKey}></Tabs>
</div>
</div>
</PageContainer>
</PageContainerInner>
);
};
+4 -2
View File
@@ -1,3 +1,5 @@
@HEADER_HEIGHT: 56px;
.ground-left-wrapper {
display: flex;
@@ -7,7 +9,7 @@
width: 390px;
border-left: 1px solid var(--ant-color-split);
transition: width 0.3s ease;
height: calc(100vh - 72px);
height: calc(100vh - @HEADER_HEIGHT);
padding-top: 16px;
overflow-y: auto;
@@ -40,7 +42,7 @@
justify-content: space-between;
flex-direction: column;
position: relative;
height: calc(100vh - 72px);
height: calc(100vh - @HEADER_HEIGHT);
width: calc(100% - 390px);
.message-list-wrap {
+12 -11
View File
@@ -1,3 +1,5 @@
@HEADER_HEIGHT: 56px;
.play-ground {
display: flex;
align-items: flex-start;
@@ -37,7 +39,7 @@
.params {
overflow: hidden;
height: calc(100vh - 72px);
height: calc(100vh - @HEADER_HEIGHT);
.collapse {
width: 0;
@@ -81,20 +83,19 @@
.ant-page-header {
position: relative;
height: 72px;
}
&.chat {
.ant-page-header {
&::after {
position: absolute;
content: '';
left: 32px;
right: 32px;
bottom: 0;
height: 1px;
border-bottom: 1px solid var(--ant-color-split);
}
// &::after {
// position: absolute;
// content: '';
// left: 32px;
// right: 32px;
// bottom: 0;
// height: 1px;
// border-bottom: 1px solid var(--ant-color-split);
// }
}
}
+10 -23
View File
@@ -1,9 +1,9 @@
import useTabActive from '@/hooks/use-tab-active';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useModel } from '@umijs/max';
import { TabsProps } from 'antd';
import { Tabs, TabsProps } from 'antd';
import React, { useCallback, useMemo, useState } from 'react';
import styled from 'styled-components';
import PageBox from '../_components/page-box';
import Appearance from './components/appearance';
import ModifyPasswordn from './components/modify-password';
@@ -53,27 +53,14 @@ const Profile: React.FC = () => {
}, []);
return (
<Wrapper>
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'users.settings.title' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
}
}}
tabList={items}
onTabChange={handleChangeTab}
tabActiveKey={activeKey}
tabProps={{
type: 'card',
style: {
marginTop: 78
}
}}
extra={[]}
></PageContainer>
</Wrapper>
<PageBox>
<Tabs
activeKey={activeKey}
onChange={handleChangeTab}
items={items}
type="card"
/>
</PageBox>
);
};
+3 -13
View File
@@ -2,8 +2,8 @@ import IconFont from '@/components/icon-font';
import { FilterBar } from '@/components/page-tools';
import useTableFetch from '@/hooks/use-table-fetch';
import NoResult from '@/pages/_components/no-result';
import PageBox from '@/pages/_components/page-box';
import { queryClusterList } from '@/pages/cluster-management/apis';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { ConfigProvider, Table } from 'antd';
import React, { useEffect, useState } from 'react';
@@ -76,17 +76,7 @@ const GPUList: React.FC = () => {
return (
<>
<PageContainer
ghost
header={{
title: 'GPUs',
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<FilterBar
marginBottom={22}
marginTop={30}
@@ -116,7 +106,7 @@ const GPUList: React.FC = () => {
}}
></Table>
</ConfigProvider>
</PageContainer>
</PageBox>
</>
);
};
+3 -13
View File
@@ -7,6 +7,7 @@ import useAppUtils from '@/hooks/use-app-utils';
import useBodyScroll from '@/hooks/use-body-scroll';
import useTableFetch from '@/hooks/use-table-fetch';
import NoResult from '@/pages/_components/no-result';
import PageBox from '@/pages/_components/page-box';
import { createModel } from '@/pages/llmodels/apis';
import DeployModal from '@/pages/llmodels/components/deploy-modal';
import { modelSourceMap } from '@/pages/llmodels/config';
@@ -20,7 +21,6 @@ import DownloadModal from '@/pages/llmodels/download';
import useCheckBackend from '@/pages/llmodels/hooks/use-check-backend';
import { useGenerateWorkerOptions } from '@/pages/llmodels/hooks/use-form-initial-values';
import useRecognizeAudio from '@/pages/llmodels/hooks/use-recognize-audio';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { ConfigProvider, Table, message } from 'antd';
@@ -290,17 +290,7 @@ const ModelFiles = () => {
return (
<>
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'resources.modelfiles.modelfile' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<FilterBar
marginBottom={22}
marginTop={30}
@@ -365,7 +355,7 @@ const ModelFiles = () => {
isGGUF={openDeployModal.isGGUF}
clusterList={clusterList}
></DeployModal>
</PageContainer>
</PageBox>
</>
);
};
+3 -11
View File
@@ -2,8 +2,8 @@ import DeleteModal from '@/components/delete-modal';
import IconFont from '@/components/icon-font';
import { FilterBar } from '@/components/page-tools';
import useTableFetch from '@/hooks/use-table-fetch';
import PageBox from '@/pages/_components/page-box';
import { queryClusterList } from '@/pages/cluster-management/apis';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Button, ConfigProvider, Table, message } from 'antd';
@@ -227,7 +227,7 @@ const Workers: React.FC = () => {
return (
<>
<PageContainer
<PageBox
ghost
footer={[
<TerminalTabs
@@ -239,14 +239,6 @@ const Workers: React.FC = () => {
onClose={handleTerminalClose}
/>
]}
header={{
title: intl.formatMessage({ id: 'resources.nodes' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<FilterBar
showSelect={true}
@@ -300,7 +292,7 @@ const Workers: React.FC = () => {
setWorkerDetailStatus({ currentData: null, open: false })
}
/>
</PageContainer>
</PageBox>
</>
);
};
+3 -13
View File
@@ -4,12 +4,12 @@ import { FilterBar } from '@/components/page-tools';
import { PageAction } from '@/config';
import type { PageActionType } from '@/config/types';
import useTableFetch from '@/hooks/use-table-fetch';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useModel } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Button, ConfigProvider, message, Table } from 'antd';
import { useMemo, useState } from 'react';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import { createUser, deleteUser, queryUsersList, updateUser } from './apis';
import AddModal from './components/add-modal';
import { FormData, ListItem } from './config/types';
@@ -165,17 +165,7 @@ const Users: React.FC = () => {
return (
<>
<PageContainer
ghost
header={{
title: intl.formatMessage({ id: 'users.title' }),
style: {
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
extra={[]}
>
<PageBox>
<FilterBar
marginBottom={22}
marginTop={30}
@@ -205,7 +195,7 @@ const Users: React.FC = () => {
}}
></Table>
</ConfigProvider>
</PageContainer>
</PageBox>
<AddModal
open={openAddModalStatus.open}
action={openAddModalStatus.action}