refactor: page layout
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }]
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -167,7 +167,7 @@ export const FilterBar: React.FC<FilterBarProps> = (props) => {
|
||||
return (
|
||||
<PageTools
|
||||
marginBottom={marginBottom}
|
||||
marginTop={marginTop}
|
||||
marginTop={0}
|
||||
left={
|
||||
<Space>
|
||||
<Input
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const HEADER_HEIGHT = 72;
|
||||
export const HEADER_HEIGHT = 56;
|
||||
|
||||
Vendored
+1
-1
@@ -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>;
|
||||
|
||||
|
||||
@@ -118,6 +118,12 @@ body {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.ant-pro-page-container-affix {
|
||||
.ant-affix {
|
||||
top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-modal-confirm-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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'
|
||||
})}
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user