diff --git a/src/components/rule/rule-item.tsx b/src/components/rule/rule-item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b663e866c5501dcfabb90290a439636513dd09ba --- /dev/null +++ b/src/components/rule/rule-item.tsx @@ -0,0 +1,72 @@ +import { styled, Box, Typography } from "@mui/material"; + +const Item = styled(Box)(({ theme }) => ({ + display: "flex", + padding: "6px 16px", + color: theme.palette.text.primary, + marginBottom: "6px", +})); + +const COLOR = [ + "primary", + "secondary", + "info", + "warning", + "error", + "success", + "text", +]; + +interface Props { + index: number; + value: ApiType.RuleItem; +} + +const parseColor = (text: string) => { + let sum = 0; + for (let i = 0; i < text.length; i++) { + sum += text.charCodeAt(i); + } + return COLOR[sum % COLOR.length]; +}; + +const RuleItem = (props: Props) => { + const { index, value } = props; + + return ( + <Item> + <Typography + color="text.secondary" + variant="body2" + sx={{ lineHeight: 2, minWidth: 30, mr: 2.25, textAlign: "center" }} + > + {index} + </Typography> + + <Box> + <Typography component="h6" variant="subtitle1" color="text.primary"> + {value.payload || "-"} + </Typography> + + <Typography + component="span" + variant="body2" + color="text.secondary" + sx={{ mr: 3, minWidth: 120, display: "inline-block" }} + > + {value.type} + </Typography> + + <Typography + component="span" + variant="body2" + color={parseColor(value.proxy)} + > + {value.proxy} + </Typography> + </Box> + </Item> + ); +}; + +export default RuleItem; diff --git a/src/locales/en.json b/src/locales/en.json index cbaab6357b9efa2850efbef04144d299c2a7c1fb..6819cbe242d6ffafc0f6effc0e65adb1d2642162 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -3,6 +3,7 @@ "Label-Profiles": "Profiles", "Label-Connections": "Connections", "Label-Logs": "Logs", + "Label-Rules": "Rules", "Label-Settings": "Settings", "Connections": "Connections", @@ -73,6 +74,7 @@ "Theme Mode": "Theme Mode", "Theme Blur": "Theme Blur", "Theme Setting": "Theme Setting", + "Hotkey Setting": "Hotkey Setting", "Traffic Graph": "Traffic Graph", "Language": "Language", "Open App Dir": "Open App Dir", diff --git a/src/locales/zh.json b/src/locales/zh.json index 05cd83b5b1e7dbf59a301933eaa271b73e6fb56d..d4d01427e957dc1e3ab8531d7310d2517726339e 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -3,6 +3,7 @@ "Label-Profiles": "é… ç½®", "Label-Connections": "è¿ž 接", "Label-Logs": "æ—¥ å¿—", + "Label-Rules": "规 则", "Label-Settings": "设 ç½®", "Connections": "连接", @@ -73,6 +74,7 @@ "Theme Mode": "主题模å¼", "Theme Blur": "背景模糊", "Theme Setting": "主题设置", + "Hotkey Setting": "çƒé”®è®¾ç½®", "Traffic Graph": "æµé‡å›¾æ˜¾", "Language": "è¯è¨€è®¾ç½®", "Open App Dir": "应用目录", diff --git a/src/pages/_routers.tsx b/src/pages/_routers.tsx index 9ab46205a14ad1904d695215d02c98cec424c1a3..bb3d7c9bb4f4eb91c7d23e2e48988b3e570bc390 100644 --- a/src/pages/_routers.tsx +++ b/src/pages/_routers.tsx @@ -3,6 +3,7 @@ import ProxiesPage from "./proxies"; import ProfilesPage from "./profiles"; import SettingsPage from "./settings"; import ConnectionsPage from "./connections"; +import RulesPage from "./rules"; export const routers = [ { @@ -15,6 +16,11 @@ export const routers = [ link: "/profile", ele: ProfilesPage, }, + { + label: "Label-Rules", + link: "/rules", + ele: RulesPage, + }, { label: "Label-Connections", link: "/connections", diff --git a/src/pages/rules.tsx b/src/pages/rules.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6397d08a6c491bcf0f1e147966f88a40da7662cc --- /dev/null +++ b/src/pages/rules.tsx @@ -0,0 +1,65 @@ +import useSWR from "swr"; +import { useState, useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import { Virtuoso } from "react-virtuoso"; +import { Box, Button, MenuItem, Paper, Select, TextField } from "@mui/material"; +import { getRules } from "@/services/api"; +import BasePage from "@/components/base/base-page"; +import BaseEmpty from "@/components/base/base-empty"; +import RuleItem from "@/components/rule/rule-item"; + +const RulesPage = () => { + const { t } = useTranslation(); + const { data = [] } = useSWR("getRules", getRules); + + const [filterText, setFilterText] = useState(""); + + const rules = useMemo(() => { + return data.filter((each) => each.payload.includes(filterText)); + }, [data, filterText]); + + return ( + <BasePage title={t("Rules")} contentStyle={{ height: "100%" }}> + <Paper sx={{ boxSizing: "border-box", boxShadow: 2, height: "100%" }}> + <Box + sx={{ + pt: 1, + mb: 0.5, + mx: "12px", + height: "36px", + display: "flex", + alignItems: "center", + }} + > + <TextField + hiddenLabel + fullWidth + size="small" + autoComplete="off" + variant="outlined" + placeholder={t("Filter conditions")} + value={filterText} + onChange={(e) => setFilterText(e.target.value)} + sx={{ input: { py: 0.65, px: 1.25 } }} + /> + </Box> + + <Box height="calc(100% - 50px)"> + {rules.length > 0 ? ( + <Virtuoso + data={rules} + itemContent={(index, item) => ( + <RuleItem index={index + 1} value={item} /> + )} + followOutput={"smooth"} + /> + ) : ( + <BaseEmpty text="No Rules" /> + )} + </Box> + </Paper> + </BasePage> + ); +}; + +export default RulesPage; diff --git a/src/services/api.ts b/src/services/api.ts index 4794cf7d6e535c42cc99a99dc7e321aa6d5032ef..96e9128f3bbf048b8658069f88a8397fae840281 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -62,7 +62,8 @@ export async function updateConfigs(config: Partial<ApiType.ConfigData>) { /// Get current rules export async function getRules() { const instance = await getAxios(); - return instance.get("/rules") as Promise<ApiType.RuleItem[]>; + const response = await instance.get<any, any>("/rules"); + return response?.rules as ApiType.RuleItem[]; } /// Get Proxy delay