style: column wrapper srollable style

This commit is contained in:
jialin
2025-12-13 19:47:48 +08:00
parent b327eedb45
commit 7a0ee6aac4
15 changed files with 81 additions and 133 deletions
+32 -40
View File
@@ -1,8 +1,28 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import './style.less'; import styled from 'styled-components';
import { WrapperContext } from './use-wrapper-context'; import { WrapperContext } from './use-wrapper-context';
const Wrapper = styled.div`
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
width: 100%;
`;
const ContentWrapper = styled.div`
flex: 1;
position: relative;
overflow-y: auto;
`;
const Footer = styled.div`
padding-block: 0;
background-color: var(--ant-color-bg-elevated);
`;
interface ColumnWrapperProps { interface ColumnWrapperProps {
children: React.ReactNode; children: React.ReactNode;
footer?: React.ReactNode; footer?: React.ReactNode;
@@ -44,29 +64,8 @@ const ColumnWrapper: React.FC<ColumnWrapperProps> = ({
} }
}, []); }, []);
React.useLayoutEffect(() => {
if (!scroller.current || !footerRef.current || !contentRef.current) return;
const updatePadding = () => {
const height = footerRef.current!.getBoundingClientRect().height;
contentRef.current!.style.paddingBottom = `${height - 22}px`;
};
updatePadding();
const observer = new ResizeObserver(updatePadding);
observer.observe(footerRef.current);
return () => observer.disconnect();
}, []);
const setContentPaddingBottom = useCallback((padding: number) => { const setContentPaddingBottom = useCallback((padding: number) => {
if (footerRef.current) { contentRef.current!.style.paddingBottom = `${padding}px`;
const height = footerRef.current.getBoundingClientRect().height;
contentRef.current!.style.paddingBottom = `${height + padding - 22}px`;
} else {
contentRef.current!.style.paddingBottom = `${padding}px`;
}
}, []); }, []);
return ( return (
@@ -81,25 +80,18 @@ const ColumnWrapper: React.FC<ColumnWrapperProps> = ({
setSScrollContentPaddingBottom: setContentPaddingBottom setSScrollContentPaddingBottom: setContentPaddingBottom
}} }}
> >
<div <Wrapper style={{ height: maxHeight || '100%', ...styles.wrapper }}>
className="column-wrapper-footer" <ContentWrapper
style={{ height: maxHeight || '100%', ...styles.wrapper }}
>
<div
className="column-wrapper"
ref={scroller} ref={scroller}
style={{ padding: '16px 24px', ...styles.container }} style={{
padding: '16px 24px',
...styles.container
}}
> >
<div ref={contentRef} className="child-content"> <div ref={contentRef}>{children}</div>
{children} </ContentWrapper>
</div> {footer && <Footer ref={footerRef}>{footer}</Footer>}
</div> </Wrapper>
{footer && (
<div className="footer" ref={footerRef}>
{footer}
</div>
)}
</div>
</WrapperContext.Provider> </WrapperContext.Provider>
); );
}; };
@@ -1,32 +0,0 @@
.column-wrapper {
flex: 1;
position: relative;
height: 100%;
overflow-y: auto;
}
.simplebar-scrollbar::before {
width: var(--scrollbar-size);
background: var(--scrollbar-handle-bg);
}
.column-wrapper-footer {
flex: 1;
display: flex;
position: relative;
width: 100%;
.column-wrapper {
border-left: none;
}
.footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
padding-block: 0;
background-color: var(--ant-color-bg-elevated);
}
}
@@ -16,6 +16,12 @@ import { expirationOptions } from '../../config';
import { FormData, ListItem } from '../../config/types'; import { FormData, ListItem } from '../../config/types';
import APIKeyForm from './form'; import APIKeyForm from './form';
const ModalFooterStyle = {
padding: '16px 24px 8px',
display: 'flex',
justifyContent: 'flex-end'
};
type AddModalProps = { type AddModalProps = {
title: string; title: string;
action: PageActionType; action: PageActionType;
@@ -209,16 +215,15 @@ const AddModal: React.FC<AddModalProps> = ({
> >
<ColumnWrapper <ColumnWrapper
styles={{ styles={{
container: { paddingTop: 0 } container: { paddingBlock: 0 }
}} }}
footer={ footer={
!showKey ? ( !showKey ? (
<> <>
{isChanged && ( {isChanged && (
<div style={{ marginInline: 24 }}> <div style={{ marginInline: 24, paddingTop: 8 }}>
<AlertBlockInfo <AlertBlockInfo
type="warning" type="warning"
style={{ marginBottom: 16 }}
contentStyle={{ paddingInline: 0 }} contentStyle={{ paddingInline: 0 }}
message={intl.formatMessage({ message={intl.formatMessage({
id: 'models.button.accessSettings.tips' id: 'models.button.accessSettings.tips'
@@ -230,11 +235,7 @@ const AddModal: React.FC<AddModalProps> = ({
onOk={handleSumit} onOk={handleSumit}
onCancel={onCancel} onCancel={onCancel}
loading={loading} loading={loading}
style={{ style={ModalFooterStyle}
padding: '16px 24px',
display: 'flex',
justifyContent: 'flex-end'
}}
></ModalFooter> ></ModalFooter>
</> </>
) : ( ) : (
@@ -245,11 +246,7 @@ const AddModal: React.FC<AddModalProps> = ({
loading={loading} loading={loading}
okText={intl.formatMessage({ id: 'common.button.done' })} okText={intl.formatMessage({ id: 'common.button.done' })}
showCancelBtn={false} showCancelBtn={false}
style={{ style={ModalFooterStyle}
padding: '16px 24px',
display: 'flex',
justifyContent: 'flex-end'
}}
></ModalFooter> ></ModalFooter>
</> </>
) )
+2 -2
View File
@@ -20,7 +20,7 @@ import BackendForm from '../forms';
import ImportYAML from './import-yaml'; import ImportYAML from './import-yaml';
const ModalFooterStyle = { const ModalFooterStyle = {
padding: '16px 24px', padding: '16px 24px 8px',
display: 'flex', display: 'flex',
justifyContent: 'flex-end' justifyContent: 'flex-end'
}; };
@@ -220,7 +220,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
maxHeight={'calc(100vh - 140px)'} maxHeight={'calc(100vh - 140px)'}
styles={{ styles={{
container: { container: {
paddingTop: 0 paddingBlock: 0
} }
}} }}
footer={ footer={
@@ -26,7 +26,7 @@ interface CompatibilityAlertProps {
const DivWrapper = styled.div` const DivWrapper = styled.div`
position: relative; position: relative;
padding-inline: 24px; padding-inline: 24px;
padding-block: 10px 0; padding-block: 8px 0;
&:hover { &:hover {
.close-wrapper { .close-wrapper {
display: block; display: block;
@@ -357,7 +357,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
<ColumnWrapper <ColumnWrapper
styles={{ styles={{
container: { container: {
paddingTop: 0 paddingBlock: 0
} }
}} }}
footer={ footer={
@@ -387,7 +387,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
) )
} }
style={{ style={{
padding: '16px 24px', padding: '16px 24px 8px',
display: 'flex', display: 'flex',
justifyContent: 'flex-end' justifyContent: 'flex-end'
}} }}
@@ -41,7 +41,7 @@ const dropFieldsFromForm = [
const resetFields = ['worker_selector', 'env']; const resetFields = ['worker_selector', 'env'];
const ModalFooterStyle = { const ModalFooterStyle = {
padding: '16px 24px', padding: '16px 24px 8px',
display: 'flex', display: 'flex',
justifyContent: 'flex-end' justifyContent: 'flex-end'
}; };
@@ -586,7 +586,7 @@ const AddModal: FC<AddModalProps> = (props) => {
<FormWrapper> <FormWrapper>
<ColumnWrapper <ColumnWrapper
styles={{ styles={{
container: { paddingTop: 0 } container: { paddingBlock: 0 }
}} }}
footer={ footer={
<> <>
@@ -35,7 +35,7 @@ type AddModalProps = {
}; };
const ModalFooterStyle = { const ModalFooterStyle = {
padding: '16px 24px', padding: '16px 24px 8px',
display: 'flex', display: 'flex',
justifyContent: 'flex-end' justifyContent: 'flex-end'
}; };
@@ -249,7 +249,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
<ColumnWrapper <ColumnWrapper
styles={{ styles={{
container: { container: {
paddingTop: 0 paddingBlock: 0
} }
}} }}
footer={ footer={
@@ -490,6 +490,7 @@ const options: BackendParameter[] = [
'quark', 'quark',
'moe_wna16', 'moe_wna16',
'torchao', 'torchao',
'ascend',
'None' 'None'
] ]
}, },
+1 -1
View File
@@ -375,7 +375,7 @@ export const defaultFormValues = {
gpu_selector: {}, gpu_selector: {},
worker_selector: {}, worker_selector: {},
backend_parameters: [], backend_parameters: [],
backend_version: '' backend_version: null
}; };
export const getBackendParamsTips = (backend: string) => { export const getBackendParamsTips = (backend: string) => {
+2 -2
View File
@@ -207,7 +207,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
<FormWrapper> <FormWrapper>
<ColumnWrapper <ColumnWrapper
styles={{ styles={{
container: { paddingTop: 0 } container: { paddingBlock: 0 }
}} }}
footer={ footer={
<> <>
@@ -218,7 +218,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
loading: loading loading: loading
}} }}
style={{ style={{
padding: '16px 24px', padding: '16px 24px 8px',
display: 'flex', display: 'flex',
justifyContent: 'flex-end' justifyContent: 'flex-end'
}} }}
+20 -1
View File
@@ -118,6 +118,11 @@ const BackendFields: React.FC = () => {
return option.title; return option.title;
}; };
const backendVersionLabelRender = (option: any) => {
console.log('backendVersionLabelRender option:', option);
return option.title;
};
const renderVersionOptions = (values: any[], label: string) => { const renderVersionOptions = (values: any[], label: string) => {
if (!values || values.length === 0) { if (!values || values.length === 0) {
return null; return null;
@@ -188,7 +193,8 @@ const BackendFields: React.FC = () => {
<SealSelect <SealSelect
allowClear allowClear
showSearch showSearch
labelRender={labelRender} allowNull
labelRender={backendVersionLabelRender}
placeholder={intl.formatMessage({ placeholder={intl.formatMessage({
id: 'models.form.backendVersion.holder' id: 'models.form.backendVersion.holder'
})} })}
@@ -216,6 +222,19 @@ const BackendFields: React.FC = () => {
</dl> </dl>
} }
> >
{(backendVersions.builtIn.length > 0 ||
backendVersions.custom.length > 0) && (
<Select.Option
key="auto"
value={null}
title={intl.formatMessage({ id: 'common.options.auto' })}
label={intl.formatMessage({
id: 'common.options.auto'
})}
>
{intl.formatMessage({ id: 'common.options.auto' })}
</Select.Option>
)}
{renderVersionOptions( {renderVersionOptions(
backendVersions.builtIn, backendVersions.builtIn,
intl.formatMessage({ id: 'backend.builtin' }) intl.formatMessage({ id: 'backend.builtin' })
+4 -6
View File
@@ -95,8 +95,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
onClusterChange, onClusterChange,
onOk onOk
} = props; } = props;
const { getScrollElementScrollableHeight, osInstance, scrollEventElement } = const { getScrollElementScrollableHeight } = useWrapperContext();
useWrapperContext();
const { backendOptions, getBackendOptions } = useQueryBackends(); const { backendOptions, getBackendOptions } = useQueryBackends();
const { getGPUOptionList, gpuOptions, workerLabelOptions } = const { getGPUOptionList, gpuOptions, workerLabelOptions } =
useGenerateGPUOptions(); useGenerateGPUOptions();
@@ -105,8 +104,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
const [activeKey, setActiveKey] = React.useState<string[]>([]); const [activeKey, setActiveKey] = React.useState<string[]>([]);
const [target, setTarget] = React.useState<string>(TABKeysMap.BASIC); const [target, setTarget] = React.useState<string>(TABKeysMap.BASIC);
console.log('scroller instance in form:', osInstance, scrollEventElement);
const segmentOptions = [ const segmentOptions = [
{ {
value: TABKeysMap.BASIC, value: TABKeysMap.BASIC,
@@ -226,7 +223,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
}); });
form.setFieldsValue({ form.setFieldsValue({
env: null, env: null,
backend_version: '', // don't set default version here, let the user select it backend_version: null, // don't set default version here, let the user select it
backend_parameters: option.default_backend_param || [], backend_parameters: option.default_backend_param || [],
...updateKVCacheConfig(val, option), ...updateKVCacheConfig(val, option),
...updateGPUSelector(val) ...updateGPUSelector(val)
@@ -454,7 +451,8 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
ngram_max_match_length: ngram_max_match_length:
initialValues?.speculative_config?.ngram_max_match_length || 10 initialValues?.speculative_config?.ngram_max_match_length || 10
}, },
...initialValues ...initialValues,
backend_version: initialValues?.backend_version || null
}} }}
> >
<BasicForm <BasicForm
+1 -29
View File
@@ -4,7 +4,6 @@ import SealCascader from '@/components/seal-form/seal-cascader';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import TooltipList from '@/components/tooltip-list'; import TooltipList from '@/components/tooltip-list';
import useAppUtils from '@/hooks/use-app-utils'; import useAppUtils from '@/hooks/use-app-utils';
import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrapper-context';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Form, InputNumber } from 'antd'; import { Form, InputNumber } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
@@ -72,8 +71,6 @@ const ScheduleTypeForm: React.FC = () => {
clearCacheFormValues, clearCacheFormValues,
initialValues initialValues
} = useFormContext(); } = useFormContext();
const { setSScrollContentPaddingBottom, getScrollElementScrollableHeight } =
useWrapperContext();
const { getRuleMessage } = useAppUtils(); const { getRuleMessage } = useAppUtils();
const form = Form.useFormInstance(); const form = Form.useFormInstance();
const scheduleType = Form.useWatch('scheduleType', form); const scheduleType = Form.useWatch('scheduleType', form);
@@ -82,29 +79,6 @@ const ScheduleTypeForm: React.FC = () => {
['gpu_selector', 'gpus_per_replica'], ['gpu_selector', 'gpus_per_replica'],
form form
); );
const gpuSekectorElRef = React.useRef<HTMLElement | null>(null);
const setContentPaddingBottom = () => {
if (!gpuSekectorElRef.current) {
gpuSekectorElRef.current = document.querySelector(
'[data-field="gpu_selector.gpu_ids"]'
);
}
if (gpuSekectorElRef.current) {
const { scrollHeight, scrollTop } =
getScrollElementScrollableHeight?.() || {
scrollHeight: 0,
scrollTop: 0
};
const rect = gpuSekectorElRef.current.getBoundingClientRect();
const bottomSpace =
window.innerHeight - rect.bottom + (scrollHeight - scrollTop);
if (bottomSpace < 340) {
setSScrollContentPaddingBottom?.(340 - bottomSpace);
}
}
};
const handleScheduleTypeChange = async (value: string) => { const handleScheduleTypeChange = async (value: string) => {
await new Promise((resolve) => { await new Promise((resolve) => {
@@ -118,11 +92,9 @@ const ScheduleTypeForm: React.FC = () => {
gpu_ids: [], gpu_ids: [],
gpus_per_replica: null gpus_per_replica: null
}); });
requestAnimationFrame(() => {
setContentPaddingBottom();
});
} }
}; };
const handleGpusPerReplicasChange = (val: string | number | null) => { const handleGpusPerReplicasChange = (val: string | number | null) => {
if (val === null) { if (val === null) {
form.setFieldValue(['gpu_selector', 'gpus_per_replica'], null); form.setFieldValue(['gpu_selector', 'gpus_per_replica'], null);
@@ -43,6 +43,7 @@ export default function useChatCompletion(
}; };
const joinMessage = (chunk: any) => { const joinMessage = (chunk: any) => {
console.log('chunk:', chunk);
setTokenResult({ setTokenResult({
...(chunk?.usage ?? {}) ...(chunk?.usage ?? {})
}); });