fix: page error when edit error

main
jialin 12 months ago
parent f91311144b
commit 0f7d04e0b9

@ -37,6 +37,7 @@ const AutoTooltip: React.FC<AutoTooltipProps> = ({
}) => {
const contentRef = useRef<HTMLDivElement>(null);
const [isOverflowing, setIsOverflowing] = useState(false);
const resizeObserver = useRef<ResizeObserver | null>(null);
const checkOverflow = useCallback(() => {
if (contentRef.current) {
@ -48,17 +49,20 @@ const AutoTooltip: React.FC<AutoTooltipProps> = ({
useEffect(() => {
const element = contentRef.current;
if (!element) return;
const resizeObserver = new ResizeObserver(() => {
resizeObserver.current?.disconnect();
resizeObserver.current = new ResizeObserver(() => {
checkOverflow();
});
resizeObserver.observe(element);
resizeObserver.current?.observe(element);
// Initial check
checkOverflow();
return () => resizeObserver.disconnect();
return () => {
resizeObserver.current?.disconnect();
resizeObserver.current = null;
};
}, [checkOverflow]);
useEffect(() => {

@ -5,7 +5,7 @@
display: flex;
justify-content: flex-start;
align-items: center;
padding-inline: 8px 12px;
// padding-inline: 2px 2px;
height: 54px;
border-width: var(--ant-line-width);
border-style: var(--ant-line-type);
@ -82,7 +82,7 @@
position: relative;
color: var(--ant-color-text-quaternary);
font-size: 14px;
// padding-right: calc(var(--ant-padding-sm) - 1px);
padding-right: calc(var(--ant-padding-sm) - 1px);
}
}
@ -90,7 +90,7 @@
@wrapheight: 54px;
@inputheight: 32px;
@borderRadius: 8px;
@input-inner-padding: 6px;
@input-inner-padding: 14px;
@bgColor: transparent;
position: relative;
@ -124,7 +124,7 @@
.label {
position: absolute;
left: 6px;
left: @input-inner-padding;
color: rgba(0, 0, 0, 45%);
font-size: var(--font-size-base);
line-height: 1;
@ -172,7 +172,14 @@
}
:global(.ant-select-selection-search) {
inset-inline-start: 8px !important;
inset-inline-start: @input-inner-padding;
}
:global(.ant-select-multiple.ant-select-lg) {
:global(.ant-select-selection-search) {
margin-inline-start: 0 !important;
left: 0 !important;
}
}
:global(.ant-select-selection-item) {
@ -211,6 +218,7 @@
:global(.ant-select-selection-search-input) {
height: @inputheight !important;
}
// ==================== input ====================
:global(.ant-input),

@ -4,6 +4,7 @@ import type { CascaderAutoProps } from 'antd';
import { Cascader, Form } from 'antd';
import { cloneDeep } from 'lodash';
import { useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import Wrapper from './components/wrapper';
import { SealFormItemProps } from './types';
@ -24,6 +25,7 @@ const SealCascader: React.FC<CascaderAutoProps & SealFormItemProps> = (
const intl = useIntl();
const [isFocus, setIsFocus] = useState(false);
const inputRef = useRef<any>(null);
const boxRef = useRef<any>(null);
let status = '';
// the status can be controlled by Form.Item
@ -81,26 +83,30 @@ const SealCascader: React.FC<CascaderAutoProps & SealFormItemProps> = (
props.onBlur?.(e);
};
const Boxer = styled.div``;
return (
<Wrapper
status={status}
label={label}
isFocus={isFocus}
required={required}
description={description}
disabled={props.disabled}
onClick={handleClickWrapper}
>
<Cascader
{...rest}
ref={inputRef}
options={children ? null : _options}
onFocus={handleOnFocus}
onBlur={handleOnBlur}
onChange={handleChange}
notFoundContent={null}
></Cascader>
</Wrapper>
<>
<Wrapper
status={status}
label={label}
isFocus={isFocus}
required={required}
description={description}
disabled={props.disabled}
onClick={handleClickWrapper}
>
<Cascader
{...rest}
ref={inputRef}
options={children ? null : _options}
onFocus={handleOnFocus}
onBlur={handleOnBlur}
onChange={handleChange}
notFoundContent={null}
></Cascader>
</Wrapper>
</>
);
};

@ -19,6 +19,7 @@ const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
addAfter,
checkStatus,
trim = true,
loading,
...rest
} = props;
const [isFocus, setIsFocus] = useState(false);

@ -22,6 +22,7 @@ const SealSelect: React.FC<SelectProps & SealFormItemProps> = (props) => {
const intl = useIntl();
const [isFocus, setIsFocus] = useState(false);
const inputRef = useRef<any>(null);
const boxRef = useRef<any>(null);
let status = '';
// the status can be controlled by Form.Item

@ -31,9 +31,9 @@ const TagsWrapper: React.FC<TagsWrapperProps> = (props) => {
if (!sizeList.length && childNodes?.length) {
sizeList = _.map(childNodes, (node: HTMLDivElement, index: number) => {
if (index === childNodes.length - 1) {
return node.offsetWidth;
return node?.offsetWidth;
}
return node.offsetWidth + gap;
return node?.offsetWidth + gap;
});
nodeSizeList.current = sizeList;
}

@ -31,6 +31,7 @@ html {
--color-logs-text: #d4d4d4;
--layout-content-blockpadding: 32px;
--layout-content-inlinepadding: 32px;
--layout-content-header-inlinepadding: 40px;
--border-radius-modal: 6px;
--menu-border-radius-base: 4px;
--border-radius-base: 4px;
@ -797,7 +798,7 @@ body {
}
.cascader-popup-wrapper {
width: 100%;
// width: 100%;
&.gpu-selector {
.ant-cascader-menu:last-child {

@ -10,7 +10,7 @@ const AccessPage: React.FC = () => {
header={{
title: 'permission example',
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
}
}}
>

@ -184,7 +184,7 @@ const APIKeys: React.FC = () => {
header={{
title: intl.formatMessage({ id: 'apikeys.title' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
}
}}
extra={[]}

@ -13,7 +13,7 @@ const Dashboard: React.FC = () => {
extra={[]}
header={{
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
}
}}
>

@ -209,7 +209,7 @@ const Catalog: React.FC = () => {
header={{
title: intl.formatMessage({ id: 'menu.modelCatalog' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}

@ -39,8 +39,7 @@ interface AdvanceConfigProps {
}
const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
const { form, isGGUF, action, gpuOptions, source } = props;
const { form, isGGUF, gpuOptions, source } = props;
const intl = useIntl();
const wokerSelector = Form.useWatch('worker_selector', form);
const EnviromentVars = Form.useWatch('env', form);
@ -50,7 +49,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
const categories = Form.useWatch('categories', form);
const backend_version = Form.useWatch('backend_version', 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 placementStrategyTips = [
@ -208,41 +207,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
}
></SealSelect>
</Form.Item>
<Form.Item<FormData>
name="env"
rules={[
() => ({
validator(rule, value) {
if (_.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: 'common.text.variable'
})
}
)
);
}
}
return Promise.resolve();
}
})
]}
>
<LabelSelector
label={intl.formatMessage({
id: 'models.form.env'
})}
labels={EnviromentVars}
btnText="common.button.vars"
onChange={handleEnviromentVarsChange}
></LabelSelector>
</Form.Item>
<Form.Item<FormData>
name="worker_selector"
rules={[
@ -381,6 +345,41 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
}
></ListInput>
</Form.Item>
<Form.Item<FormData>
name="env"
rules={[
() => ({
validator(rule, value) {
if (_.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: 'common.text.variable'
})
}
)
);
}
}
return Promise.resolve();
}
})
]}
>
<LabelSelector
label={intl.formatMessage({
id: 'models.form.env'
})}
labels={EnviromentVars}
btnText="common.button.vars"
onChange={handleEnviromentVarsChange}
></LabelSelector>
</Form.Item>
{backend === backendOptionsMap.llamaBox && (
<div style={{ paddingBottom: 22, paddingLeft: 10 }}>
@ -467,6 +466,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
backend_version,
placement_strategy,
gpuSelectorIds,
EnviromentVars,
worker_selector
]);

@ -17,7 +17,6 @@ import React, {
useRef,
useState
} from 'react';
import { queryGPUList } from '../apis';
import {
HuggingFaceTaskMap,
ModelscopeTaskMap,
@ -28,7 +27,7 @@ import {
sourceOptions
} from '../config';
import { HuggingFaceModels, ModelScopeModels } from '../config/audio-catalog';
import { FormData, GPUListItem } from '../config/types';
import { FormData } from '../config/types';
import AdvanceConfig from './advance-config';
interface DataFormProps {
@ -43,6 +42,7 @@ interface DataFormProps {
byBuiltIn?: boolean;
backendOptions?: Global.BaseOption<string>[];
sourceList?: Global.BaseOption<string>[];
gpuOptions: any[];
onSizeChange?: (val: number) => void;
onQuantizationChange?: (val: string) => void;
onSourceChange?: (value: string) => void;
@ -71,6 +71,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
backendOptions,
sourceList,
byBuiltIn,
gpuOptions = [],
sizeOptions = [],
quantizationOptions = [],
fields = ['source'],
@ -79,7 +80,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
} = props;
const [form] = Form.useForm();
const intl = useIntl();
const [gpuOptions, setGpuOptions] = useState<Array<GPUOption>>([]);
const [modelTask, setModelTask] = useState<Record<string, any>>({
type: '',
value: '',
@ -119,42 +119,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
}
];
const generateCascaderOptions = (list: GPUListItem[]) => {
const workerFields = ['worker_name', 'worker_id', 'worker_ip'];
const workers = _.groupBy(list, 'worker_name');
const workerList = _.map(workers, (value: GPUListItem[]) => {
return {
label: `${value[0].worker_name}`,
value: value[0].worker_name,
parent: true,
disableCheckbox: false,
..._.pick(value[0], workerFields),
children: _.map(value, (item: GPUListItem) => {
return {
label: `${item.name}`,
value: item.id,
disableCheckbox: false,
..._.omit(item, workerFields)
};
})
};
});
return workerList;
};
const getGPUList = async () => {
const data = await queryGPUList();
const gpuList = generateCascaderOptions(data.items);
setGpuOptions(gpuList);
};
useEffect(() => {
getGPUList();
}, []);
const handleSumit = () => {
form.submit();
};
@ -335,24 +299,26 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
defaultActiveFirstOption
disabled={false}
options={ollamaModelOptions}
label={intl.formatMessage({ id: 'model.form.ollama.model' })}
placeholder={intl.formatMessage({ id: 'model.form.ollamaholder' })}
addAfter={
<Typography.Link
href="https://www.ollama.com/library"
target="_blank"
>
<Tooltip
title={intl.formatMessage({ id: 'models.form.ollamalink' })}
placement="topRight"
label={
<>
{intl.formatMessage({ id: 'model.form.ollama.model' })}{' '}
<Typography.Link
href="https://www.ollama.com/library"
target="_blank"
>
<IconFont
type="icon-external-link"
className="font-size-14"
></IconFont>
</Tooltip>
</Typography.Link>
<Tooltip
title={intl.formatMessage({ id: 'models.form.ollamalink' })}
placement="topRight"
>
<IconFont
type="icon-external-link"
className="font-size-14"
></IconFont>
</Tooltip>
</Typography.Link>
</>
}
placeholder={intl.formatMessage({ id: 'model.form.ollamaholder' })}
required
></SealAutoComplete>
</Form.Item>

@ -4,7 +4,7 @@ import { CloseOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Drawer } from 'antd';
import { debounce } from 'lodash';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { backendOptionsMap, modelSourceMap } from '../config';
import { FormData } from '../config/types';
import ColumnWrapper from './column-wrapper';
@ -21,6 +21,7 @@ type AddModalProps = {
open: boolean;
source: string;
width?: string | number;
gpuOptions?: any[];
onOk: (values: FormData) => void;
onCancel: () => void;
};
@ -44,14 +45,11 @@ const AddModal: React.FC<AddModalProps> = (props) => {
const intl = useIntl();
const [selectedModel, setSelectedModel] = useState<any>({});
const [collapsed, setCollapsed] = useState<boolean>(false);
const [loadingModel, setLoadingModel] = useState<boolean>(false);
const [isGGUF, setIsGGUF] = useState<boolean>(false);
const modelFileRef = useRef<any>(null);
const [loadfinish, setLoadfinish] = useState<boolean>(false);
const handleSelectModelFile = useCallback((item: any) => {
form.current?.setFieldValue?.('file_name', item.fakeName);
setLoadfinish(true);
}, []);
const handleOnSelectModel = (item: any) => {
@ -151,7 +149,6 @@ const AddModal: React.FC<AddModalProps> = (props) => {
<SearchModel
modelSource={props.source}
onSelectModel={handleOnSelectModel}
setLoadingModel={setLoadingModel}
></SearchModel>
</ColumnWrapper>
<Separator></Separator>
@ -206,6 +203,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
onOk={onOk}
ref={form}
isGGUF={isGGUF}
gpuOptions={props.gpuOptions}
onBackendChange={handleBackendChange}
></DataForm>
</>
@ -215,4 +213,4 @@ const AddModal: React.FC<AddModalProps> = (props) => {
);
};
export default memo(AddModal);
export default AddModal;

@ -286,7 +286,8 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
: undefined
}
extra={
item.state === InstanceStatusMap.Error ? (
item.state === InstanceStatusMap.Error &&
item.worker_id ? (
<Button
type="link"
size="small"

@ -60,12 +60,14 @@ import {
} from '../apis';
import {
InstanceRealtimeLogStatus,
backendOptionsMap,
getSourceRepoConfigValue,
modelCategories,
modelCategoriesMap,
modelSourceMap
} from '../config';
import { FormData, ListItem, ModelInstanceListItem } from '../config/types';
import { useGenerateFormEditInitialValues } from '../hooks';
import DeployDropdown from './deploy-dropdown';
import DeployModal from './deploy-modal';
import InstanceItem from './instance-item';
@ -172,7 +174,6 @@ const Models: React.FC<ModelsProps> = ({
handleCategoryChange,
deleteIds,
dataSource,
gpuDeviceList,
workerList,
catalogList,
queryParams,
@ -180,7 +181,18 @@ const Models: React.FC<ModelsProps> = ({
loadend,
total
}) => {
const { getGPUList, generateFormValues, gpuDeviceList } =
useGenerateFormEditInitialValues();
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
const [updateFormInitials, setUpdateFormInitials] = useState<{
gpuOptions: any[];
data: any;
isGGUF: boolean;
}>({
gpuOptions: [],
data: {},
isGGUF: false
});
const [isFirstLogin, setIsFirstLogin] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [expandAtom, setExpandAtom] = useAtom(modelsExpandKeysAtom);
@ -200,12 +212,18 @@ const Models: React.FC<ModelsProps> = ({
const [openLogModal, setOpenLogModal] = useState(false);
const [openAddModal, setOpenAddModal] = useState(false);
const [openDeployModal, setOpenDeployModal] = useState<any>({
const [openDeployModal, setOpenDeployModal] = useState<{
show: boolean;
width: number | string;
source: string;
gpuOptions: any[];
}>({
show: false,
width: 600,
source: modelSourceMap.huggingface_value
source: modelSourceMap.huggingface_value,
gpuOptions: []
});
const [currentData, setCurrentData] = useState<ListItem>({} as ListItem);
const currentData = useRef<ListItem>({} as ListItem);
const [currentInstance, setCurrentInstance] = useState<{
url: string;
status: string;
@ -235,7 +253,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 'calc(100vw - 220px)',
source: modelSourceMap.huggingface_value
source: modelSourceMap.huggingface_value,
gpuOptions: gpuDeviceList.current
});
},
{
@ -250,7 +269,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 'calc(100vw - 220px)',
source: modelSourceMap.modelscope_value
source: modelSourceMap.modelscope_value,
gpuOptions: gpuDeviceList.current
});
},
{
@ -265,7 +285,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 600,
source: modelSourceMap.ollama_library_value
source: modelSourceMap.ollama_library_value,
gpuOptions: gpuDeviceList.current
});
},
{
@ -279,7 +300,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 600,
source: modelSourceMap.local_path_value
source: modelSourceMap.local_path_value,
gpuOptions: gpuDeviceList.current
});
},
{
@ -295,6 +317,7 @@ const Models: React.FC<ModelsProps> = ({
}, [deleteIds]);
useEffect(() => {
getGPUList();
return () => {
setExpandAtom([]);
};
@ -333,6 +356,10 @@ const Models: React.FC<ModelsProps> = ({
}
];
const setCurrentData = (data: ListItem) => {
currentData.current = data;
};
const handleOnSort = (dataIndex: string, order: any) => {
setSortOrder(order);
};
@ -396,13 +423,16 @@ const Models: React.FC<ModelsProps> = ({
const handleModalOk = useCallback(
async (data: FormData) => {
try {
const result = getSourceRepoConfigValue(currentData?.source, data);
const result = getSourceRepoConfigValue(
currentData.current?.source,
data
);
await updateModel({
data: {
...result.values,
..._.omit(data, result.omits)
},
id: currentData?.id as number
id: currentData.current?.id as number
});
setOpenAddModal(false);
message.success(intl.formatMessage({ id: 'common.message.success' }));
@ -568,7 +598,14 @@ const Models: React.FC<ModelsProps> = ({
return `${MODELS_API}/${params.id}/instances`;
}, []);
const handleEdit = (row: ListItem) => {
const handleEdit = async (row: ListItem) => {
const initialValues = generateFormValues(row, gpuDeviceList.current);
console.log('initialValues:', initialValues, row);
setUpdateFormInitials({
gpuOptions: gpuDeviceList.current,
data: initialValues,
isGGUF: row.backend === backendOptionsMap.llamaBox
});
setCurrentData(row);
setOpenAddModal(true);
saveScrollHeight();
@ -639,7 +676,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 'calc(100vw - 220px)',
source: modelSourceMap.huggingface_value
source: modelSourceMap.huggingface_value,
gpuOptions: gpuDeviceList.current
});
}
@ -647,7 +685,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 600,
source: modelSourceMap.ollama_library_value
source: modelSourceMap.ollama_library_value,
gpuOptions: gpuDeviceList.current
});
}
@ -655,7 +694,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 'calc(100vw - 220px)',
source: modelSourceMap.modelscope_value
source: modelSourceMap.modelscope_value,
gpuOptions: gpuDeviceList.current
});
}
@ -663,7 +703,8 @@ const Models: React.FC<ModelsProps> = ({
setOpenDeployModal({
show: true,
width: 600,
source: modelSourceMap.local_path_value
source: modelSourceMap.local_path_value,
gpuOptions: gpuDeviceList.current
});
}
if (item.key === 'catalog') {
@ -836,7 +877,7 @@ const Models: React.FC<ModelsProps> = ({
header={{
title: intl.formatMessage({ id: 'models.title' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}
@ -844,7 +885,6 @@ const Models: React.FC<ModelsProps> = ({
>
<PageTools
marginBottom={22}
style={{ display: isFirstLogin ? 'none' : 'flex' }}
left={
<Space>
<Input
@ -975,7 +1015,7 @@ const Models: React.FC<ModelsProps> = ({
open={openAddModal}
action={PageAction.EDIT}
title={intl.formatMessage({ id: 'models.title.edit' })}
data={currentData}
updateFormInitials={updateFormInitials}
onCancel={handleModalCancel}
onOk={handleModalOk}
></UpdateModel>
@ -985,6 +1025,7 @@ const Models: React.FC<ModelsProps> = ({
title={intl.formatMessage({ id: 'models.button.deploy' })}
source={openDeployModal.source}
width={openDeployModal.width}
gpuOptions={openDeployModal.gpuOptions}
onCancel={handleDeployModalCancel}
onOk={handleCreateModel}
></DeployModal>

@ -8,31 +8,26 @@ import { PageActionType } from '@/config/types';
import { useIntl } from '@umijs/max';
import { Form, Modal, Tooltip, Typography } from 'antd';
import _ from 'lodash';
import React, {
memo,
useCallback,
useEffect,
useMemo,
useRef,
useState
} from 'react';
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import SimpleBar from 'simplebar-react';
import 'simplebar-react/dist/simplebar.min.css';
import { queryGPUList } from '../apis';
import {
backendOptionsMap,
modelSourceMap,
ollamaModelOptions,
setSourceRepoConfigValue
ollamaModelOptions
} from '../config';
import { FormData, GPUListItem, ListItem } from '../config/types';
import { FormData, ListItem } from '../config/types';
import AdvanceConfig from './advance-config';
type AddModalProps = {
title: string;
action: PageActionType;
open: boolean;
data?: ListItem;
updateFormInitials: {
data?: ListItem;
gpuOptions: any[];
isGGUF: boolean;
};
onOk: (values: FormData) => void;
onCancel: () => void;
};
@ -67,90 +62,18 @@ const sourceOptions = [
];
const UpdateModal: React.FC<AddModalProps> = (props) => {
const { title, action, open, onOk, onCancel } = props || {};
const {
title,
action,
open,
onOk,
onCancel,
updateFormInitials: { gpuOptions, isGGUF, data: formData }
} = props || {};
const [form] = Form.useForm();
const intl = useIntl();
const [gpuOptions, setGpuOptions] = useState<any[]>([]);
const [isGGUF, setIsGGUF] = useState<boolean>(false);
const [loading, setLoading] = useState(false);
const localPathCache = useRef<string>('');
const generateCascaderOptions = (list: GPUListItem[]) => {
const workerFields = ['worker_name', 'worker_id', 'worker_ip'];
const workers = _.groupBy(list, 'worker_name');
const workerList = _.map(workers, (value: GPUListItem[]) => {
return {
label: `${value[0].worker_name}`,
value: value[0].worker_name,
parent: true,
..._.pick(value[0], workerFields),
children: _.map(value, (item: GPUListItem) => {
return {
label: `${item.name}`,
value: item.id,
..._.omit(item, workerFields)
};
})
};
});
return workerList;
};
const getGPUList = async () => {
const data = await queryGPUList();
const gpuList = generateCascaderOptions(data.items);
setGpuOptions(gpuList);
};
const generateGPUSelector = (data: any) => {
const gpu_ids = _.get(data, 'gpu_selector.gpu_ids', []);
if (gpu_ids.length === 0) {
return [];
}
const gpuids: string[][] = [];
gpuOptions?.forEach((item) => {
item.children?.forEach((child: any) => {
if (gpu_ids.includes(child.value)) {
gpuids.push([item.value, child.value]);
}
});
});
return data.backend === backendOptionsMap.voxBox ? gpuids[0] : gpuids;
};
useEffect(() => {
if (action === PageAction.EDIT && open) {
const result = setSourceRepoConfigValue(
props.data?.source || '',
props.data
);
const formData = {
...result.values,
..._.omit(props.data, result.omits),
categories: props.data?.categories?.length
? props.data.categories[0]
: null,
scheduleType: props.data?.gpu_selector ? 'manual' : 'auto',
gpu_selector: props.data?.gpu_selector?.gpu_ids.length
? {
gpu_ids: generateGPUSelector(props.data)
}
: []
};
form.setFieldsValue(formData);
}
}, [open]);
useEffect(() => {
setIsGGUF(props.data?.backend === backendOptionsMap.llamaBox);
}, [props.data?.backend]);
const handleSetGPUIds = (backend: string) => {
if (backend === backendOptionsMap.llamaBox) {
return;
@ -235,7 +158,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
<SealInput.Input
label={intl.formatMessage({ id: 'models.form.filename' })}
required
loading={loading}
disabled={false}
></SealInput.Input>
</Form.Item>
@ -244,34 +166,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
);
};
const renderS3Fields = () => {
return (
<>
<Form.Item<FormData>
name="s3_address"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.input'
},
{ name: intl.formatMessage({ id: 'models.form.s3address' }) }
)
}
]}
>
<SealInput.Input
label={intl.formatMessage({
id: 'models.form.s3address'
})}
required
></SealInput.Input>
</Form.Item>
</>
);
};
const renderOllamaModelFields = () => {
return (
<>
@ -350,24 +244,20 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
};
const renderFieldsBySource = useMemo(() => {
if (SEARCH_SOURCE.includes(props.data?.source || '')) {
if (SEARCH_SOURCE.includes(formData?.source || '')) {
return renderHuggingfaceFields();
}
if (props.data?.source === modelSourceMap.ollama_library_value) {
if (formData?.source === modelSourceMap.ollama_library_value) {
return renderOllamaModelFields();
}
if (props.data?.source === modelSourceMap.s3_value) {
return renderS3Fields();
}
if (props.data?.source === modelSourceMap.local_path_value) {
if (formData?.source === modelSourceMap.local_path_value) {
return renderLocalPathFields();
}
return null;
}, [props.data?.source, isGGUF, intl]);
}, [formData?.source, isGGUF, intl]);
const handleSumit = () => {
form.submit();
@ -443,8 +333,10 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
};
useEffect(() => {
getGPUList();
}, []);
if (open && formData) {
form.setFieldsValue(formData);
}
}, [open, formData]);
return (
<Modal
@ -488,6 +380,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
form={form}
onFinish={handleOk}
preserve={false}
initialValues={formData}
style={{
padding: 'var(--ant-modal-content-padding)',
paddingBlock: 0
@ -550,7 +443,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
label: `llama-box`,
value: backendOptionsMap.llamaBox,
disabled:
props.data?.source === modelSourceMap.local_path_value
formData?.source === modelSourceMap.local_path_value
? false
: !isGGUF
},
@ -558,7 +451,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
label: 'vLLM',
value: backendOptionsMap.vllm,
disabled:
props.data?.source === modelSourceMap.local_path_value
formData?.source === modelSourceMap.local_path_value
? false
: isGGUF
},
@ -566,13 +459,13 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
label: 'vox-box',
value: backendOptionsMap.voxBox,
disabled:
props.data?.source ===
modelSourceMap.ollama_library_value || isGGUF
formData?.source === modelSourceMap.ollama_library_value ||
isGGUF
}
]}
disabled={
action === PageAction.EDIT &&
props.data?.source !== modelSourceMap.local_path_value
formData?.source !== modelSourceMap.local_path_value
}
></SealSelect>
</Form.Item>
@ -616,8 +509,8 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
form={form}
gpuOptions={gpuOptions}
action={PageAction.EDIT}
source={props.data?.source || ''}
isGGUF={props.data?.backend === backendOptionsMap.llamaBox}
source={formData?.source || ''}
isGGUF={formData?.backend === backendOptionsMap.llamaBox}
></AdvanceConfig>
</Form>
</SimpleBar>
@ -625,4 +518,4 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
);
};
export default memo(UpdateModal);
export default UpdateModal;

@ -0,0 +1,80 @@
import _ from 'lodash';
import { useRef } from 'react';
import { queryGPUList } from '../apis';
import { backendOptionsMap, setSourceRepoConfigValue } from '../config';
import { GPUListItem, ListItem } from '../config/types';
export const useGenerateFormEditInitialValues = () => {
const gpuDeviceList = useRef<any[]>([]);
const generateCascaderOptions = (list: GPUListItem[]) => {
const workerFields = ['worker_name', 'worker_id', 'worker_ip'];
const workers = _.groupBy(list, 'worker_name');
const workerList = _.map(workers, (value: GPUListItem[]) => {
return {
label: `${value[0].worker_name}`,
value: value[0].worker_name,
parent: true,
..._.pick(value[0], workerFields),
children: _.map(value, (item: GPUListItem) => {
return {
label: `${item.name}`,
value: item.id,
..._.omit(item, workerFields)
};
})
};
});
return workerList;
};
const getGPUList = async () => {
const data = await queryGPUList();
const gpuList = generateCascaderOptions(data.items);
gpuDeviceList.current = gpuList;
return gpuList;
};
const generateGPUSelector = (data: any, gpuOptions: any[]) => {
const gpu_ids = _.get(data, 'gpu_selector.gpu_ids', []);
if (gpu_ids.length === 0) {
return [];
}
const gpuids: string[][] = [];
gpuOptions?.forEach((item) => {
item.children?.forEach((child: any) => {
if (gpu_ids.includes(child.value)) {
gpuids.push([item.value, child.value]);
}
});
});
return data.backend === backendOptionsMap.voxBox ? gpuids[0] : gpuids;
};
const generateFormValues = (data: ListItem, gpuOptions: any[]) => {
const result = setSourceRepoConfigValue(data?.source || '', data);
const formData = {
...result.values,
..._.omit(data, result.omits),
categories: data?.categories?.length ? data.categories[0] : null,
scheduleType: data?.gpu_selector ? 'manual' : 'auto',
gpu_selector: data?.gpu_selector?.gpu_ids?.length
? {
gpu_ids: generateGPUSelector(data, gpuOptions)
}
: null
};
return formData;
};
return {
getGPUList,
generateFormValues,
gpuDeviceList
};
};

@ -259,6 +259,10 @@ const Models: React.FC = () => {
search: 'DeepSeek R1',
page: 1
});
if (!res?.items?.length) {
setCatalogList([]);
return;
}
const name = _.toLower(res?.items[0]?.name).replace(/\s/g, '-') || '';
const catalogSpecs: any = await queryCatalogItemSpec({
id: res?.items[0]?.id

@ -394,8 +394,8 @@ const GroundEmbedding: React.FC<MessageProps> = forwardRef((props, ref) => {
</Form.Item>
);
}
return null;
}, modelMeta);
return [];
}, [modelMeta]);
const outputItems = useMemo(() => {
return [

@ -406,7 +406,7 @@ const GroundReranker: React.FC<MessageProps> = forwardRef((props, ref) => {
);
}
return null;
}, modelMeta);
}, [modelMeta]);
const handleClearDocuments = () => {
setTextList([

@ -99,7 +99,7 @@ const PlaygroundEmbedding: React.FC = () => {
header={{
title: intl.formatMessage({ id: 'menu.playground.embedding' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}

@ -169,7 +169,7 @@ const TextToImages: React.FC = () => {
</div>
),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}

@ -166,7 +166,7 @@ const Playground: React.FC = () => {
</div>
),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}

@ -103,7 +103,7 @@ const PlaygroundRerank: React.FC = () => {
header={{
title: intl.formatMessage({ id: 'menu.playground.rerank' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}

@ -212,7 +212,7 @@ const Playground: React.FC = () => {
</div>
),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
},
breadcrumb: {}
}}

@ -39,7 +39,7 @@ const Profile: React.FC = () => {
header={{
title: intl.formatMessage({ id: 'users.form.updatepassword' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
}
}}
extra={[]}

@ -2,9 +2,16 @@ import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import type { TabsProps } from 'antd';
import { useCallback, useState } from 'react';
import styled from 'styled-components';
import GPUs from './components/gpus';
import Workers from './components/workers';
const Wrapper = styled.div`
.ant-page-header-heading {
padding-inline: 8px;
}
`;
const items: TabsProps['items'] = [
{
key: 'workers',
@ -27,7 +34,7 @@ const Resources = () => {
}, []);
return (
<>
<Wrapper>
<PageContainer
ghost
header={{
@ -47,7 +54,7 @@ const Resources = () => {
}}
extra={[]}
></PageContainer>
</>
</Wrapper>
);
};

@ -13,7 +13,7 @@ const Dashboard: React.FC = () => {
extra={[]}
header={{
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
}
}}
>

@ -244,7 +244,7 @@ const Users: React.FC = () => {
header={{
title: intl.formatMessage({ id: 'users.title' }),
style: {
paddingInline: 'var(--layout-content-inlinepadding)'
paddingInline: 'var(--layout-content-header-inlinepadding)'
}
}}
extra={[]}

Loading…
Cancel
Save