refactor: advance collapse
This commit is contained in:
+6
-4
@@ -58,12 +58,14 @@ export default defineConfig({
|
|||||||
.filename(`js/[name].${t}.js`)
|
.filename(`js/[name].${t}.js`)
|
||||||
.chunkFilename(`js/[name].${t}.chunk.js`);
|
.chunkFilename(`js/[name].${t}.chunk.js`);
|
||||||
compressionPluginConfig(config);
|
compressionPluginConfig(config);
|
||||||
|
monacoPluginConfig(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: {}),
|
: {
|
||||||
chainWebpack(config) {
|
chainWebpack(config) {
|
||||||
monacoPluginConfig(config);
|
monacoPluginConfig(config);
|
||||||
},
|
}
|
||||||
|
}),
|
||||||
favicons: ['/static/favicon.png'],
|
favicons: ['/static/favicon.png'],
|
||||||
jsMinifier: 'terser',
|
jsMinifier: 'terser',
|
||||||
cssMinifier: 'cssnano',
|
cssMinifier: 'cssnano',
|
||||||
|
|||||||
@@ -2,11 +2,23 @@ import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
|
|
||||||
const ColumnWrapper: React.FC<any> = ({
|
interface ColumnWrapperProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
footer?: React.ReactNode;
|
||||||
|
maxHeight?: string | number;
|
||||||
|
paddingBottom?: number;
|
||||||
|
styles?: {
|
||||||
|
wrapper?: React.CSSProperties;
|
||||||
|
container?: React.CSSProperties;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColumnWrapper: React.FC<ColumnWrapperProps> = ({
|
||||||
children,
|
children,
|
||||||
footer,
|
footer,
|
||||||
maxHeight,
|
maxHeight,
|
||||||
paddingBottom = 50
|
paddingBottom = 50,
|
||||||
|
styles = {}
|
||||||
}) => {
|
}) => {
|
||||||
const scroller = React.useRef<any>(null);
|
const scroller = React.useRef<any>(null);
|
||||||
const { initialize } = useOverlayScroller({
|
const { initialize } = useOverlayScroller({
|
||||||
@@ -27,12 +39,12 @@ const ColumnWrapper: React.FC<any> = ({
|
|||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className="column-wrapper-footer"
|
className="column-wrapper-footer"
|
||||||
style={{ height: maxHeight || '100%' }}
|
style={{ height: maxHeight || '100%', ...styles.wrapper }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="column-wrapper"
|
className="column-wrapper"
|
||||||
ref={scroller}
|
ref={scroller}
|
||||||
style={{ padding: '16px 24px' }}
|
style={{ padding: '16px 24px', ...styles.container }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { PageActionType } from '@/config/types';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Segmented, Tabs } from 'antd';
|
import { Segmented, Tabs } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useId, useRef, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import ColumnWrapper from '../../_components/column-wrapper';
|
import ColumnWrapper from '../../_components/column-wrapper';
|
||||||
import { backendFields, json2Yaml } from '../config';
|
import { backendFields, json2Yaml } from '../config';
|
||||||
@@ -46,6 +46,7 @@ interface AddModalProps {
|
|||||||
const AddModal: React.FC<AddModalProps> = (props) => {
|
const AddModal: React.FC<AddModalProps> = (props) => {
|
||||||
const { action, currentData, onClose, onSubmit, onSubmitYaml, open, title } =
|
const { action, currentData, onClose, onSubmit, onSubmitYaml, open, title } =
|
||||||
props;
|
props;
|
||||||
|
const uid = useId();
|
||||||
const formRef = useRef<any>(null);
|
const formRef = useRef<any>(null);
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -121,7 +122,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
setYamlContent(yaml);
|
setYamlContent(yaml);
|
||||||
setFormContent(formData);
|
setFormContent(formData);
|
||||||
formRef.current?.setFieldsValue?.(formData);
|
formRef.current?.setFieldsValue?.(formData);
|
||||||
editorRef.current?.setValue?.(yaml);
|
editorRef.current?.setContent?.(yaml);
|
||||||
}
|
}
|
||||||
}, [action, currentData]);
|
}, [action, currentData]);
|
||||||
|
|
||||||
@@ -129,6 +130,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
<GSDrawer
|
<GSDrawer
|
||||||
title={title}
|
title={title}
|
||||||
open={open}
|
open={open}
|
||||||
|
key={uid}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
destroyOnHidden={true}
|
destroyOnHidden={true}
|
||||||
closeIcon={false}
|
closeIcon={false}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import LabelSelector from '@/components/label-selector';
|
import LabelSelector from '@/components/label-selector';
|
||||||
import ListInput from '@/components/list-input';
|
|
||||||
import CheckboxField from '@/components/seal-form/checkbox-field';
|
import CheckboxField from '@/components/seal-form/checkbox-field';
|
||||||
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 { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Collapse, Form, FormInstance, Typography } from 'antd';
|
import { Collapse, Form, FormInstance } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
backendParamsHolderTips,
|
|
||||||
getBackendParamsTips,
|
getBackendParamsTips,
|
||||||
modelCategories,
|
modelCategories,
|
||||||
placementStrategyOptions,
|
placementStrategyOptions,
|
||||||
@@ -21,9 +19,10 @@ import BackendParameters, {
|
|||||||
} from '../config/backend-parameters';
|
} from '../config/backend-parameters';
|
||||||
import { useFormContext } from '../config/form-context';
|
import { useFormContext } from '../config/form-context';
|
||||||
import { FormData } from '../config/types';
|
import { FormData } from '../config/types';
|
||||||
import BackendFields from '../forms/backend-fields';
|
import Backend from '../forms/backend';
|
||||||
|
import BackendParametersList from '../forms/backend-parameters-list';
|
||||||
|
import Performance from '../forms/performance';
|
||||||
import dataformStyles from '../style/data-form.less';
|
import dataformStyles from '../style/data-form.less';
|
||||||
import Performance from './performance';
|
|
||||||
|
|
||||||
interface AdvanceConfigProps {
|
interface AdvanceConfigProps {
|
||||||
isGGUF: boolean;
|
isGGUF: boolean;
|
||||||
@@ -44,9 +43,9 @@ const placementStrategyTips = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
const AdvanceConfig = () => {
|
||||||
const { form, isGGUF, gpuOptions, source, action } = props;
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const form = Form.useFormInstance();
|
||||||
const wokerSelector = Form.useWatch('worker_selector', form);
|
const wokerSelector = Form.useWatch('worker_selector', form);
|
||||||
const EnviromentVars = Form.useWatch('env', form);
|
const EnviromentVars = Form.useWatch('env', form);
|
||||||
const scheduleType = Form.useWatch('scheduleType', form);
|
const scheduleType = Form.useWatch('scheduleType', form);
|
||||||
@@ -57,7 +56,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
|||||||
const placement_strategy = Form.useWatch('placement_strategy', form);
|
const placement_strategy = Form.useWatch('placement_strategy', form);
|
||||||
const gpuSelectorIds = Form.useWatch(['gpu_selector', 'gpu_ids'], form);
|
const gpuSelectorIds = Form.useWatch(['gpu_selector', 'gpu_ids'], form);
|
||||||
const worker_selector = Form.useWatch('worker_selector', form);
|
const worker_selector = Form.useWatch('worker_selector', form);
|
||||||
const { onValuesChange } = useFormContext();
|
const { onValuesChange, gpuOptions, source, isGGUF } = useFormContext();
|
||||||
|
|
||||||
const paramsConfig = useMemo(() => {
|
const paramsConfig = useMemo(() => {
|
||||||
return _.get(BackendParameters, backend, []);
|
return _.get(BackendParameters, backend, []);
|
||||||
@@ -131,7 +130,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
|||||||
options={modelCategories}
|
options={modelCategories}
|
||||||
></SealSelect>
|
></SealSelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<BackendFields></BackendFields>
|
<Backend></Backend>
|
||||||
{scheduleType === ScheduleValueMap.Auto && (
|
{scheduleType === ScheduleValueMap.Auto && (
|
||||||
<>
|
<>
|
||||||
<Form.Item<FormData> name="placement_strategy">
|
<Form.Item<FormData> name="placement_strategy">
|
||||||
@@ -194,57 +193,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Form.Item<FormData> name="backend_parameters">
|
<BackendParametersList></BackendParametersList>
|
||||||
<ListInput
|
|
||||||
placeholder={
|
|
||||||
backendParamsHolderTips[backend]
|
|
||||||
? intl.formatMessage({
|
|
||||||
id: backendParamsHolderTips[backend].holder
|
|
||||||
})
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
btnText={intl.formatMessage({ id: 'common.button.addParams' })}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
id: 'models.form.backend_parameters'
|
|
||||||
})}
|
|
||||||
dataList={form.getFieldValue('backend_parameters') || []}
|
|
||||||
onChange={handleBackendParametersChange}
|
|
||||||
onBlur={handleBackendParametersOnBlur}
|
|
||||||
onDelete={handleDeleteBackendParameters}
|
|
||||||
options={paramsConfig}
|
|
||||||
description={
|
|
||||||
backendParamsTips.link && (
|
|
||||||
<span>
|
|
||||||
{backend === backendOptionsMap.ascendMindie && (
|
|
||||||
<span>
|
|
||||||
{intl.formatMessage({ id: 'models.backend.mindie.310p' })}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<span style={{ marginLeft: 5 }}>
|
|
||||||
{intl.formatMessage(
|
|
||||||
{ id: 'models.form.backend_parameters.vllm.tips' },
|
|
||||||
{ backend: backendParamsTips.backend || '' }
|
|
||||||
)}{' '}
|
|
||||||
<Typography.Link
|
|
||||||
style={{ display: 'inline' }}
|
|
||||||
className="flex-center"
|
|
||||||
href={backendParamsTips.link}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
{intl.formatMessage({ id: 'common.text.here' })}
|
|
||||||
</span>
|
|
||||||
<IconFont
|
|
||||||
type="icon-external-link"
|
|
||||||
className="font-size-14 m-l-4"
|
|
||||||
></IconFont>
|
|
||||||
</Typography.Link>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
></ListInput>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item<FormData> name="env">
|
<Form.Item<FormData> name="env">
|
||||||
<LabelSelector
|
<LabelSelector
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
@@ -313,19 +262,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
|||||||
forceRender: true,
|
forceRender: true,
|
||||||
children: <Performance></Performance>
|
children: <Performance></Performance>
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// key: '3',
|
|
||||||
// label: (
|
|
||||||
// <span
|
|
||||||
// style={{ fontWeight: 'var(--font-weight-medium)' }}
|
|
||||||
// className="font-size-14"
|
|
||||||
// >
|
|
||||||
// Scaling
|
|
||||||
// </span>
|
|
||||||
// ),
|
|
||||||
// forceRender: true,
|
|
||||||
// children: <Scaling></Scaling>
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
key: '1',
|
key: '1',
|
||||||
label: (
|
label: (
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import SealInput from '@/components/seal-form/seal-input';
|
|||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
|
import CollapsePanel from '@/pages/_components/collapse-panel';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -17,10 +18,12 @@ import {
|
|||||||
} from '../config/types';
|
} from '../config/types';
|
||||||
import { generateGPUIds } from '../config/utils';
|
import { generateGPUIds } from '../config/utils';
|
||||||
import CatalogFrom from '../forms/catalog';
|
import CatalogFrom from '../forms/catalog';
|
||||||
import HuggingFaceForm from '../forms/hugging-face';
|
import LocalPathSource from '../forms/local-path-source';
|
||||||
import LocalPathForm from '../forms/local-path';
|
import OnlineSource from '../forms/online-source';
|
||||||
import { useGenerateGPUOptions } from '../hooks/use-form-initial-values';
|
import { useGenerateGPUOptions } from '../hooks/use-form-initial-values';
|
||||||
import AdvanceConfig from './advance-config';
|
// import AdvanceConfig from './advance-config';
|
||||||
|
import AdvanceConfig from '../forms/advance-config';
|
||||||
|
import Performance from '../forms/performance';
|
||||||
|
|
||||||
interface DataFormProps {
|
interface DataFormProps {
|
||||||
initialValues?: any;
|
initialValues?: any;
|
||||||
@@ -59,6 +62,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
const { getRuleMessage } = useAppUtils();
|
const { getRuleMessage } = useAppUtils();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const [activeKey, setActiveKey] = React.useState<string[]>([]);
|
||||||
|
|
||||||
const handleSumit = () => {
|
const handleSumit = () => {
|
||||||
form.submit();
|
form.submit();
|
||||||
@@ -118,6 +122,10 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
onValuesChange?.(changedValues, allValues);
|
onValuesChange?.(changedValues, allValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOnCollapseChange = (keys: string | string[]) => {
|
||||||
|
setActiveKey(Array.isArray(keys) ? keys : [keys]);
|
||||||
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => {
|
useImperativeHandle(ref, () => {
|
||||||
return {
|
return {
|
||||||
form: form,
|
form: form,
|
||||||
@@ -216,8 +224,8 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<HuggingFaceForm></HuggingFaceForm>
|
<OnlineSource></OnlineSource>
|
||||||
<LocalPathForm></LocalPathForm>
|
<LocalPathSource></LocalPathSource>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="cluster_id"
|
name="cluster_id"
|
||||||
rules={[
|
rules={[
|
||||||
@@ -245,13 +253,25 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
})}
|
})}
|
||||||
></SealInput.TextArea>
|
></SealInput.TextArea>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<AdvanceConfig
|
<CollapsePanel
|
||||||
form={form}
|
activeKey={activeKey}
|
||||||
gpuOptions={gpuOptions}
|
accordion={false}
|
||||||
isGGUF={isGGUF}
|
onChange={handleOnCollapseChange}
|
||||||
action={action}
|
items={[
|
||||||
source={props.source}
|
{
|
||||||
></AdvanceConfig>
|
key: 'performance',
|
||||||
|
label: 'Performance',
|
||||||
|
forceRender: true,
|
||||||
|
children: <Performance></Performance>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'advance_config',
|
||||||
|
label: 'Advanced',
|
||||||
|
forceRender: true,
|
||||||
|
children: <AdvanceConfig></AdvanceConfig>
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
></CollapsePanel>
|
||||||
</Form>
|
</Form>
|
||||||
</FormContext.Provider>
|
</FormContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { Col, Row } from 'antd';
|
|
||||||
import React from 'react';
|
|
||||||
import '../style/deploy-dropdown.less';
|
|
||||||
|
|
||||||
interface DeployDropdownProps {
|
|
||||||
items: { label: string; value: string; key: string; icon: React.ReactNode }[];
|
|
||||||
onSelect: (item: {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
key: string;
|
|
||||||
icon: React.ReactNode;
|
|
||||||
}) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DeployDropdown: React.FC<DeployDropdownProps> = ({ items, onSelect }) => {
|
|
||||||
return (
|
|
||||||
<div className="deploy-dropdown">
|
|
||||||
<Row gutter={[0, 16]}>
|
|
||||||
{items.map((item) => (
|
|
||||||
<Col span={8} key={item.key}>
|
|
||||||
<div key={item.key} onClick={() => onSelect(item)} className="item">
|
|
||||||
<span className="icon">{item.icon}</span>
|
|
||||||
<span className="label">{item.label}</span>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
))}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DeployDropdown;
|
|
||||||
@@ -36,10 +36,15 @@ const ModalFooterStyle = {
|
|||||||
justifyContent: 'flex-end'
|
justifyContent: 'flex-end'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Container = styled.div`
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
const ColWrapper = styled.div`
|
const ColWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
maxwidth: 33.33%;
|
max-width: 33.33%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FormWrapper = styled.div`
|
const FormWrapper = styled.div`
|
||||||
@@ -445,31 +450,27 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
width={width}
|
width={width}
|
||||||
footer={false}
|
footer={false}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', height: '100%' }}>
|
<Container>
|
||||||
{SEARCH_SOURCE.includes(props.source) &&
|
{SEARCH_SOURCE.includes(props.source) &&
|
||||||
deploymentType === 'modelList' && (
|
deploymentType === 'modelList' && (
|
||||||
<>
|
<>
|
||||||
<ColWrapper>
|
<ColWrapper>
|
||||||
<ColumnWrapper>
|
<SearchModel
|
||||||
<SearchModel
|
hasLinuxWorker={hasLinuxWorker}
|
||||||
hasLinuxWorker={hasLinuxWorker}
|
modelSource={props.source}
|
||||||
modelSource={props.source}
|
onSelectModel={handleOnSelectModel}
|
||||||
onSelectModel={handleOnSelectModel}
|
onSelectModelAfterEvaluate={handleOnSelectModelAfterEvaluate}
|
||||||
onSelectModelAfterEvaluate={
|
clusterId={
|
||||||
handleOnSelectModelAfterEvaluate
|
form.current?.getFieldValue?.('cluster_id') ||
|
||||||
}
|
initClusterId()
|
||||||
clusterId={
|
}
|
||||||
form.current?.getFieldValue?.('cluster_id') ||
|
displayEvaluateStatus={displayEvaluateStatus}
|
||||||
initClusterId()
|
gpuOptions={[]}
|
||||||
}
|
></SearchModel>
|
||||||
displayEvaluateStatus={displayEvaluateStatus}
|
|
||||||
gpuOptions={[]}
|
|
||||||
></SearchModel>
|
|
||||||
</ColumnWrapper>
|
|
||||||
<Separator></Separator>
|
<Separator></Separator>
|
||||||
</ColWrapper>
|
</ColWrapper>
|
||||||
<ColWrapper>
|
<ColWrapper>
|
||||||
<ColumnWrapper>
|
<ColumnWrapper styles={{ container: { paddingTop: 0 } }}>
|
||||||
<ModelCard
|
<ModelCard
|
||||||
selectedModel={selectedModel}
|
selectedModel={selectedModel}
|
||||||
onCollapse={setCollapsed}
|
onCollapse={setCollapsed}
|
||||||
@@ -545,7 +546,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
</>
|
</>
|
||||||
</ColumnWrapper>
|
</ColumnWrapper>
|
||||||
</FormWrapper>
|
</FormWrapper>
|
||||||
</div>
|
</Container>
|
||||||
</GSDrawer>
|
</GSDrawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { getRequestId, setRquestId } from '@/atoms/models';
|
import { getRequestId, setRquestId } from '@/atoms/models';
|
||||||
import BaseSelect from '@/components/seal-form/base/select';
|
import BaseSelect from '@/components/seal-form/base/select';
|
||||||
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
||||||
|
import ColumnWrapper from '@/pages/_components/column-wrapper';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Pagination } from 'antd';
|
import { Pagination } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -521,11 +522,11 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
onChange={handleSearchInputChange}
|
onChange={handleSearchInputChange}
|
||||||
modelSource={modelSource}
|
modelSource={modelSource}
|
||||||
></SearchInput>
|
></SearchInput>
|
||||||
<div className="gguf-tips">
|
{/* <div className="gguf-tips">
|
||||||
<span>
|
<span>
|
||||||
{intl.formatMessage({ id: 'models.form.search.gguftips' })}
|
{intl.formatMessage({ id: 'models.form.search.gguftips' })}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div> */}
|
||||||
<div className={SearchStyle.filter}>
|
<div className={SearchStyle.filter}>
|
||||||
<span className="flex-center gap-8">
|
<span className="flex-center gap-8">
|
||||||
<BaseSelect
|
<BaseSelect
|
||||||
@@ -582,18 +583,19 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ width: '100%' }}>
|
||||||
<div className={SearchStyle['search-bar']}>{renderHFSearch()}</div>
|
<div className={SearchStyle['search-bar']}>{renderHFSearch()}</div>
|
||||||
|
<ColumnWrapper maxHeight={'calc(100vh - 210px)'}>
|
||||||
<SearchResult
|
<SearchResult
|
||||||
loading={dataSource.loading}
|
loading={dataSource.loading}
|
||||||
resultList={dataSource.dataList}
|
resultList={dataSource.dataList}
|
||||||
networkError={dataSource.networkError}
|
networkError={dataSource.networkError}
|
||||||
current={current}
|
current={current}
|
||||||
source={modelSource}
|
source={modelSource}
|
||||||
isEvaluating={isEvaluating}
|
isEvaluating={isEvaluating}
|
||||||
onSelect={handleSelectModelManually}
|
onSelect={handleSelectModelManually}
|
||||||
></SearchResult>
|
></SearchResult>
|
||||||
|
</ColumnWrapper>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import SimpleOverlay from '@/components/simple-overlay';
|
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Empty, Spin } from 'antd';
|
import { Button, Empty, Spin } from 'antd';
|
||||||
@@ -121,7 +120,7 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
|||||||
}, [networkError, source, intl]);
|
}, [networkError, source, intl]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleOverlay style={{ height: 'calc(100vh - 224px)' }}>
|
<>
|
||||||
<div style={{ ...props.style }} className="search-result-wrap">
|
<div style={{ ...props.style }} className="search-result-wrap">
|
||||||
<Spin spinning={props.loading}>
|
<Spin spinning={props.loading}>
|
||||||
<div style={{ minHeight: 200 }}>
|
<div style={{ minHeight: 200 }}>
|
||||||
@@ -167,7 +166,7 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
</SimpleOverlay>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ interface FormContextProps {
|
|||||||
formKey: DeployFormKey;
|
formKey: DeployFormKey;
|
||||||
source: string;
|
source: string;
|
||||||
pageAction: PageActionType;
|
pageAction: PageActionType;
|
||||||
gpuOptions?: any[];
|
gpuOptions: any[];
|
||||||
backendOptions: BackendOption[];
|
backendOptions: BackendOption[];
|
||||||
onValuesChange?: (changedValues: any, allValues: any) => void;
|
onValuesChange?: (changedValues: any, allValues: any) => void;
|
||||||
onBackendChange: (backend: string, option: any) => void;
|
onBackendChange: (backend: string, option: any) => void;
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
import LabelSelector from '@/components/label-selector';
|
||||||
|
import CheckboxField from '@/components/seal-form/checkbox-field';
|
||||||
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
|
import TooltipList from '@/components/tooltip-list';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Form } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import {
|
||||||
|
modelCategories,
|
||||||
|
placementStrategyOptions,
|
||||||
|
ScheduleValueMap
|
||||||
|
} from '../config';
|
||||||
|
import { backendOptionsMap } from '../config/backend-parameters';
|
||||||
|
import { useFormContext } from '../config/form-context';
|
||||||
|
import { FormData } from '../config/types';
|
||||||
|
import Backend from '../forms/backend';
|
||||||
|
import BackendParametersList from '../forms/backend-parameters-list';
|
||||||
|
|
||||||
|
const placementStrategyTips = [
|
||||||
|
{
|
||||||
|
title: 'Spread',
|
||||||
|
tips: 'resources.form.spread.tips'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Binpack',
|
||||||
|
tips: 'resources.form.binpack.tips'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const AdvanceConfig = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const form = Form.useFormInstance();
|
||||||
|
const wokerSelector = Form.useWatch('worker_selector', form);
|
||||||
|
const EnviromentVars = Form.useWatch('env', form);
|
||||||
|
const scheduleType = Form.useWatch('scheduleType', form);
|
||||||
|
const backend = Form.useWatch('backend', form);
|
||||||
|
const { onValuesChange } = useFormContext();
|
||||||
|
|
||||||
|
const handleWorkerLabelsChange = useCallback(
|
||||||
|
(labels: Record<string, any>) => {
|
||||||
|
form.setFieldValue('worker_selector', labels);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const handleEnviromentVarsChange = useCallback(
|
||||||
|
(labels: Record<string, any>) => {
|
||||||
|
form.setFieldValue('env', labels);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectorChange = (field: string, allowEmpty?: boolean) => {
|
||||||
|
const workerSelector = form.getFieldValue(field);
|
||||||
|
// check if all keys have values
|
||||||
|
const hasEmptyValue = _.some(_.keys(workerSelector), (k: string) => {
|
||||||
|
return !workerSelector[k];
|
||||||
|
});
|
||||||
|
if (!hasEmptyValue || allowEmpty) {
|
||||||
|
onValuesChange?.({}, form.getFieldsValue());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectorOnBlur = () => {
|
||||||
|
onSelectorChange('worker_selector');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteWorkerSelector = (index: number) => {
|
||||||
|
onValuesChange?.({}, form.getFieldsValue());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEnvSelectorOnBlur = () => {
|
||||||
|
onSelectorChange('env', true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteEnvSelector = (index: number) => {
|
||||||
|
onValuesChange?.({}, form.getFieldsValue());
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item<FormData> name="categories">
|
||||||
|
<SealSelect
|
||||||
|
allowNull
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'models.form.categories'
|
||||||
|
})}
|
||||||
|
options={modelCategories}
|
||||||
|
></SealSelect>
|
||||||
|
</Form.Item>
|
||||||
|
<Backend></Backend>
|
||||||
|
{scheduleType === ScheduleValueMap.Auto && (
|
||||||
|
<>
|
||||||
|
<Form.Item<FormData> name="placement_strategy">
|
||||||
|
<SealSelect
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'resources.form.placementStrategy'
|
||||||
|
})}
|
||||||
|
options={placementStrategyOptions}
|
||||||
|
description={
|
||||||
|
<TooltipList list={placementStrategyTips}></TooltipList>
|
||||||
|
}
|
||||||
|
></SealSelect>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="worker_selector"
|
||||||
|
rules={[
|
||||||
|
({ getFieldValue }) => ({
|
||||||
|
validator(rule, value) {
|
||||||
|
if (
|
||||||
|
getFieldValue('scheduleType') === ScheduleValueMap.Auto &&
|
||||||
|
_.keys(value).length > 0
|
||||||
|
) {
|
||||||
|
if (_.some(_.keys(value), (k: string) => !value[k])) {
|
||||||
|
return Promise.reject(
|
||||||
|
intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'common.validate.value'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: intl.formatMessage({
|
||||||
|
id: 'models.form.selector'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<LabelSelector
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'resources.form.workerSelector'
|
||||||
|
})}
|
||||||
|
labels={wokerSelector}
|
||||||
|
onChange={handleWorkerLabelsChange}
|
||||||
|
onBlur={handleSelectorOnBlur}
|
||||||
|
onDelete={handleDeleteWorkerSelector}
|
||||||
|
description={
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: 'resources.form.workerSelector.description'
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
></LabelSelector>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<BackendParametersList></BackendParametersList>
|
||||||
|
<Form.Item<FormData> name="env">
|
||||||
|
<LabelSelector
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'models.form.env'
|
||||||
|
})}
|
||||||
|
labels={EnviromentVars}
|
||||||
|
btnText={intl.formatMessage({ id: 'common.button.vars' })}
|
||||||
|
onBlur={handleEnvSelectorOnBlur}
|
||||||
|
onDelete={handleDeleteEnvSelector}
|
||||||
|
onChange={handleEnviromentVarsChange}
|
||||||
|
></LabelSelector>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
{scheduleType === ScheduleValueMap.Auto &&
|
||||||
|
[backendOptionsMap.vllm, backendOptionsMap.ascendMindie].includes(
|
||||||
|
backend
|
||||||
|
) && (
|
||||||
|
<div style={{ paddingBottom: 22, paddingLeft: 10 }}>
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="distributed_inference_across_workers"
|
||||||
|
valuePropName="checked"
|
||||||
|
style={{ padding: '0 10px', marginBottom: 0 }}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
<CheckboxField
|
||||||
|
description={intl.formatMessage({
|
||||||
|
id: 'models.form.distribution.tips'
|
||||||
|
})}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'resources.form.enableDistributedInferenceAcrossWorkers'
|
||||||
|
})}
|
||||||
|
></CheckboxField>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div style={{ paddingBottom: 22, paddingLeft: 10 }}>
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="restart_on_error"
|
||||||
|
valuePropName="checked"
|
||||||
|
style={{ padding: '0 10px', marginBottom: 0 }}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
<CheckboxField
|
||||||
|
description={intl.formatMessage({
|
||||||
|
id: 'models.form.restart.onerror.tips'
|
||||||
|
})}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'models.form.restart.onerror'
|
||||||
|
})}
|
||||||
|
></CheckboxField>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdvanceConfig;
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import IconFont from '@/components/icon-font';
|
||||||
|
import ListInput from '@/components/list-input';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Form, Typography } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { backendParamsHolderTips, getBackendParamsTips } from '../config';
|
||||||
|
import BackendParameters, {
|
||||||
|
backendOptionsMap
|
||||||
|
} from '../config/backend-parameters';
|
||||||
|
import { useFormContext } from '../config/form-context';
|
||||||
|
import { FormData } from '../config/types';
|
||||||
|
|
||||||
|
const BackendParametersList: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const { onValuesChange } = useFormContext();
|
||||||
|
const form = Form.useFormInstance();
|
||||||
|
const backend = Form.useWatch('backend', form);
|
||||||
|
|
||||||
|
const backendParamsTips = useMemo(() => {
|
||||||
|
return getBackendParamsTips(backend);
|
||||||
|
}, [backend]);
|
||||||
|
|
||||||
|
const paramsConfig = useMemo(() => {
|
||||||
|
return _.get(BackendParameters, backend, []);
|
||||||
|
}, [backend]);
|
||||||
|
|
||||||
|
const handleBackendParametersChange = (list: string[]) => {
|
||||||
|
form.setFieldValue('backend_parameters', list);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBackendParametersOnBlur = () => {
|
||||||
|
onValuesChange?.({}, form.getFieldsValue());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteBackendParameters = (index: number) => {
|
||||||
|
onValuesChange?.({}, form.getFieldsValue());
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item<FormData> name="backend_parameters">
|
||||||
|
<ListInput
|
||||||
|
placeholder={
|
||||||
|
backendParamsHolderTips[backend]
|
||||||
|
? intl.formatMessage({
|
||||||
|
id: backendParamsHolderTips[backend].holder
|
||||||
|
})
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
btnText={intl.formatMessage({ id: 'common.button.addParams' })}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'models.form.backend_parameters'
|
||||||
|
})}
|
||||||
|
dataList={form.getFieldValue('backend_parameters') || []}
|
||||||
|
onChange={handleBackendParametersChange}
|
||||||
|
onBlur={handleBackendParametersOnBlur}
|
||||||
|
onDelete={handleDeleteBackendParameters}
|
||||||
|
options={paramsConfig}
|
||||||
|
description={
|
||||||
|
backendParamsTips.link && (
|
||||||
|
<span>
|
||||||
|
{backend === backendOptionsMap.ascendMindie && (
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'models.backend.mindie.310p' })}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span style={{ marginLeft: 5 }}>
|
||||||
|
{intl.formatMessage(
|
||||||
|
{ id: 'models.form.backend_parameters.vllm.tips' },
|
||||||
|
{ backend: backendParamsTips.backend || '' }
|
||||||
|
)}{' '}
|
||||||
|
<Typography.Link
|
||||||
|
style={{ display: 'inline' }}
|
||||||
|
className="flex-center"
|
||||||
|
href={backendParamsTips.link}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span>{intl.formatMessage({ id: 'common.text.here' })}</span>
|
||||||
|
<IconFont
|
||||||
|
type="icon-external-link"
|
||||||
|
className="font-size-14 m-l-4"
|
||||||
|
></IconFont>
|
||||||
|
</Typography.Link>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
></ListInput>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BackendParametersList;
|
||||||
+9
-3
@@ -14,9 +14,14 @@ import useCheckBackend from '../hooks/use-check-backend';
|
|||||||
const LocalPathForm: React.FC = () => {
|
const LocalPathForm: React.FC = () => {
|
||||||
const { checkOnlyAscendNPU } = useCheckBackend();
|
const { checkOnlyAscendNPU } = useCheckBackend();
|
||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
const formCtx = useFormContext();
|
|
||||||
const source = Form.useWatch('source', form);
|
const source = Form.useWatch('source', form);
|
||||||
const { formKey, gpuOptions, onValuesChange, onBackendChange } = formCtx;
|
const {
|
||||||
|
formKey,
|
||||||
|
gpuOptions,
|
||||||
|
backendOptions,
|
||||||
|
onValuesChange,
|
||||||
|
onBackendChange
|
||||||
|
} = useFormContext();
|
||||||
const { getRuleMessage } = useAppUtils();
|
const { getRuleMessage } = useAppUtils();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const localPathCache = useRef<string>(form.getFieldValue('local_path') || '');
|
const localPathCache = useRef<string>(form.getFieldValue('local_path') || '');
|
||||||
@@ -58,7 +63,8 @@ const LocalPathForm: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (oldBackend !== backend) {
|
if (oldBackend !== backend) {
|
||||||
onBackendChange?.(backend);
|
const option = backendOptions.find((item) => item.value === backend);
|
||||||
|
onBackendChange?.(backend, option);
|
||||||
} else {
|
} else {
|
||||||
onValuesChange?.({ local_path: value }, form.getFieldsValue());
|
onValuesChange?.({ local_path: value }, form.getFieldsValue());
|
||||||
}
|
}
|
||||||
+1
-1
@@ -5,10 +5,10 @@ import useAppUtils from '@/hooks/use-app-utils';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import GPUCard from '../components/gpu-card';
|
||||||
import { scheduleList, ScheduleValueMap } from '../config';
|
import { scheduleList, ScheduleValueMap } from '../config';
|
||||||
import { backendOptionsMap } from '../config/backend-parameters';
|
import { backendOptionsMap } from '../config/backend-parameters';
|
||||||
import { useCatalogFormContext, useFormContext } from '../config/form-context';
|
import { useCatalogFormContext, useFormContext } from '../config/form-context';
|
||||||
import GPUCard from './gpu-card';
|
|
||||||
|
|
||||||
const scheduleTypeTips = [
|
const scheduleTypeTips = [
|
||||||
{
|
{
|
||||||
@@ -26,8 +26,3 @@
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-wrapper {
|
|
||||||
padding: 16px 24px;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@padding: 24px;
|
@padding: 24px;
|
||||||
|
|
||||||
.search-result-wrap {
|
.search-result-wrap {
|
||||||
padding: 16px @padding;
|
|
||||||
border-radius: 0 0 var(--border-radius-base) var(--border-radius-base);
|
border-radius: 0 0 var(--border-radius-base) var(--border-radius-base);
|
||||||
|
|
||||||
.ant-spin-container.ant-spin-blur {
|
.ant-spin-container.ant-spin-blur {
|
||||||
@@ -21,8 +20,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding-inline: @padding;
|
padding-inline: @padding;
|
||||||
background: var(--ant-color-bg-elevated);
|
background: var(--ant-color-bg-elevated);
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
@@ -32,6 +29,8 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
row-gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
color: var(--ant-color-text-tertiary);
|
color: var(--ant-color-text-tertiary);
|
||||||
|
|
||||||
:global {
|
:global {
|
||||||
|
|||||||
Reference in New Issue
Block a user