diff --git a/src/components/overlay-scroller/index.tsx b/src/components/overlay-scroller/index.tsx
index aa98d84b..e4fbcfc1 100644
--- a/src/components/overlay-scroller/index.tsx
+++ b/src/components/overlay-scroller/index.tsx
@@ -11,7 +11,7 @@ export type { OverlayScrollerOptions };
export const OverlayScroller: React.FC<
OverlayScrollerOptions & {
- maxHeight?: number;
+ maxHeight?: number | string;
style?: React.CSSProperties;
styles?: {
wrapper?: React.CSSProperties;
diff --git a/src/components/page-tools/filters-button.less b/src/components/page-tools/filters-button.less
new file mode 100644
index 00000000..5dcb0fd2
--- /dev/null
+++ b/src/components/page-tools/filters-button.less
@@ -0,0 +1,47 @@
+.wrapper {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ cursor: pointer;
+
+ .count {
+ display: flex;
+ width: 16px;
+ height: 16px;
+ justify-content: center;
+ align-items: center;
+ border-radius: 50%;
+ font-size: 12px;
+ font-weight: 500;
+ background-color: var(--ant-color-bg-text-active);
+ color: var(--ant-color-text-secondary);
+ }
+}
+
+.buttonWrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+
+ .close-btn {
+ border-radius: 50%;
+ color: var(--ant-color-text-quaternary);
+ display: none;
+ font-size: 16px;
+
+ &:hover {
+ color: var(--ant-color-text-tertiary);
+ }
+ }
+
+ &:hover {
+ .count {
+ display: none;
+ }
+
+ .close-btn {
+ display: block;
+ }
+ }
+}
diff --git a/src/components/page-tools/index.tsx b/src/components/page-tools/index.tsx
index 8f08f3dd..eb5a2e4e 100644
--- a/src/components/page-tools/index.tsx
+++ b/src/components/page-tools/index.tsx
@@ -1,5 +1,6 @@
import DropDownActions from '@/components/drop-down-actions';
import {
+ CloseCircleFilled,
DeleteOutlined,
DownOutlined,
PlusOutlined,
@@ -9,7 +10,9 @@ import {
import { useIntl } from '@umijs/max';
import { Button, Input, Space } from 'antd';
import React, { useMemo } from 'react';
+import IconFont from '../icon-font';
import BaseSelect from '../seal-form/base/select';
+import filtersButtonCss from './filters-button.less';
import './index.less';
type PageToolsProps = {
@@ -20,6 +23,49 @@ type PageToolsProps = {
style?: React.CSSProperties;
};
+export const FiltersButton = ({
+ onClick,
+ onClear,
+ count
+}: {
+ onClick: () => void;
+ onClear: () => void;
+ count?: number;
+}) => {
+ const handleClear = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ onClear();
+ };
+ const intl = useIntl();
+
+ return (
+
+
+
+ );
+};
+
const PageTools: React.FC = (props) => {
const {
left,
@@ -77,6 +123,12 @@ interface FilterBarProps {
showDeleteButton?: boolean;
right?: React.ReactNode;
left?: React.ReactNode;
+ filtersButtonProps?: {
+ show: boolean;
+ count: number;
+ onClick: () => void;
+ onClear: () => void;
+ };
widths?: {
input?: number;
select?: number;
@@ -103,13 +155,21 @@ export const FilterBar: React.FC = (props) => {
selectHolder,
right,
left,
- widths
+ widths,
+ filtersButtonProps
} = props;
const intl = useIntl();
const renderLeft = () => {
return (
+ {filtersButtonProps?.show && (
+
+ )}
`
+ width: 100%;
--ant-table-cell-padding-inline: ${(props) =>
props.$token.cellPaddingInline}px;
--ant-table-cell-padding-block: ${(props) => props.$token.cellPaddingBlock}px;
diff --git a/src/locales/en-US/models.ts b/src/locales/en-US/models.ts
index e65499ac..2cffff15 100644
--- a/src/locales/en-US/models.ts
+++ b/src/locales/en-US/models.ts
@@ -281,5 +281,6 @@ export default {
'Not enabled yet. Will be enabled after deployment. ',
'models.table.instance.benchmark': 'Run Benchmark',
'models.table.modelView': 'Model List',
- 'models.table.instanceView': 'Instance List'
+ 'models.table.instanceView': 'Instance List',
+ 'models.table.category': 'Category'
};
diff --git a/src/locales/ja-JP/models.ts b/src/locales/ja-JP/models.ts
index bbc24c0e..d5b58f74 100644
--- a/src/locales/ja-JP/models.ts
+++ b/src/locales/ja-JP/models.ts
@@ -281,7 +281,8 @@ export default {
'Not enabled yet. Will be enabled after deployment. ',
'models.table.instance.benchmark': 'Run Benchmark',
'models.table.modelView': 'Model List',
- 'models.table.instanceView': 'Instance List'
+ 'models.table.instanceView': 'Instance List',
+ 'models.table.category': 'Category'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -383,5 +384,6 @@ export default {
// 77. 'models.form.enableModelRoute': 'Enable Model Route',
// 78. 'models.form.enableModelRoute.tips': 'Enable Model Route',
// 79. 'models.table.modelView': 'Model View',
-// 80. 'models.table.instanceView': 'Instance View'
+// 80. 'models.table.instanceView': 'Instance View',
+// 81. 'models.table.category': 'Category'
// ========== End of To-Do List ==========
diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts
index b3d368ce..bef59099 100644
--- a/src/locales/ru-RU/models.ts
+++ b/src/locales/ru-RU/models.ts
@@ -285,7 +285,8 @@ export default {
'Not enabled yet. Will be enabled after deployment. ',
'models.table.instance.benchmark': 'Run Benchmark',
'models.table.modelView': 'Model List',
- 'models.table.instanceView': 'Instance List'
+ 'models.table.instanceView': 'Instance List',
+ 'models.table.category': 'Category'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -297,5 +298,6 @@ export default {
// 4. 'models.form.backend.vllm': 'Built-in support for NVIDIA, AMD, Ascend, Hygon, Moore Threads, Iluvatar, MetaX, T-Head PPU devices.',
// 5. 'models.form.backend.sglang': 'Built-in support for NVIDIA, AMD, Ascend, Moore Threads, MetaX, T-Head PPU devices.',
// 6. 'models.table.modelView': 'Model List',
-// 7. 'models.table.instanceView': 'Instance List'
+// 7. 'models.table.instanceView': 'Instance List',
+// 8. 'models.table.category': 'Category'
// ========== End of To-Do List ==========
diff --git a/src/locales/tr-TR/models.ts b/src/locales/tr-TR/models.ts
index a98946b3..52e16765 100644
--- a/src/locales/tr-TR/models.ts
+++ b/src/locales/tr-TR/models.ts
@@ -281,10 +281,12 @@ export default {
'Henüz etkinleştirilmedi. Dağıtımdan sonra etkinleştirilecektir. ',
'models.table.instance.benchmark': 'Kıyaslama Çalıştır',
'models.table.modelView': 'Model List',
- 'models.table.instanceView': 'Instance List'
+ 'models.table.instanceView': 'Instance List',
+ 'models.table.category': 'Category'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. 'models.table.modelView': 'Model List',
// 2. 'models.table.instanceView': 'Instance List',
+// 3. 'models.table.category': 'Category'
// ========== End of To-Do List ==========
diff --git a/src/locales/zh-CN/models.ts b/src/locales/zh-CN/models.ts
index 996b2071..9979ee41 100644
--- a/src/locales/zh-CN/models.ts
+++ b/src/locales/zh-CN/models.ts
@@ -265,5 +265,6 @@ export default {
'models.form.backend.helperText': '该社区后端暂未启用,部署后将自动启用',
'models.table.instance.benchmark': '运行基准测试',
'models.table.modelView': '模型列表',
- 'models.table.instanceView': '实例列表'
+ 'models.table.instanceView': '实例列表',
+ 'models.table.category': '类别'
};
diff --git a/src/pages/_components/filter-form.tsx b/src/pages/_components/filter-form.tsx
deleted file mode 100644
index cc7149ca..00000000
--- a/src/pages/_components/filter-form.tsx
+++ /dev/null
@@ -1,238 +0,0 @@
-import IconFont from '@/components/icon-font';
-import OverlayScroller from '@/components/overlay-scroller';
-import { CloseCircleFilled } from '@ant-design/icons';
-import { useIntl } from '@umijs/max';
-import { Button, Divider, Form, Popover } from 'antd';
-import React, { useState } from 'react';
-import styled from 'styled-components';
-
-const Container = styled.div`
- padding: 12px 8px;
- .title {
- font-weight: 500;
- margin-bottom: 12px;
- }
- .btn-wrapper {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding-top: 24px;
- padding-right: 8px;
- }
- .buttons {
- display: flex;
- gap: 8px;
- justify-content: flex-end;
- }
-`;
-
-const Filters = styled.span`
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 0;
- cursor: pointer;
- .count {
- display: flex;
- width: 16px;
- height: 16px;
- justify-content: center;
- align-items: center;
- border-radius: 50%;
- font-size: 12px;
- font-weight: 500;
- background-color: var(--ant-color-bg-text-active);
- color: var(--ant-color-text-secondary);
- }
-`;
-
-const ButtonWrapper = styled.div`
- display: flex;
- align-items: center;
- justify-content: center;
- position: relative;
- .close-btn {
- border-radius: 50%;
- color: var(--ant-color-text-quaternary);
- &:hover {
- color: var(--ant-color-text-tertiary);
- }
- }
- &:hover {
- .close-btn {
- display: block;
- }
- }
-`;
-
-const FilterForm: React.FC<
- React.PropsWithChildren & {
- width?: number;
- contentHeight?: number;
- initialValues?: any;
- hasFilters?: boolean;
- placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';
- onClose?: () => void;
- onValuesChange?: (ChangeValues: any, allValues: any) => void;
- }
-> = ({
- children,
- width = 300,
- contentHeight = 400,
- initialValues = {},
- placement = 'bottomLeft',
- onClose,
- onValuesChange
-}) => {
- const intl = useIntl();
- const [open, setOpen] = useState(false);
- const [hasFilters, setHasFilters] = useState(false);
- const [form] = Form.useForm();
-
- const handleToggle = () => {
- setOpen(!open);
- };
-
- const handleOpenChange = (isOpen: boolean) => {
- setOpen(isOpen);
- };
-
- const handleOnReset = () => {
- form.resetFields(Object.keys(initialValues));
- setOpen(false);
- setHasFilters(false);
- form.resetFields();
- onValuesChange?.({}, form.getFieldsValue());
- };
-
- const handleOnClose = () => {
- setOpen(false);
- onClose?.();
- };
-
- const handleOnValuesChange = (changedValues: any, allValues: any) => {
- onValuesChange?.(changedValues, allValues);
- const hasActiveFilters = Object.values(allValues).some(
- (value) => value !== undefined && value !== null && value !== ''
- );
- setHasFilters(hasActiveFilters);
- };
-
- const handleOnClear = () => {
- handleOnReset();
- };
-
- const filtersCount = Object.values(form.getFieldsValue()).filter(
- (value) => value !== undefined && value !== null && value !== ''
- ).length;
-
- const renderFooter = () => {
- return (
-
-
-
-
-
-
- );
- };
-
- return (
-
-
-
-
-
- }
- onOpenChange={handleOpenChange}
- styles={{
- container: {
- padding: 8,
- border: '1px solid var(--ant-color-split)'
- },
- root: {
- width: width
- }
- }}
- >
-
-
-
-
-
- );
-};
-
-export default FilterForm;
diff --git a/src/pages/_components/filter-form/index.tsx b/src/pages/_components/filter-form/index.tsx
new file mode 100644
index 00000000..6e68fb58
--- /dev/null
+++ b/src/pages/_components/filter-form/index.tsx
@@ -0,0 +1,155 @@
+import OverlayScroller from '@/components/overlay-scroller';
+import { CloseOutlined } from '@ant-design/icons';
+import { useIntl } from '@umijs/max';
+import { Button, Form } from 'antd';
+import classNames from 'classnames';
+import React, { forwardRef, useImperativeHandle } from 'react';
+import filterFormCss from '../styles/filter-form.less';
+
+const FilterForm: React.FC<
+ React.PropsWithChildren & {
+ ref?: any;
+ width?: number;
+ contentHeight?: number | string;
+ initialValues?: any;
+ hasFilters?: boolean;
+ open?: boolean;
+ onClear?: () => void;
+ onClose?: () => void;
+ onValuesChange?: (ChangeValues: any, allValues: any) => void;
+ styles?: {
+ container?: React.CSSProperties;
+ wrapper?: React.CSSProperties;
+ };
+ }
+> = forwardRef(
+ (
+ {
+ children,
+ open,
+ width = 300,
+ contentHeight = 400,
+ initialValues = {},
+ styles,
+ onClose,
+ onClear,
+ onValuesChange
+ },
+ ref
+ ) => {
+ const intl = useIntl();
+ const [form] = Form.useForm();
+
+ const handleOnReset = () => {
+ form.resetFields(Object.keys(initialValues));
+ form.resetFields();
+ onValuesChange?.({}, form.getFieldsValue());
+ };
+
+ const handleOnClose = () => {
+ onClose?.();
+ };
+
+ const handleOnValuesChange = (changedValues: any, allValues: any) => {
+ onValuesChange?.(changedValues, allValues);
+ };
+
+ const handleOnClear = () => {
+ handleOnReset();
+ };
+
+ const filtersCount = Object.values(form.getFieldsValue()).filter(
+ (value) => value !== undefined && value !== null && value !== ''
+ ).length;
+
+ const renderFooter = () => {
+ return (
+
+
+
+
+
+
+ );
+ };
+
+ useImperativeHandle(ref, () => ({
+ form,
+ reset: handleOnReset,
+ getValues: () => form.getFieldsValue(),
+ setValues: (values: any) => form.setFieldsValue(values)
+ }));
+
+ return (
+
+
+
+
+ {intl.formatMessage({ id: 'common.filter.label' })}
+
+ }
+ onClick={handleOnClose}
+ type="text"
+ style={{
+ color: 'var(--ant-color-text-secondary)'
+ }}
+ >
+
+
+
+
+
+
+ );
+ }
+);
+
+export default FilterForm;
diff --git a/src/pages/_components/page-box.tsx b/src/pages/_components/page-box.tsx
index 8daa456b..e6ba8368 100644
--- a/src/pages/_components/page-box.tsx
+++ b/src/pages/_components/page-box.tsx
@@ -74,8 +74,11 @@ export const PageContainerInner: React.FC<
);
};
-const PageBox: React.FC<{ children: React.ReactNode }> = ({ children }) => {
- return {children}
;
+const PageBox: React.FC<{
+ children: React.ReactNode;
+ style?: React.CSSProperties;
+}> = ({ children, style }) => {
+ return {children}
;
};
export default PageBox;
diff --git a/src/pages/_components/styles/filter-form.less b/src/pages/_components/styles/filter-form.less
new file mode 100644
index 00000000..9bbdb3e6
--- /dev/null
+++ b/src/pages/_components/styles/filter-form.less
@@ -0,0 +1,41 @@
+.wrapper {
+ flex-shrink: 0;
+ overflow: hidden;
+ width: 0;
+ transition: all var(--ant-motion-duration-slow) var(--ant-motion-ease-in-out);
+ border-color: var(--ant-color-split);
+
+ &.show {
+ width: 232px;
+ border-right: 1px solid var(--ant-color-split);
+ }
+}
+
+.container {
+ padding: 0 16px;
+
+ .title {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+ margin-top: 8px;
+ padding-inline: 8px;
+ font-weight: 500;
+ color: var(--ant-color-text-tertiary);
+ }
+
+ .btn-wrapper {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-top: 24px;
+ padding-right: 8px;
+ }
+
+ .buttons {
+ display: flex;
+ gap: 8px;
+ justify-content: flex-end;
+ }
+}
diff --git a/src/pages/backends/index.tsx b/src/pages/backends/index.tsx
index 9428c8db..91f28a3b 100644
--- a/src/pages/backends/index.tsx
+++ b/src/pages/backends/index.tsx
@@ -233,7 +233,7 @@ const BackendList = () => {
marginBottom={22}
marginTop={30}
widths={{
- input: 300
+ input: 230
}}
actionItems={addActions}
actionType="dropdown"
diff --git a/src/pages/benchmark/components/left-actions.tsx b/src/pages/benchmark/components/left-actions.tsx
index c8bc39d2..2bff3045 100644
--- a/src/pages/benchmark/components/left-actions.tsx
+++ b/src/pages/benchmark/components/left-actions.tsx
@@ -1,11 +1,10 @@
-import BaseSelect from '@/components/seal-form/base/select';
+import { FiltersButton } from '@/components/page-tools';
import { modelCategoriesMap } from '@/pages/llmodels/config';
import { SearchOutlined, SyncOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Input, Space } from 'antd';
import _ from 'lodash';
import React from 'react';
-import { profileOptions } from '../config';
export interface RightActionsProps {
handleInputChange: (e: React.ChangeEvent) => void;
@@ -13,12 +12,18 @@ export interface RightActionsProps {
handleQueryChange: (value: any, option?: any) => void;
modelList?: Global.BaseOption[];
datasetList?: Global.BaseOption[];
+ toggleFilters: () => void;
+ count?: number;
+ onClear: () => void;
}
const RightActions: React.FC = ({
handleInputChange,
handleSearch,
handleQueryChange,
+ toggleFilters,
+ count,
+ onClear,
modelList,
datasetList
}) => {
@@ -44,6 +49,11 @@ const RightActions: React.FC = ({
return (
+
= ({
placeholder={intl.formatMessage({
id: 'common.filter.name'
})}
- style={{ width: 200 }}
+ style={{ width: 300 }}
allowClear
onChange={handleInputChange}
>
- = ({
page: 1
})
}
- >
+ > */}