fix: flatten all filters in table list

This commit is contained in:
jialin
2026-06-10 15:37:27 +08:00
committed by jialin
parent ded270ff25
commit 98a6b19298
11 changed files with 108 additions and 109 deletions
+3 -3
View File
@@ -37,10 +37,10 @@ export default {
'Stress test for long-context handling. Evaluates KV cache behavior, memory usage, and backend stability.', 'Stress test for long-context handling. Evaluates KV cache behavior, memory usage, and backend stability.',
'benchmark.form.profile.heavy.tips': 'benchmark.form.profile.heavy.tips':
'Decode-heavy generation benchmark. Measures sustained decoding speed and output token throughput.', 'Decode-heavy generation benchmark. Measures sustained decoding speed and output token throughput.',
'benchmark.table.filter.bygpu': 'Filter by GPU', 'benchmark.table.filter.bygpu': 'Search by GPU',
'benchmark.table.filter.bymodel': 'Filter by Model', 'benchmark.table.filter.bymodel': 'Search by model',
'benchmark.table.filter.bydataset': 'Filter by Dataset', 'benchmark.table.filter.bydataset': 'Filter by Dataset',
'benchmark.table.filter.byProfile': 'Filter by Profile', 'benchmark.table.filter.byProfile': 'Filter by profile',
'benchmark.table.avg': 'Avg', 'benchmark.table.avg': 'Avg',
'benchmark.table.columnSettings': 'Column Settings', 'benchmark.table.columnSettings': 'Column Settings',
'benchmark.detail.summary.results': 'Test Results', 'benchmark.detail.summary.results': 'Test Results',
+2 -2
View File
@@ -37,8 +37,8 @@ export default {
'Stress test for long-context handling. Evaluates KV cache behavior, memory usage, and backend stability.', 'Stress test for long-context handling. Evaluates KV cache behavior, memory usage, and backend stability.',
'benchmark.form.profile.heavy.tips': 'benchmark.form.profile.heavy.tips':
'Decode-heavy generation benchmark. Measures sustained decoding speed and output token throughput.', 'Decode-heavy generation benchmark. Measures sustained decoding speed and output token throughput.',
'benchmark.table.filter.bygpu': 'Filter by GPU', 'benchmark.table.filter.bygpu': 'GPU 検索',
'benchmark.table.filter.bymodel': 'Filter by Model', 'benchmark.table.filter.bymodel': 'モデル検索',
'benchmark.table.filter.bydataset': 'Filter by Dataset', 'benchmark.table.filter.bydataset': 'Filter by Dataset',
'benchmark.table.filter.byProfile': 'Filter by Profile', 'benchmark.table.filter.byProfile': 'Filter by Profile',
'benchmark.table.avg': 'Avg', 'benchmark.table.avg': 'Avg',
+2 -2
View File
@@ -37,8 +37,8 @@ export default {
'Stress test for long-context handling. Evaluates KV cache behavior, memory usage, and backend stability.', 'Stress test for long-context handling. Evaluates KV cache behavior, memory usage, and backend stability.',
'benchmark.form.profile.heavy.tips': 'benchmark.form.profile.heavy.tips':
'Decode-heavy generation benchmark. Measures sustained decoding speed and output token throughput.', 'Decode-heavy generation benchmark. Measures sustained decoding speed and output token throughput.',
'benchmark.table.filter.bygpu': 'Filter by GPU', 'benchmark.table.filter.bygpu': 'Поиск GPU',
'benchmark.table.filter.bymodel': 'Filter by Model', 'benchmark.table.filter.bymodel': 'Поиск модели',
'benchmark.table.filter.bydataset': 'Filter by Dataset', 'benchmark.table.filter.bydataset': 'Filter by Dataset',
'benchmark.table.filter.byProfile': 'Filter by Profile', 'benchmark.table.filter.byProfile': 'Filter by Profile',
'benchmark.table.avg': 'Avg', 'benchmark.table.avg': 'Avg',
+2 -2
View File
@@ -37,8 +37,8 @@ export default {
'Uzun bağlam işleme için stres testi. KV önbellek davranışını, bellek kullanımını ve altyapı kararlılığını değerlendirir.', 'Uzun bağlam işleme için stres testi. KV önbellek davranışını, bellek kullanımını ve altyapı kararlılığını değerlendirir.',
'benchmark.form.profile.heavy.tips': 'benchmark.form.profile.heavy.tips':
'Çözümleme ağırlıklı üretim kıyaslaması. Sürekli çözümleme hızını ve çıkış token verimini ölçer.', 'Çözümleme ağırlıklı üretim kıyaslaması. Sürekli çözümleme hızını ve çıkış token verimini ölçer.',
'benchmark.table.filter.bygpu': "GPU'ya göre filtrele", 'benchmark.table.filter.bygpu': 'GPU ara',
'benchmark.table.filter.bymodel': 'Modele göre filtrele', 'benchmark.table.filter.bymodel': 'Model ara',
'benchmark.table.filter.bydataset': 'Veri Kümesine göre filtrele', 'benchmark.table.filter.bydataset': 'Veri Kümesine göre filtrele',
'benchmark.table.filter.byProfile': 'Profile göre filtrele', 'benchmark.table.filter.byProfile': 'Profile göre filtrele',
'benchmark.table.avg': 'Ort.', 'benchmark.table.avg': 'Ort.',
+2 -2
View File
@@ -37,8 +37,8 @@ export default {
'长上下文压力测试。评估 KV Cache 行为、内存占用及后端稳定性。', '长上下文压力测试。评估 KV Cache 行为、内存占用及后端稳定性。',
'benchmark.form.profile.heavy.tips': 'benchmark.form.profile.heavy.tips':
'以解码为主的生成测试。衡量持续解码速度与输出 Token 吞吐能力。', '以解码为主的生成测试。衡量持续解码速度与输出 Token 吞吐能力。',
'benchmark.table.filter.bygpu': 'GPU 过滤', 'benchmark.table.filter.bygpu': 'GPU 查询',
'benchmark.table.filter.bymodel': '模型过滤', 'benchmark.table.filter.bymodel': '模型查询',
'benchmark.table.filter.bydataset': '按数据集过滤', 'benchmark.table.filter.bydataset': '按数据集过滤',
'benchmark.table.filter.byProfile': '按模式过滤', 'benchmark.table.filter.byProfile': '按模式过滤',
'benchmark.table.avg': '均值', 'benchmark.table.avg': '均值',
+1 -1
View File
@@ -261,7 +261,7 @@ export default {
'common.button.terminal': '终端', 'common.button.terminal': '终端',
'common.button.addItem': '添加项', 'common.button.addItem': '添加项',
'common.help.default': '默认: {content}', 'common.help.default': '默认: {content}',
'common.filter.status': '按状态筛选', 'common.filter.status': '按状态过滤',
'common.form.rule.selectInput': '请选择或输入{name}', 'common.form.rule.selectInput': '请选择或输入{name}',
'common.tag.experimental': '实验性', 'common.tag.experimental': '实验性',
'common.title.example': '示例', 'common.title.example': '示例',
+1 -1
View File
@@ -99,7 +99,7 @@ export default {
'models.form.search.gguftips': 'models.form.search.gguftips':
'当 macOS 或 Windows 作节点时勾选 GGUF(搜索语音模型时取消勾选)', '当 macOS 或 Windows 作节点时勾选 GGUF(搜索语音模型时取消勾选)',
'models.form.button.addlabel': '添加标签', 'models.form.button.addlabel': '添加标签',
'models.filter.category': '按类别筛选', 'models.filter.category': '按类别过滤',
'models.list.more.logs': '查看更多', 'models.list.more.logs': '查看更多',
'models.catalog.release.date': '发布日期', 'models.catalog.release.date': '发布日期',
'models.localpath.gguf.tips.title': 'GGUF 格式模型', 'models.localpath.gguf.tips.title': 'GGUF 格式模型',
+23 -31
View File
@@ -1,10 +1,10 @@
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { SearchOutlined, SyncOutlined } from '@ant-design/icons'; import { SearchOutlined, SyncOutlined } from '@ant-design/icons';
import { FiltersButton } from '@gpustack/core-ui'; import { BaseSelect } from '@gpustack/core-ui';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Input, Space } from 'antd'; import { Button, Input, Space } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import React from 'react'; import React from 'react';
import { profileOptions } from '../config';
export interface RightActionsProps { export interface RightActionsProps {
handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void; handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
@@ -38,22 +38,15 @@ const RightActions: React.FC<RightActionsProps> = ({
const handleGPUChange = debounceUpdateFilter; const handleGPUChange = debounceUpdateFilter;
const modelOptions = modelList const handleSearchByModelDebounce = _.debounce((value: any) => {
?.filter((item) => { handleQueryChange({
return item.categories?.includes(modelCategoriesMap.llm); page: 1,
}) model_name: value
.map((item) => ({ });
label: item.label, }, 350);
value: item.label
}));
return ( return (
<Space> <Space>
<FiltersButton
onClick={toggleFilters}
count={count}
onClear={onClear}
></FiltersButton>
<Input <Input
prefix={ prefix={
<SearchOutlined <SearchOutlined
@@ -63,11 +56,24 @@ const RightActions: React.FC<RightActionsProps> = ({
placeholder={intl.formatMessage({ placeholder={intl.formatMessage({
id: 'common.filter.name' id: 'common.filter.name'
})} })}
style={{ width: 300 }} style={{ width: 200 }}
allowClear allowClear
onChange={handleInputChange} onChange={handleInputChange}
></Input> ></Input>
{/* <Input <Input
prefix={
<SearchOutlined
style={{ color: 'var(--ant-color-text-placeholder)' }}
></SearchOutlined>
}
placeholder={intl.formatMessage({
id: 'benchmark.table.filter.bymodel'
})}
style={{ width: 180 }}
allowClear
onChange={handleSearchByModelDebounce}
></Input>
<Input
prefix={ prefix={
<SearchOutlined <SearchOutlined
style={{ color: 'var(--ant-color-text-placeholder)' }} style={{ color: 'var(--ant-color-text-placeholder)' }}
@@ -104,20 +110,6 @@ const RightActions: React.FC<RightActionsProps> = ({
}) })
} }
></BaseSelect> ></BaseSelect>
<BaseSelect
allowClear
placeholder={intl.formatMessage({
id: 'benchmark.table.filter.bymodel'
})}
style={{ width: 180 }}
options={modelOptions}
onChange={(value, option) =>
handleQueryChange({
model_name: value,
page: 1
})
}
></BaseSelect> */}
<Button <Button
type="text" type="text"
style={{ color: 'var(--ant-color-text-tertiary)' }} style={{ color: 'var(--ant-color-text-tertiary)' }}
+5 -28
View File
@@ -22,7 +22,7 @@ import {
TableOrder TableOrder
} from '@gpustack/core-ui'; } from '@gpustack/core-ui';
import { useIntl, useNavigate, useSearchParams } from '@umijs/max'; import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
import { useMemoizedFn, useToggle } from 'ahooks'; import { useMemoizedFn } from 'ahooks';
import { Button, Space, message } from 'antd'; import { Button, Space, message } from 'antd';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import _ from 'lodash'; import _ from 'lodash';
@@ -54,14 +54,13 @@ import {
ModelInstanceListItem, ModelInstanceListItem,
SourceType SourceType
} from '../config/types'; } from '../config/types';
import Filters from '../filters';
import useEditDeployment from '../hooks/use-edit-deployment'; import useEditDeployment from '../hooks/use-edit-deployment';
import useModelsColumns from '../hooks/use-models-columns'; import useModelsColumns from '../hooks/use-models-columns';
import useViewInstanceLogs from '../hooks/use-view-instance-logs'; import useViewInstanceLogs from '../hooks/use-view-instance-logs';
import LeftFilters from '../instance-view/left-filters';
import DeployModal from './deployment/deploy-modal'; import DeployModal from './deployment/deploy-modal';
import UpdateModelModal from './deployment/update-modal'; import UpdateModelModal from './deployment/update-modal';
import Instances from './instance/instances'; import Instances from './instance/instances';
import LeftFilters from './left-filters';
import ViewLogsModal from './view-logs-modal'; import ViewLogsModal from './view-logs-modal';
interface ModelsProps { interface ModelsProps {
handleSearch: (params?: any) => void; handleSearch: (params?: any) => void;
@@ -124,15 +123,13 @@ const Models: React.FC<ModelsProps> = ({
onTableSort, onTableSort,
onStatusChange, onStatusChange,
onDeleteInstanceFromCache, onDeleteInstanceFromCache,
onFilterChange,
sortOrder, sortOrder,
deleteIds, deleteIds,
dataSource, dataSource,
queryParams, queryParams,
loading, loading,
loadend, loadend,
total, total
filterValues = {}
}) => { }) => {
const { generateFormValues, clusterList, workerList } = const { generateFormValues, clusterList, workerList } =
useDeploymentsContext(); useDeploymentsContext();
@@ -180,8 +177,6 @@ const Models: React.FC<ModelsProps> = ({
source: modelSourceMap.huggingface_value as SourceType source: modelSourceMap.huggingface_value as SourceType
}); });
const modalRef = useRef<any>(null); const modalRef = useRef<any>(null);
const [filtersVisible, { toggle: toggleFilters }] = useToggle();
const filterRef = useRef<any>(null);
useEffect(() => { useEffect(() => {
if (deleteIds?.length) { if (deleteIds?.length) {
@@ -550,14 +545,6 @@ const Models: React.FC<ModelsProps> = ({
} }
}); });
const handleOnClearFilters = () => {
filterRef.current?.reset();
};
const filtersCount = Object.values(filterValues).filter(
(value) => value !== undefined && value !== null && value !== ''
);
useEffect(() => { useEffect(() => {
if (modelsSession.source && loadend) { if (modelsSession.source && loadend) {
handleClickDropdown({ handleClickDropdown({
@@ -576,29 +563,19 @@ const Models: React.FC<ModelsProps> = ({
alignItems: 'flex-start' alignItems: 'flex-start'
}} }}
> >
<Filters
ref={filterRef}
open={filtersVisible}
onValuesChange={onFilterChange}
clusterList={clusterList}
onClose={toggleFilters}
onClear={handleOnClearFilters}
></Filters>
<div style={{ flex: 1, padding: '24px' }}> <div style={{ flex: 1, padding: '24px' }}>
<PageTools <PageTools
marginBottom={22} marginBottom={22}
marginTop={0} marginTop={0}
left={ left={
<LeftFilters <LeftFilters
count={filtersCount.length} showCategory
toggleFilters={toggleFilters} showWorker={false}
onClear={handleOnClearFilters}
handleNameChange={handleNameChange} handleNameChange={handleNameChange}
handleClusterChange={handleClusterChange} handleClusterChange={handleClusterChange}
handleCategoryChange={handleCategoryChange} handleCategoryChange={handleCategoryChange}
handleStatusChange={onStatusChange} handleStatusChange={onStatusChange}
handleSearch={handleSearch} handleSearch={handleSearch}
onFilterChange={onFilterChange}
clusterList={clusterList} clusterList={clusterList}
></LeftFilters> ></LeftFilters>
} }
@@ -20,6 +20,21 @@ import useQueryModelList from '../services/use-query-model-list';
import LeftFilters from './left-filters'; import LeftFilters from './left-filters';
import useInstanceColumns from './use-instance-columns'; import useInstanceColumns from './use-instance-columns';
const filterOptions = {
optionList: [
{
label: 'Running',
value: 'running',
color: 'var(--ant-color-success)'
},
{
label: 'Error',
value: 'error',
color: 'var(--ant-color-error)'
}
]
};
const InstanceView = forwardRef((props, ref) => { const InstanceView = forwardRef((props, ref) => {
const { const {
dataSource, dataSource,
@@ -150,6 +165,7 @@ const InstanceView = forwardRef((props, ref) => {
handleSearch={handleSearch} handleSearch={handleSearch}
clusterList={clusterList} clusterList={clusterList}
workerList={workerList} workerList={workerList}
filterOptions={filterOptions}
></LeftFilters> ></LeftFilters>
} }
></FilterBar> ></FilterBar>
@@ -4,15 +4,26 @@ import { BaseSelect } from '@gpustack/core-ui';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Input, Space } from 'antd'; import { Button, Input, Space } from 'antd';
import React from 'react'; import React from 'react';
import { categoryOptions } from '../config';
import useFilterStatus from '../hooks/use-filter-status'; import useFilterStatus from '../hooks/use-filter-status';
interface LeftFiltersProps { interface LeftFiltersProps {
handleNameChange: (e: React.ChangeEvent<HTMLInputElement>) => void; handleNameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
handleClusterChange: (value: number) => void; handleClusterChange: (value: number) => void;
handleStatusChange: (value: string) => void; handleStatusChange: (value: string) => void;
handleWorkerChange: (value: number) => void; handleWorkerChange?: (value: number) => void;
handleCategoryChange?: (value: string) => void;
handleSearch: () => void; handleSearch: () => void;
clusterList: Global.BaseOption<number>[]; clusterList: Global.BaseOption<number>[];
workerList: workerListItem[]; workerList?: workerListItem[];
showWorker?: boolean;
showCategory?: boolean;
filterOptions?: {
optionList: {
label: string;
value: string;
color: string;
}[];
};
} }
const LeftFilters: React.FC<LeftFiltersProps> = (props) => { const LeftFilters: React.FC<LeftFiltersProps> = (props) => {
@@ -21,29 +32,16 @@ const LeftFilters: React.FC<LeftFiltersProps> = (props) => {
handleClusterChange, handleClusterChange,
handleStatusChange, handleStatusChange,
handleWorkerChange, handleWorkerChange,
handleCategoryChange,
handleSearch, handleSearch,
clusterList, clusterList,
workerList workerList = [],
showWorker = true,
showCategory = false,
filterOptions
} = props; } = props;
const { labelRender, optionRender, statusOptions } = useFilterStatus({ const { labelRender, optionRender, statusOptions } =
optionList: [ useFilterStatus(filterOptions);
{
label: 'Running',
value: 'running',
color: 'var(--ant-color-success)'
},
{
label: 'Error',
value: 'error',
color: 'var(--ant-color-error)'
}
// {
// label: 'Provisioning',
// value: 'provisioning',
// color: 'var(--ant-blue-5)'
// }
]
});
const intl = useIntl(); const intl = useIntl();
return ( return (
@@ -72,21 +70,37 @@ const LeftFilters: React.FC<LeftFiltersProps> = (props) => {
onChange={handleClusterChange} onChange={handleClusterChange}
options={clusterList} options={clusterList}
></BaseSelect> ></BaseSelect>
<BaseSelect {showCategory && (
allowClear <BaseSelect
showSearch={false} allowClear
placeholder={intl.formatMessage({ showSearch={false}
id: 'resources.filter.worker' placeholder={intl.formatMessage({
})} id: 'models.filter.category'
style={{ width: 160 }} })}
size="large" style={{ width: 160 }}
maxTagCount={1} size="large"
onChange={handleWorkerChange} maxTagCount={1}
options={workerList.map((worker) => ({ onChange={handleCategoryChange}
label: worker.name, options={categoryOptions}
value: worker.id ></BaseSelect>
}))} )}
></BaseSelect> {showWorker && (
<BaseSelect
allowClear
showSearch={false}
placeholder={intl.formatMessage({
id: 'resources.filter.worker'
})}
style={{ width: 160 }}
size="large"
maxTagCount={1}
onChange={handleWorkerChange}
options={workerList.map((worker) => ({
label: worker.name,
value: worker.id
}))}
></BaseSelect>
)}
<BaseSelect <BaseSelect
allowClear allowClear
showSearch={false} showSearch={false}