fix: display image menu

This commit is contained in:
jialin
2025-11-10 10:07:25 +08:00
parent 0077d109e7
commit 285e274818
25 changed files with 91 additions and 86 deletions
@@ -16,6 +16,9 @@ const DropDownActions: React.FC<DropDownProps> = (props) => {
const items = useMemo(() => {
return menu?.items?.map((item: any) => ({
..._.omit(item, 'locale'),
icon: item.icon
? React.cloneElement(item.icon, { style: { fontSize: 14 } })
: null,
label: item.locale ? intl.formatMessage({ id: item.label }) : item.label
}));
}, [menu?.items, intl]);
+5 -7
View File
@@ -86,8 +86,8 @@ export const FilterBar: React.FC<FilterBarProps> = (props) => {
handleInputChange,
handleSelectChange,
handleSearch,
handleDeleteByBatch,
handleClickPrimary,
handleDeleteByBatch = null,
handleClickPrimary = null,
rowSelection,
actionItems = [],
selectOptions,
@@ -99,8 +99,6 @@ export const FilterBar: React.FC<FilterBarProps> = (props) => {
marginTop = 10,
inputHolder,
selectHolder,
showPrimaryButton = true,
showDeleteButton = true,
right,
left,
width
@@ -108,12 +106,12 @@ export const FilterBar: React.FC<FilterBarProps> = (props) => {
const intl = useIntl();
const renderRight = useMemo(() => {
if (!showPrimaryButton && !showDeleteButton) {
if (!handleClickPrimary && !handleDeleteByBatch) {
return null;
}
return (
<Space size={20}>
{showPrimaryButton ? (
{handleClickPrimary ? (
actionType === 'dropdown' ? (
<DropDownActions
menu={{
@@ -139,7 +137,7 @@ export const FilterBar: React.FC<FilterBarProps> = (props) => {
</Button>
)
) : null}
{showDeleteButton && (
{handleDeleteByBatch && (
<Button
icon={<DeleteOutlined />}
danger
+1
View File
@@ -49,6 +49,7 @@ const NO_CONTAINER_PAGES = [
'embedding',
'speech',
'image',
'text2images',
'clusterDetail',
'clusterCreate'
];
+3 -1
View File
@@ -240,5 +240,7 @@ export default {
'models.form.quantization': 'Quantization',
'models.form.backend.custom': 'User-defined',
'models.form.rules.name':
'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.'
'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.',
'models.catalog.button.explore': 'Explore Other Models',
'models.catalog.precision': 'Precision'
};
+6 -2
View File
@@ -240,7 +240,9 @@ export default {
'models.form.quantization': 'Quantization',
'models.form.backend.custom': 'User Defined',
'models.form.rules.name':
'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.'
'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.',
'models.catalog.button.explore': 'Explore Other Models',
'models.catalog.precision': 'Precision'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -309,5 +311,7 @@ export default {
// 46. 'models.form.draftModel.tips': 'You can enter a local path (e.g., /path/to/model) or select a model from Hugging Face or ModelScope (e.g., Tengyunw/qwen3_8b_eagle3). The system will automatically match based on the primary model source.'
// 47. 'models.form.quantization': 'Quantization',
// 48. 'models.form.backend.custom': 'User Defined',
// 49. 'models.form.rules.name': 'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.'
// 49. 'models.form.rules.name': 'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.',
// 50. 'models.catalog.button.explore': 'Explore Other Models',
// 51. 'models.catalog.precision': 'Precision'
// ========== End of To-Do List ==========
+3 -1
View File
@@ -241,7 +241,9 @@ export default {
'models.form.quantization': 'Квантование',
'models.form.backend.custom': 'Пользовательский',
'models.form.rules.name':
'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.'
'Up to 63 characters; letters, numbers, dots (.), underscores (_), and hyphens (-) only; must start and end with an alphanumeric character.',
'models.catalog.button.explore': 'Изучить другие модели',
'models.catalog.precision': 'Точность'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
+3 -1
View File
@@ -227,5 +227,7 @@ export default {
'models.form.quantization': '量化',
'models.form.backend.custom': '用户定义',
'models.form.rules.name':
'长度不超过 63 个字符,只能包含字母、数字、点(.)、下划线(_)和连字符(-),且必须以字母或数字开头和结尾。'
'长度不超过 63 个字符,只能包含字母、数字、点(.)、下划线(_)和连字符(-),且必须以字母或数字开头和结尾。',
'models.catalog.button.explore': '浏览其他模型',
'models.catalog.precision': '精度'
};
-2
View File
@@ -172,7 +172,6 @@ const BackendList = () => {
return (
<PageBox>
<FilterBar
showDeleteButton={false}
marginBottom={22}
marginTop={30}
width={{
@@ -180,7 +179,6 @@ const BackendList = () => {
}}
inputHolder={intl.formatMessage({ id: 'common.filter.name' })}
buttonText={intl.formatMessage({ id: 'backend.button.add' })}
handleDeleteByBatch={handleDeleteBatch}
handleClickPrimary={handleAddBackend}
handleSearch={handleSearch}
handleInputChange={handleNameChange}
@@ -329,8 +329,6 @@ const Clusters: React.FC = () => {
<PageBox>
<FilterBar
showSelect={false}
showPrimaryButton={true}
showDeleteButton={true}
marginBottom={22}
marginTop={30}
width={{ input: 300 }}
@@ -136,8 +136,6 @@ const WorkerPools = () => {
</SubTitle>
<FilterBar
showSelect={false}
showPrimaryButton={true}
showDeleteButton={true}
marginBottom={22}
marginTop={22}
width={{ input: 300 }}
@@ -183,7 +183,6 @@ const Credentials: React.FC = () => {
actionItems={addActions}
actionType="dropdown"
showSelect={false}
showPrimaryButton={true}
marginBottom={22}
marginTop={0}
buttonText={intl.formatMessage({
+23 -53
View File
@@ -1,19 +1,17 @@
import { modelsExpandKeysAtom } from '@/atoms/models';
import IconFont from '@/components/icon-font';
import PageTools from '@/components/page-tools';
import BaseSelect from '@/components/seal-form/base/select';
import { FilterBar } from '@/components/page-tools';
import { PageAction } from '@/config';
import useBodyScroll from '@/hooks/use-body-scroll';
import { ScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context';
import { IS_FIRST_LOGIN, writeState } from '@/utils/localstore/index';
import { SearchOutlined, SyncOutlined } from '@ant-design/icons';
import { SearchOutlined } from '@ant-design/icons';
import { useIntl, useNavigate } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { Button, Input, Space, message } from 'antd';
import { message } from 'antd';
import { useAtom } from 'jotai';
import _ from 'lodash';
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import NoResult from '../_components/no-result';
import PageBox from '../_components/page-box';
import { createModel, queryCatalogList } from './apis';
@@ -22,11 +20,6 @@ import DelopyBuiltInModal from './components/deploy-builtin-modal';
import { modelCategories, modelSourceMap } from './config';
import { CatalogItem as CatalogItemType, FormData } from './config/types';
const PageWrapper = styled.div`
display: none;
margin-block: 32px 16px;
`;
const Catalog: React.FC = () => {
const intl = useIntl();
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
@@ -59,7 +52,9 @@ const Catalog: React.FC = () => {
const [modelsExpandKeys, setModelsExpandKeys] = useAtom(modelsExpandKeysAtom);
const cacheData = React.useRef<CatalogItemType[]>([]);
const categoryOptions = [...modelCategories.filter((item) => item.value)];
const categoryOptions = [
...modelCategories.filter((item) => item.value)
] as Global.BaseOption<string>[];
const fetchData = useCallback(
async (query?: any) => {
@@ -159,7 +154,7 @@ const Catalog: React.FC = () => {
[openDeployModal]
);
const handleSearch = (e: any) => {
const handleSearch = () => {
fetchData({
...queryParams,
page: 1
@@ -189,6 +184,10 @@ const Catalog: React.FC = () => {
});
});
const handleDeployFromOtherHubs = () => {
navigate('/models/deployments');
};
useEffect(() => {
fetchData();
}, []);
@@ -220,49 +219,20 @@ const Catalog: React.FC = () => {
return (
<PageBox>
<PageTools
<FilterBar
showSelect={true}
selectHolder={intl.formatMessage({ id: 'models.filter.category' })}
marginBottom={22}
marginTop={0}
left={
<Space>
<Input
prefix={
<SearchOutlined
style={{ color: 'var(--ant-color-text-placeholder)' }}
></SearchOutlined>
}
placeholder={intl.formatMessage({ id: 'common.filter.name' })}
style={{ width: 230 }}
size="large"
allowClear
onClear={() =>
handleNameChange({
target: {
value: ''
}
})
}
onChange={handleNameChange}
></Input>
<BaseSelect
allowClear
showSearch={false}
placeholder={intl.formatMessage({ id: 'models.filter.category' })}
style={{ width: 200 }}
size="large"
maxTagCount={1}
onChange={handleCategoryChange}
options={categoryOptions}
></BaseSelect>
<Button
type="text"
style={{ color: 'var(--ant-color-text-tertiary)' }}
icon={<SyncOutlined></SyncOutlined>}
onClick={handleSearch}
></Button>
</Space>
}
></PageTools>
buttonText={intl.formatMessage({ id: 'models.catalog.button.explore' })}
handleSearch={handleSearch}
handleSelectChange={handleCategoryChange}
handleClickPrimary={handleDeployFromOtherHubs}
handleInputChange={handleNameChange}
selectOptions={categoryOptions}
buttonIcon={<SearchOutlined />}
width={{ input: 230, select: 200 }}
></FilterBar>
<ScrollerContext.Provider
value={{
total: dataSource.totalPage,
@@ -652,7 +652,6 @@ const Models: React.FC<ModelsProps> = ({
items: sourceOptions,
onClick: handleClickDropdown
}}
trigger={['hover']}
placement="bottomRight"
>
<Button
+1
View File
@@ -335,6 +335,7 @@ export const DO_NOT_TRIGGER_CHECK_COMPATIBILITY = [
'description',
'env',
'source',
'cluster_id',
'quantization',
'size',
'restart_on_error',
+3 -3
View File
@@ -38,13 +38,13 @@ const CatalogForm: React.FC = () => {
key="quantization"
rules={[
{
required: true,
message: getRuleMessage('select', 'models.form.quantization', false)
required: false,
message: getRuleMessage('select', 'models.catalog.precision', false)
}
]}
>
<SealInput.Input
label={intl.formatMessage({ id: 'models.form.quantization' })}
label={intl.formatMessage({ id: 'models.catalog.precision' })}
disabled
></SealInput.Input>
</Form.Item>
+11 -1
View File
@@ -238,12 +238,16 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
onOk(allValues);
};
const handleClusterChange = (value: number) => {
const handleClusterChange = async (value: number) => {
getGPUOptionList({ clusterId: value });
getBackendOptions({ cluster_id: value });
if (scheduleType === ScheduleValueMap.Manual) {
form.setFieldValue(['gpu_selector', 'gpu_ids'], []);
}
await new Promise((resolve) => {
setTimeout(resolve, 150);
});
onValuesChange?.({}, form.getFieldsValue());
};
const getFieldPaths = (obj: Record<string, any>, prefix = ''): string => {
@@ -259,6 +263,12 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
return result[0] || '';
};
/**
* auto check compatibility or notify recreate when certain fields change
* @param changedValues
* @param allValues
* @returns
*/
const handleOnValuesChange = async (changedValues: any, allValues: any) => {
const fieldName = getFieldPaths(changedValues);
+12 -1
View File
@@ -1,3 +1,13 @@
export const VLLMMetaKeys: Record<string, any> = {};
export const SGLangMetaKeys: Record<string, any> = {};
/**
* LLM Meta Keys
* @description Keys used for configuring large language models (LLMs)
* These keys are from model metadata
* These values are set to the from, use uniform keys for easier management
*/
export const LLM_METAKEYS: Record<string, any> = {
seed: 'seed',
stop: 'stop',
@@ -8,7 +18,8 @@ export const LLM_METAKEYS: Record<string, any> = {
max_model_len: 'max_model_len',
frequency_penalty: 'frequency_penalty',
presence_penalty: 'presence_penalty',
max_total_tokens: 'max_total_tokens'
max_total_tokens: 'max_total_tokens',
max_stop_sequences: 'stop'
};
export const precisionTwoKeys = [
@@ -76,6 +76,8 @@ export const useInitLLmMeta = (
return model;
}, [model, modelList, isChat]);
const getLLamaBoxMeta = (meta: any) => {};
const getMaxTokens = (meta: any) => {
const { max_model_len, n_ctx, n_slot, max_total_tokens } = meta || {};
+2 -1
View File
@@ -138,13 +138,14 @@ const TextToImages: React.FC = () => {
options={optionsList}
size="middle"
className="m-l-40 font-600"
value={activeKey}
onChange={(key) => setActiveKey(key)}
></Segmented>
}
</div>
)
};
}, [optionsList]);
}, [activeKey, optionsList, intl]);
useHotkeys(
HotKeys.RIGHT.join(','),
+2 -1
View File
@@ -130,13 +130,14 @@ const Playground: React.FC = () => {
options={optionsList}
size="middle"
className="m-l-40 font-600"
value={activeKey}
onChange={(key) => setActiveKey(key)}
></Segmented>
}
</div>
)
};
}, [optionsList]);
}, [activeKey, optionsList, intl]);
useHotkeys(
HotKeys.RIGHT.join(','),
+1 -1
View File
@@ -182,7 +182,7 @@ const Playground: React.FC = () => {
</div>
)
};
}, [activeKey, optionsList]);
}, [activeKey, optionsList, intl]);
useHotkeys(
HotKeys.RIGHT.join(','),
-2
View File
@@ -92,8 +92,6 @@ const GPUList: React.FC = () => {
handleSearch={handleSearch}
handleInputChange={handleNameChange}
handleSelectChange={handleClusterChange}
showDeleteButton={false}
showPrimaryButton={false}
selectOptions={clusterList}
showSelect
width={{ input: 200 }}
@@ -92,8 +92,6 @@ const WorkerDetailContent: React.FC<{ worker_id: number | undefined }> = ({
handleSearch={handleSearch}
handleSelectChange={handleSelectChange}
handleInputChange={handleNameChange}
showDeleteButton={false}
showPrimaryButton={false}
selectHolder={intl.formatMessage({ id: 'resources.filter.status' })}
showSelect={true}
selectOptions={statusList}
@@ -229,7 +229,6 @@ const Workers: React.FC = () => {
<PageBox>
<FilterBar
showSelect={true}
showPrimaryButton={false}
selectHolder={intl.formatMessage({ id: 'clusters.filterBy.cluster' })}
marginBottom={22}
marginTop={30}