refactor(layout): adopt header-slot page container across pages
This commit is contained in:
+5
-29
@@ -52,21 +52,6 @@ import { ExtraContent } from './extraRender';
|
|||||||
import { patchRoutes } from './runtime';
|
import { patchRoutes } from './runtime';
|
||||||
import SiderMenu from './sider-menu';
|
import SiderMenu from './sider-menu';
|
||||||
|
|
||||||
// Pages that use the page container in the page
|
|
||||||
const NO_CONTAINER_PAGES = [
|
|
||||||
'chat',
|
|
||||||
'rerank',
|
|
||||||
'embedding',
|
|
||||||
'speech',
|
|
||||||
'image',
|
|
||||||
'text2images',
|
|
||||||
'clusterDetail',
|
|
||||||
'clusterCreate',
|
|
||||||
'benchmarkDetail',
|
|
||||||
'deployment',
|
|
||||||
'video'
|
|
||||||
];
|
|
||||||
|
|
||||||
const CHECK_RESOURCE_PATH = [
|
const CHECK_RESOURCE_PATH = [
|
||||||
'/resources/workers',
|
'/resources/workers',
|
||||||
'/resources/clusters/list',
|
'/resources/clusters/list',
|
||||||
@@ -269,11 +254,6 @@ export default (props: any) => {
|
|||||||
[location.pathname]
|
[location.pathname]
|
||||||
);
|
);
|
||||||
|
|
||||||
const isNoContainerPage = useMemo(() => {
|
|
||||||
// @ts-ignore
|
|
||||||
return NO_CONTAINER_PAGES.includes(matchedRoute?.name as string);
|
|
||||||
}, [matchedRoute]);
|
|
||||||
|
|
||||||
const collapsed = useMemo(() => {
|
const collapsed = useMemo(() => {
|
||||||
return userSettings.collapsed || false;
|
return userSettings.collapsed || false;
|
||||||
}, [userSettings.collapsed]);
|
}, [userSettings.collapsed]);
|
||||||
@@ -469,15 +449,11 @@ export default (props: any) => {
|
|||||||
unAccessible={runtimeConfig?.unAccessible}
|
unAccessible={runtimeConfig?.unAccessible}
|
||||||
noAccessible={runtimeConfig?.noAccessible}
|
noAccessible={runtimeConfig?.noAccessible}
|
||||||
>
|
>
|
||||||
{isNoContainerPage ? (
|
<PageContainerInner>
|
||||||
<Outlet />
|
<div>
|
||||||
) : (
|
<Outlet />
|
||||||
<PageContainerInner>
|
</div>
|
||||||
<div>
|
</PageContainerInner>
|
||||||
<Outlet />
|
|
||||||
</div>
|
|
||||||
</PageContainerInner>
|
|
||||||
)}
|
|
||||||
</Exception>
|
</Exception>
|
||||||
</div>
|
</div>
|
||||||
{NoResourceModal}
|
{NoResourceModal}
|
||||||
|
|||||||
@@ -7,11 +7,61 @@ import {
|
|||||||
import { useOverlayScroller } from '@gpustack/core-ui';
|
import { useOverlayScroller } from '@gpustack/core-ui';
|
||||||
import { Divider } from 'antd';
|
import { Divider } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useContext, useEffect, useRef } from 'react';
|
import {
|
||||||
|
createContext,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import pageBoxCss from './styles/page-box.less';
|
import pageBoxCss from './styles/page-box.less';
|
||||||
|
|
||||||
const paddingInlinePageContainerContent = 24;
|
const paddingInlinePageContainerContent = 24;
|
||||||
|
|
||||||
|
type HeaderSlotContextValue = {
|
||||||
|
leftEl: HTMLElement | null;
|
||||||
|
rightEl: HTMLElement | null;
|
||||||
|
setContentStyle: (style: React.CSSProperties | undefined) => () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const HeaderSlotContext = createContext<HeaderSlotContextValue | null>(null);
|
||||||
|
|
||||||
|
// Pages render <HeaderLeft> / <HeaderRight> as part of their JSX; the children
|
||||||
|
// are portaled into the layout-owned PageContainerInner header bar so the
|
||||||
|
// shell never unmounts between routes. Visibility of the default title /
|
||||||
|
// right divider is driven by CSS (`:empty` / `:not(:empty)`) on the portal
|
||||||
|
// target, so they react synchronously to DOM mutations — no React state, no
|
||||||
|
// re-renders, no inter-frame flicker.
|
||||||
|
export const HeaderLeft: React.FC<{ children: React.ReactNode }> = ({
|
||||||
|
children
|
||||||
|
}) => {
|
||||||
|
const ctx = useContext(HeaderSlotContext);
|
||||||
|
return ctx?.leftEl ? createPortal(children, ctx.leftEl) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HeaderRight: React.FC<{ children: React.ReactNode }> = ({
|
||||||
|
children
|
||||||
|
}) => {
|
||||||
|
const ctx = useContext(HeaderSlotContext);
|
||||||
|
return ctx?.rightEl ? createPortal(children, ctx.rightEl) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pages that need to override the layout-owned content wrapper style
|
||||||
|
// (e.g. playground pages that want zero padding) call this hook in render.
|
||||||
|
// Applied synchronously via useLayoutEffect to avoid first-paint flicker.
|
||||||
|
export const usePageContentStyle = (style?: React.CSSProperties): void => {
|
||||||
|
const ctx = useContext(HeaderSlotContext);
|
||||||
|
const stable = JSON.stringify(style ?? null);
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (!ctx) return;
|
||||||
|
return ctx.setContentStyle(style);
|
||||||
|
}, [stable, ctx?.setContentStyle]);
|
||||||
|
};
|
||||||
|
|
||||||
export const PageContainerInner: React.FC<
|
export const PageContainerInner: React.FC<
|
||||||
PageContainerProps & {
|
PageContainerProps & {
|
||||||
leftContent?: React.ReactNode;
|
leftContent?: React.ReactNode;
|
||||||
@@ -26,6 +76,11 @@ export const PageContainerInner: React.FC<
|
|||||||
});
|
});
|
||||||
const pageContext = useContext(RouteContext);
|
const pageContext = useContext(RouteContext);
|
||||||
const contentWrapperRef = useRef<HTMLDivElement>(null);
|
const contentWrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
const [leftEl, setLeftEl] = useState<HTMLDivElement | null>(null);
|
||||||
|
const [rightEl, setRightEl] = useState<HTMLDivElement | null>(null);
|
||||||
|
const [contentStyleOverride, setContentStyleOverride] = useState<
|
||||||
|
React.CSSProperties | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (contentWrapperRef.current) {
|
if (contentWrapperRef.current) {
|
||||||
@@ -34,43 +89,67 @@ export const PageContainerInner: React.FC<
|
|||||||
}
|
}
|
||||||
}, [initialize, contentWrapperRef]);
|
}, [initialize, contentWrapperRef]);
|
||||||
|
|
||||||
|
const setContentStyle = useCallback(
|
||||||
|
(style: React.CSSProperties | undefined) => {
|
||||||
|
setContentStyleOverride(style);
|
||||||
|
return () => setContentStyleOverride(undefined);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const slotValue = useMemo<HeaderSlotContextValue>(
|
||||||
|
() => ({
|
||||||
|
leftEl,
|
||||||
|
rightEl,
|
||||||
|
setContentStyle
|
||||||
|
}),
|
||||||
|
[leftEl, rightEl, setContentStyle]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={pageBoxCss.containerWrapper}>
|
<HeaderSlotContext.Provider value={slotValue}>
|
||||||
<PageContainer
|
<div className={pageBoxCss.containerWrapper}>
|
||||||
{...rest}
|
<PageContainer
|
||||||
fixedHeader={false}
|
{...rest}
|
||||||
title={false}
|
fixedHeader={false}
|
||||||
pageHeaderRender={false}
|
title={false}
|
||||||
style={{
|
pageHeaderRender={false}
|
||||||
flex: 1
|
style={{
|
||||||
}}
|
flex: 1
|
||||||
token={{
|
}}
|
||||||
paddingInlinePageContainerContent: paddingInlinePageContainerContent
|
token={{
|
||||||
}}
|
paddingInlinePageContainerContent: paddingInlinePageContainerContent
|
||||||
>
|
}}
|
||||||
<div className={pageBoxCss.title}>
|
|
||||||
<div className={pageBoxCss.left}>
|
|
||||||
{leftContent || pageContext.title}
|
|
||||||
</div>
|
|
||||||
<div className={pageBoxCss.right}>
|
|
||||||
{rightContent && (
|
|
||||||
<div>
|
|
||||||
{rightContent}
|
|
||||||
<Divider orientation="vertical" style={{ margin: '0 16px' }} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<ExtraContent />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classNames(pageBoxCss.contentWrapper)}
|
|
||||||
style={styles?.containerWrapper}
|
|
||||||
ref={contentWrapperRef}
|
|
||||||
>
|
>
|
||||||
{children}
|
<div className={pageBoxCss.title}>
|
||||||
</div>
|
<div className={pageBoxCss.left}>
|
||||||
</PageContainer>
|
<div ref={setLeftEl} className={pageBoxCss.leftSlot} />
|
||||||
</div>
|
{leftContent}
|
||||||
|
<span className={pageBoxCss.defaultTitle}>
|
||||||
|
{pageContext.title}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={pageBoxCss.right}>
|
||||||
|
<div ref={setRightEl} className={pageBoxCss.rightSlot} />
|
||||||
|
{rightContent}
|
||||||
|
<Divider
|
||||||
|
className={pageBoxCss.divider}
|
||||||
|
orientation="vertical"
|
||||||
|
style={{ margin: '0 16px' }}
|
||||||
|
/>
|
||||||
|
<ExtraContent />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(pageBoxCss.contentWrapper)}
|
||||||
|
style={{ ...styles?.containerWrapper, ...contentStyleOverride }}
|
||||||
|
ref={contentWrapperRef}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</PageContainer>
|
||||||
|
</div>
|
||||||
|
</HeaderSlotContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -70,14 +70,44 @@
|
|||||||
height: 56px;
|
height: 56px;
|
||||||
border-bottom: 1px solid var(--ant-color-split);
|
border-bottom: 1px solid var(--ant-color-split);
|
||||||
|
|
||||||
|
// `.left` claims all the space between the title's left edge and `.right`.
|
||||||
|
// Because the container width is fixed regardless of inner content, the
|
||||||
|
// right side never shifts during route transitions and the content inside
|
||||||
|
// .left is anchored to the left edge — no horizontal jitter.
|
||||||
.left {
|
.left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leftSlot,
|
||||||
|
.rightSlot {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defaultTitle {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Portal-driven visibility: when a page's HeaderLeft / HeaderRight
|
||||||
|
// portal target has children, hide the default title / show the divider.
|
||||||
|
// Using `:empty` (rather than React state) keeps visibility synchronous
|
||||||
|
// with the DOM mutation, so there is no inter-frame flicker on route
|
||||||
|
// transitions.
|
||||||
|
.leftSlot:not(:empty) ~ .defaultTitle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightSlot:empty ~ .divider {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { BaseSelect, DeleteModal } from '@gpustack/core-ui';
|
|||||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { PageContainerInner } from '../_components/page-box';
|
import { HeaderLeft } from '../_components/page-box';
|
||||||
import PageBreadcrumb from '../_components/page-breadcrumb';
|
import PageBreadcrumb from '../_components/page-breadcrumb';
|
||||||
import { deleteBenchmark } from './apis';
|
import { deleteBenchmark } from './apis';
|
||||||
import DetailContent from './components/detail-content';
|
import DetailContent from './components/detail-content';
|
||||||
@@ -122,9 +122,10 @@ const Details: React.FC = () => {
|
|||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
leftContent={<PageBreadcrumb items={breadcrumbItems} />}
|
<HeaderLeft>
|
||||||
>
|
<PageBreadcrumb items={breadcrumbItems} />
|
||||||
|
</HeaderLeft>
|
||||||
<DetailContext.Provider
|
<DetailContext.Provider
|
||||||
value={{
|
value={{
|
||||||
detailData: detailData || {},
|
detailData: detailData || {},
|
||||||
@@ -164,7 +165,7 @@ const Details: React.FC = () => {
|
|||||||
onCancel={closeViewLogsModal}
|
onCancel={closeViewLogsModal}
|
||||||
></ViewLogsModal>
|
></ViewLogsModal>
|
||||||
<DeleteModal ref={modalRef}></DeleteModal>
|
<DeleteModal ref={modalRef}></DeleteModal>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { IconFont } from '@gpustack/core-ui';
|
|||||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||||
import { Tabs, type TabsProps } from 'antd';
|
import { Tabs, type TabsProps } from 'antd';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import { PageContainerInner } from '../_components/page-box';
|
import { HeaderLeft } from '../_components/page-box';
|
||||||
import PageBreadcrumb from '../_components/page-breadcrumb';
|
import PageBreadcrumb from '../_components/page-breadcrumb';
|
||||||
import ClusterBasic from './components/detail/cluster-basic';
|
import ClusterBasic from './components/detail/cluster-basic';
|
||||||
import ClusterSystemLoad from './components/detail/cluster-system-load';
|
import ClusterSystemLoad from './components/detail/cluster-system-load';
|
||||||
@@ -46,11 +46,10 @@ const ClusterDetailModal = () => {
|
|||||||
) ?? []) as TabItem[];
|
) ?? []) as TabItem[];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
header={{
|
<HeaderLeft>
|
||||||
title: <PageBreadcrumb items={breadcrumbItems} />
|
<PageBreadcrumb items={breadcrumbItems} />
|
||||||
}}
|
</HeaderLeft>
|
||||||
>
|
|
||||||
<ClusterBasic clusterId={Number(id)}></ClusterBasic>
|
<ClusterBasic clusterId={Number(id)}></ClusterBasic>
|
||||||
<ClusterSystemLoad clusterId={Number(id)}></ClusterSystemLoad>
|
<ClusterSystemLoad clusterId={Number(id)}></ClusterSystemLoad>
|
||||||
<Tabs
|
<Tabs
|
||||||
@@ -75,7 +74,7 @@ const ClusterDetailModal = () => {
|
|||||||
...extraTabs
|
...extraTabs
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { PageContainerInner } from '@/pages/_components/page-box';
|
import {
|
||||||
|
HeaderLeft,
|
||||||
|
usePageContentStyle
|
||||||
|
} from '@/pages/_components/page-box';
|
||||||
import { IconFont } from '@gpustack/core-ui';
|
import { IconFont } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
@@ -105,15 +108,11 @@ const LLModels: React.FC = () => {
|
|||||||
};
|
};
|
||||||
}, [activeKey]);
|
}, [activeKey]);
|
||||||
|
|
||||||
|
usePageContentStyle({ padding: 0 });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
leftContent={title}
|
<HeaderLeft>{title}</HeaderLeft>
|
||||||
styles={{
|
|
||||||
containerWrapper: {
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DeploymentsContext.Provider
|
<DeploymentsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
generateFormValues,
|
generateFormValues,
|
||||||
@@ -138,7 +137,7 @@ const LLModels: React.FC = () => {
|
|||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
></Tabs>
|
></Tabs>
|
||||||
</DeploymentsContext.Provider>
|
</DeploymentsContext.Provider>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ import { MessageOutlined, OneToOneOutlined } from '@ant-design/icons';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Segmented, Tabs, TabsProps } from 'antd';
|
import { Segmented, Tabs, TabsProps } from 'antd';
|
||||||
import classNames from 'classnames';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { PageContainerInner } from '../../_components/page-box';
|
import {
|
||||||
|
HeaderLeft,
|
||||||
|
HeaderRight,
|
||||||
|
usePageContentStyle
|
||||||
|
} from '../../_components/page-box';
|
||||||
import { queryModelsList } from '../apis';
|
import { queryModelsList } from '../apis';
|
||||||
import MultipleChat from '../components/multiple-chat';
|
import MultipleChat from '../components/multiple-chat';
|
||||||
import ViewCodeButtons from '../components/view-code-buttons';
|
import ViewCodeButtons from '../components/view-code-buttons';
|
||||||
@@ -148,53 +151,43 @@ const Playground: React.FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
usePageContentStyle({ padding: 0 });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
className={classNames('playground-container', {
|
<HeaderLeft>
|
||||||
compare: activeKey === 'compare',
|
|
||||||
chat: activeKey !== 'compare'
|
|
||||||
})}
|
|
||||||
styles={{
|
|
||||||
containerWrapper: {
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
leftContent={
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="font-600 flex-center">
|
<span className="font-600 flex-center">
|
||||||
{intl.formatMessage({ id: 'menu.playground.chat' })}
|
{intl.formatMessage({ id: 'menu.playground.chat' })}
|
||||||
</span>
|
</span>
|
||||||
{
|
<Segmented
|
||||||
<Segmented
|
shape="round"
|
||||||
shape="round"
|
style={{
|
||||||
style={{
|
backgroundColor: 'var(--ant-color-fill-secondary)',
|
||||||
backgroundColor: 'var(--ant-color-fill-secondary)',
|
fontSize: 13
|
||||||
fontSize: 13
|
}}
|
||||||
}}
|
size="middle"
|
||||||
size="middle"
|
className="m-l-24 font-400"
|
||||||
className="m-l-24 font-400"
|
options={optionsList}
|
||||||
options={optionsList}
|
value={activeKey}
|
||||||
value={activeKey}
|
onChange={(key) => setActiveKey(key)}
|
||||||
onChange={(key) => setActiveKey(key)}
|
></Segmented>
|
||||||
></Segmented>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</HeaderLeft>
|
||||||
rightContent={
|
<HeaderRight>
|
||||||
<ViewCodeButtons
|
<ViewCodeButtons
|
||||||
handleViewCode={handleViewCode}
|
handleViewCode={handleViewCode}
|
||||||
handleToggleCollapse={handleToggleCollapse}
|
handleToggleCollapse={handleToggleCollapse}
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
key="view-code-buttons"
|
key="view-code-buttons"
|
||||||
/>
|
/>
|
||||||
}
|
</HeaderRight>
|
||||||
>
|
|
||||||
<div className="play-ground">
|
<div className="play-ground">
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
<Tabs items={items} activeKey={activeKey}></Tabs>
|
<Tabs items={items} activeKey={activeKey}></Tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import HotKeys from '@/config/hotkeys';
|
import HotKeys from '@/config/hotkeys';
|
||||||
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import classNames from 'classnames';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { PageContainerInner } from '../../_components/page-box';
|
import {
|
||||||
|
HeaderRight,
|
||||||
|
usePageContentStyle
|
||||||
|
} from '../../_components/page-box';
|
||||||
import { queryModelsList } from '../apis';
|
import { queryModelsList } from '../apis';
|
||||||
import ViewCodeButtons from '../components/view-code-buttons';
|
import ViewCodeButtons from '../components/view-code-buttons';
|
||||||
import useCollapseLayout from '../hooks/use-collapse-layout';
|
import useCollapseLayout from '../hooks/use-collapse-layout';
|
||||||
@@ -14,7 +15,6 @@ import '../style/play-ground.less';
|
|||||||
import GroundEmbedding from './page';
|
import GroundEmbedding from './page';
|
||||||
|
|
||||||
const PlaygroundEmbedding: React.FC = () => {
|
const PlaygroundEmbedding: React.FC = () => {
|
||||||
const intl = useIntl();
|
|
||||||
const groundLeftRef = useRef<any>(null);
|
const groundLeftRef = useRef<any>(null);
|
||||||
const [modelList, setModelList] = useState<Global.BaseOption<string>[]>([]);
|
const [modelList, setModelList] = useState<Global.BaseOption<string>[]>([]);
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
@@ -76,23 +76,18 @@ const PlaygroundEmbedding: React.FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
usePageContentStyle({ padding: 0 });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
className={classNames('playground-container chat')}
|
<HeaderRight>
|
||||||
styles={{
|
|
||||||
containerWrapper: {
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
rightContent={
|
|
||||||
<ViewCodeButtons
|
<ViewCodeButtons
|
||||||
activeKey=""
|
activeKey=""
|
||||||
handleViewCode={handleViewCode}
|
handleViewCode={handleViewCode}
|
||||||
handleToggleCollapse={handleToggleCollapse}
|
handleToggleCollapse={handleToggleCollapse}
|
||||||
key="view-code-buttons"
|
key="view-code-buttons"
|
||||||
/>
|
/>
|
||||||
}
|
</HeaderRight>
|
||||||
>
|
|
||||||
<div className="play-ground">
|
<div className="play-ground">
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
<GroundEmbedding
|
<GroundEmbedding
|
||||||
@@ -102,7 +97,7 @@ const PlaygroundEmbedding: React.FC = () => {
|
|||||||
></GroundEmbedding>
|
></GroundEmbedding>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ import { DiffOutlined, HighlightOutlined } from '@ant-design/icons';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Segmented, Tabs, TabsProps } from 'antd';
|
import { Segmented, Tabs, TabsProps } from 'antd';
|
||||||
import classNames from 'classnames';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { PageContainerInner } from '../../_components/page-box';
|
import {
|
||||||
|
HeaderLeft,
|
||||||
|
HeaderRight,
|
||||||
|
usePageContentStyle
|
||||||
|
} from '../../_components/page-box';
|
||||||
import { queryModelsList } from '../apis';
|
import { queryModelsList } from '../apis';
|
||||||
import ViewCodeButtons from '../components/view-code-buttons';
|
import ViewCodeButtons from '../components/view-code-buttons';
|
||||||
import '../style/play-ground.less';
|
import '../style/play-ground.less';
|
||||||
@@ -154,9 +157,11 @@ const TextToImages: React.FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
usePageContentStyle({ padding: 0 });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
leftContent={
|
<HeaderLeft>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="font-600 flex-center">
|
<span className="font-600 flex-center">
|
||||||
{intl.formatMessage({ id: 'menu.playground.text2images' })}
|
{intl.formatMessage({ id: 'menu.playground.text2images' })}
|
||||||
@@ -173,24 +178,21 @@ const TextToImages: React.FC = () => {
|
|||||||
onChange={(key) => setActiveKey(key)}
|
onChange={(key) => setActiveKey(key)}
|
||||||
></Segmented>
|
></Segmented>
|
||||||
</div>
|
</div>
|
||||||
}
|
</HeaderLeft>
|
||||||
rightContent={
|
<HeaderRight>
|
||||||
<ViewCodeButtons
|
<ViewCodeButtons
|
||||||
handleViewCode={handleViewCode}
|
handleViewCode={handleViewCode}
|
||||||
handleToggleCollapse={handleToggleCollapse}
|
handleToggleCollapse={handleToggleCollapse}
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
key="view-code-buttons"
|
key="view-code-buttons"
|
||||||
></ViewCodeButtons>
|
></ViewCodeButtons>
|
||||||
}
|
</HeaderRight>
|
||||||
styles={{ containerWrapper: { padding: 0 } }}
|
|
||||||
className={classNames('playground-container chat')}
|
|
||||||
>
|
|
||||||
<div className="play-ground">
|
<div className="play-ground">
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
<Tabs items={items} activeKey={activeKey}></Tabs>
|
<Tabs items={items} activeKey={activeKey}></Tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import HotKeys from '@/config/hotkeys';
|
import HotKeys from '@/config/hotkeys';
|
||||||
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
||||||
import classNames from 'classnames';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { PageContainerInner } from '../../_components/page-box';
|
import {
|
||||||
|
HeaderRight,
|
||||||
|
usePageContentStyle
|
||||||
|
} from '../../_components/page-box';
|
||||||
import { queryModelsList } from '../apis';
|
import { queryModelsList } from '../apis';
|
||||||
import ViewCodeButtons from '../components/view-code-buttons';
|
import ViewCodeButtons from '../components/view-code-buttons';
|
||||||
import useCollapseLayout from '../hooks/use-collapse-layout';
|
import useCollapseLayout from '../hooks/use-collapse-layout';
|
||||||
@@ -14,7 +15,6 @@ import '../style/play-ground.less';
|
|||||||
import GroundReranker from './page';
|
import GroundReranker from './page';
|
||||||
|
|
||||||
const PlaygroundRerank: React.FC = () => {
|
const PlaygroundRerank: React.FC = () => {
|
||||||
const intl = useIntl();
|
|
||||||
const groundRerankerRef = useRef<any>(null);
|
const groundRerankerRef = useRef<any>(null);
|
||||||
const [rerankerModelList, setRerankerModelList] = useState<
|
const [rerankerModelList, setRerankerModelList] = useState<
|
||||||
Global.BaseOption<string>[]
|
Global.BaseOption<string>[]
|
||||||
@@ -80,23 +80,18 @@ const PlaygroundRerank: React.FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
usePageContentStyle({ padding: 0 });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
className={classNames('playground-container chat')}
|
<HeaderRight>
|
||||||
styles={{
|
|
||||||
containerWrapper: {
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
rightContent={
|
|
||||||
<ViewCodeButtons
|
<ViewCodeButtons
|
||||||
activeKey=""
|
activeKey=""
|
||||||
handleViewCode={handleViewCode}
|
handleViewCode={handleViewCode}
|
||||||
handleToggleCollapse={handleToggleCollapse}
|
handleToggleCollapse={handleToggleCollapse}
|
||||||
key="view-code-buttons"
|
key="view-code-buttons"
|
||||||
></ViewCodeButtons>
|
></ViewCodeButtons>
|
||||||
}
|
</HeaderRight>
|
||||||
>
|
|
||||||
<div className="play-ground">
|
<div className="play-ground">
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
<GroundReranker
|
<GroundReranker
|
||||||
@@ -106,7 +101,7 @@ const PlaygroundRerank: React.FC = () => {
|
|||||||
></GroundReranker>
|
></GroundReranker>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ import { IconFont } from '@gpustack/core-ui';
|
|||||||
import { useIntl, useSearchParams } from '@umijs/max';
|
import { useIntl, useSearchParams } from '@umijs/max';
|
||||||
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
||||||
import { Segmented, Tabs, TabsProps } from 'antd';
|
import { Segmented, Tabs, TabsProps } from 'antd';
|
||||||
import classNames from 'classnames';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { PageContainerInner } from '../../_components/page-box';
|
import {
|
||||||
|
HeaderLeft,
|
||||||
|
HeaderRight,
|
||||||
|
usePageContentStyle
|
||||||
|
} from '../../_components/page-box';
|
||||||
import { queryModelsList } from '../apis';
|
import { queryModelsList } from '../apis';
|
||||||
import ViewCodeButtons from '../components/view-code-buttons';
|
import ViewCodeButtons from '../components/view-code-buttons';
|
||||||
import '../style/play-ground.less';
|
import '../style/play-ground.less';
|
||||||
@@ -194,48 +197,42 @@ const Playground: React.FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
usePageContentStyle({ padding: 0 });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
leftContent={
|
<HeaderLeft>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="font-600 flex-center">
|
<span className="font-600 flex-center">
|
||||||
{intl.formatMessage({ id: 'menu.playground.speech' })}
|
{intl.formatMessage({ id: 'menu.playground.speech' })}
|
||||||
</span>
|
</span>
|
||||||
{
|
<Segmented
|
||||||
<Segmented
|
shape="round"
|
||||||
shape="round"
|
style={{
|
||||||
style={{
|
backgroundColor: 'var(--ant-color-fill-secondary)'
|
||||||
backgroundColor: 'var(--ant-color-fill-secondary)'
|
}}
|
||||||
}}
|
size="middle"
|
||||||
size="middle"
|
className="m-l-24 font-400"
|
||||||
className="m-l-24 font-400"
|
options={optionsList}
|
||||||
options={optionsList}
|
value={activeKey}
|
||||||
value={activeKey}
|
onChange={(key) => setActiveKey(key)}
|
||||||
onChange={(key) => setActiveKey(key)}
|
></Segmented>
|
||||||
></Segmented>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</HeaderLeft>
|
||||||
rightContent={
|
<HeaderRight>
|
||||||
<ViewCodeButtons
|
<ViewCodeButtons
|
||||||
activeKey=""
|
activeKey=""
|
||||||
handleViewCode={handleViewCode}
|
handleViewCode={handleViewCode}
|
||||||
handleToggleCollapse={handleToggleCollapse}
|
handleToggleCollapse={handleToggleCollapse}
|
||||||
key="view-code-buttons"
|
key="view-code-buttons"
|
||||||
></ViewCodeButtons>
|
></ViewCodeButtons>
|
||||||
}
|
</HeaderRight>
|
||||||
styles={{ containerWrapper: { padding: 0 } }}
|
|
||||||
className={classNames('playground-container', {
|
|
||||||
compare: activeKey === 'compare',
|
|
||||||
chat: activeKey !== 'compare'
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<div className="play-ground">
|
<div className="play-ground">
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
<Tabs items={items} activeKey={activeKey}></Tabs>
|
<Tabs items={items} activeKey={activeKey}></Tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import HotKeys from '@/config/hotkeys';
|
import HotKeys from '@/config/hotkeys';
|
||||||
import { ExtraContent } from '@/layouts/extraRender';
|
|
||||||
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
||||||
import { Divider } from 'antd';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { PageContainerInner } from '../../_components/page-box';
|
import {
|
||||||
|
HeaderRight,
|
||||||
|
usePageContentStyle
|
||||||
|
} from '../../_components/page-box';
|
||||||
import { queryModelsList } from '../apis';
|
import { queryModelsList } from '../apis';
|
||||||
import ViewCodeButtons from '../components/view-code-buttons';
|
import ViewCodeButtons from '../components/view-code-buttons';
|
||||||
import useCollapseLayout from '../hooks/use-collapse-layout';
|
import useCollapseLayout from '../hooks/use-collapse-layout';
|
||||||
@@ -16,7 +15,6 @@ import '../style/play-ground.less';
|
|||||||
import GroundVideo from './page';
|
import GroundVideo from './page';
|
||||||
|
|
||||||
const PlaygroundRerank: React.FC = () => {
|
const PlaygroundRerank: React.FC = () => {
|
||||||
const intl = useIntl();
|
|
||||||
const groundVideoRef = useRef<any>(null);
|
const groundVideoRef = useRef<any>(null);
|
||||||
const [modelList, setModelList] = useState<Global.BaseOption<string>[]>([]);
|
const [modelList, setModelList] = useState<Global.BaseOption<string>[]>([]);
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
@@ -78,24 +76,18 @@ const PlaygroundRerank: React.FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
usePageContentStyle({ padding: 0 });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainerInner
|
<>
|
||||||
className={classNames('playground-container chat')}
|
<HeaderRight>
|
||||||
extra={[
|
|
||||||
<ViewCodeButtons
|
<ViewCodeButtons
|
||||||
activeKey=""
|
activeKey=""
|
||||||
handleViewCode={handleViewCode}
|
handleViewCode={handleViewCode}
|
||||||
handleToggleCollapse={handleToggleCollapse}
|
handleToggleCollapse={handleToggleCollapse}
|
||||||
key="view-code-buttons"
|
key="view-code-buttons"
|
||||||
></ViewCodeButtons>,
|
></ViewCodeButtons>
|
||||||
<Divider
|
</HeaderRight>
|
||||||
key="divider"
|
|
||||||
orientation="vertical"
|
|
||||||
style={{ height: 16, marginInline: 16 }}
|
|
||||||
/>,
|
|
||||||
<ExtraContent key="extra-content" />
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<div className="play-ground">
|
<div className="play-ground">
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
<GroundVideo
|
<GroundVideo
|
||||||
@@ -105,7 +97,7 @@ const PlaygroundRerank: React.FC = () => {
|
|||||||
></GroundVideo>
|
></GroundVideo>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainerInner>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user