diff --git a/frontend/src/locales/en-US/translation.json b/frontend/src/locales/en-US/translation.json index 6d31a1f1..afc1ba48 100644 --- a/frontend/src/locales/en-US/translation.json +++ b/frontend/src/locales/en-US/translation.json @@ -466,6 +466,7 @@ "editRoute": "Edit Route", "deleteConfirmation": "Are you sure you want to delete <1>{{currentRouteName}}?", "noCustomIngresses": "Note: Only routes created from the console are listed above.", + "routeSearchPlaceholder": "Search routes by route name, domain, routing conditions and target service.", "factorGroup": { "columns": { "key": "Key", diff --git a/frontend/src/locales/zh-CN/translation.json b/frontend/src/locales/zh-CN/translation.json index b3888a85..c4985d70 100644 --- a/frontend/src/locales/zh-CN/translation.json +++ b/frontend/src/locales/zh-CN/translation.json @@ -465,6 +465,7 @@ "editRoute": "编辑路由", "deleteConfirmation": "确定删除 <1>{{currentRouteName}} 吗?", "noCustomIngresses": "注:列表中仅包含通过控制台页面创建的路由配置。", + "routeSearchPlaceholder": "根据路由名称、域名、路由条件和目标服务搜索路由", "factorGroup": { "columns": { "key": "Key", @@ -605,4 +606,4 @@ "isRequired": "是必填的", "invalidSchema": "由于 schema 信息无法正常解析,本插件只支持 YAML 编辑方式。" } -} \ No newline at end of file +} diff --git a/frontend/src/pages/route/index.tsx b/frontend/src/pages/route/index.tsx index 69fdf24e..d3beaa24 100644 --- a/frontend/src/pages/route/index.tsx +++ b/frontend/src/pages/route/index.tsx @@ -10,11 +10,12 @@ import { addGatewayRoute, deleteGatewayRoute, getGatewayRoutes, updateGatewayRou import store from '@/store'; import switches from '@/switches'; import { isInternalResource } from '@/utils'; -import { ExclamationCircleOutlined, RedoOutlined } from '@ant-design/icons'; +import { ExclamationCircleOutlined, RedoOutlined, SearchOutlined } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-layout'; import { useRequest } from 'ahooks'; -import { Alert, Button, Col, Drawer, Form, Modal, Row, Space, Table, Typography } from 'antd'; +import { Alert, Button, Col, Drawer, Form, Input, Modal, Row, Space, Table, Typography } from 'antd'; import { history } from 'ice'; +import { debounce } from 'lodash'; import React, { useEffect, useRef, useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import RouteForm from './components/RouteForm'; @@ -105,12 +106,15 @@ const RouteList: React.FC = () => { ]; const [dataSource, setDataSource] = useState([]); + const [originalDataSource, setOriginalDataSource] = useState([]); const [form] = Form.useForm(); const [openModal, setOpenModal] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); const [currentRoute, setCurrentRoute] = useState(); const [openDrawer, setOpenDrawer] = useState(false); + const [isLoading, setIsLoading] = useState(false); const formRef = useRef(null); + const [searchValue, setSearchValue] = useState(''); const getRouteList = async (factor): Promise => getGatewayRoutes(factor); @@ -132,6 +136,7 @@ const RouteList: React.FC = () => { return i1.name.localeCompare(i2.name); }) setDataSource(result || []); + setOriginalDataSource(result || []); }, }); @@ -223,6 +228,29 @@ const RouteList: React.FC = () => { setCurrentRoute(null); }; + const handleSearch = debounce((value: string) => { + if (!value) { + setDataSource(originalDataSource); + return; + } + setIsLoading(true); + const filteredData = originalDataSource.filter((item) => { + const nameMatch = item.name?.includes(value); + const domainsMatch = item.domains?.some(domain => domain.includes(value)); + const pathMatch = item.path?.matchValue?.includes(value); + const servicesMatch = item.services?.some(service => service.name?.includes(value)); + return nameMatch || domainsMatch || pathMatch || servicesMatch; + }); + setDataSource(filteredData); + setIsLoading(false); + }, 300); + + const onSearchChange = (e: React.ChangeEvent) => { + const { value } = e.target; + setSearchValue(value); + handleSearch(value); + }; + return ( { @@ -249,12 +277,25 @@ const RouteList: React.FC = () => { }} > - - - -