diff --git a/package.json b/package.json index 2ddf6be..1a934a4 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react": "^17.0.0", "react-dom": "^17.0.0", "react-router-dom": "^6.0.2", + "react-virtuoso": "^2.3.1", "recoil": "^0.5.2" }, "devDependencies": { diff --git a/src/components/proxy-group.tsx b/src/components/proxy-group.tsx new file mode 100644 index 0000000..6be59f4 --- /dev/null +++ b/src/components/proxy-group.tsx @@ -0,0 +1,142 @@ +import { useState } from "react"; +import { Virtuoso } from "react-virtuoso"; +import { + Box, + Collapse, + Divider, + IconButton, + List, + ListItem, + ListItemButton, + ListItemIcon, + ListItemText, +} from "@mui/material"; +import { + SendRounded, + ExpandLessRounded, + ExpandMoreRounded, + MyLocationRounded, + NetworkCheckRounded, + CheckCircleOutlineRounded, +} from "@mui/icons-material"; +import services from "../services"; +import type { ProxyItem, ProxyGroupItem } from "../services/proxy"; + +interface ItemProps { + proxy: ProxyItem; + selected: boolean; + onClick?: (name: string) => void; +} + +const Item = ({ proxy, selected, onClick }: ItemProps) => { + return ( + + onClick?.(proxy.name)} + sx={{ borderRadius: 1, py: 0.5 }} + > + + + {selected && } + + + + ); +}; + +interface Props { + group: ProxyGroupItem; +} + +const ProxyGroup = ({ group }: Props) => { + const [open, setOpen] = useState(false); + const [now, setNow] = useState(group.now); + + const proxies = group.all ?? []; + + const onUpdate = async (name: string) => { + // can not call update + if (group.type !== "Selector") { + // Todo + // error Tips + return; + } + const oldValue = now; + try { + setNow(name); + await services.updateProxy(group.name, name); + } catch { + setNow(oldValue); + // Todo + // error tips + } + }; + + return ( + <> + setOpen(!open)}> + + + {now} + + } + secondaryTypographyProps={{ + sx: { display: "flex", alignItems: "center" }, + }} + /> + + {open ? : } + + + + + + + + + + + + + {proxies.length >= 10 ? ( + ( + + )} + /> + ) : ( + + {proxies.map((proxy) => ( + + ))} + + )} + + + + + ); +}; + +export default ProxyGroup; diff --git a/src/pages/proxy.tsx b/src/pages/proxy.tsx index 2808614..2bbcbcc 100644 --- a/src/pages/proxy.tsx +++ b/src/pages/proxy.tsx @@ -1,5 +1,33 @@ +import { useEffect, useState } from "react"; +import { Box, List, Typography } from "@mui/material"; +import services from "../services"; +import ProxyGroup from "../components/proxy-group"; +import type { ProxyGroupItem } from "../services/proxy"; + const ProxyPage = () => { - return

Proxy

; + const [groups, setGroups] = useState([]); + + useEffect(() => { + // Todo + // result cache + services.getProxyInfo().then((res) => { + setGroups(res.groups); + }); + }, []); + + return ( + + + Proxy Groups + + + + {groups.map((group) => ( + + ))} + + + ); }; export default ProxyPage; diff --git a/src/services/index.ts b/src/services/index.ts index a15cef0..6832043 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -1,5 +1,7 @@ +import * as proxy from "./proxy"; import * as traffic from "./traffic"; export default { + ...proxy, ...traffic, }; diff --git a/src/services/proxy.ts b/src/services/proxy.ts new file mode 100644 index 0000000..452926e --- /dev/null +++ b/src/services/proxy.ts @@ -0,0 +1,47 @@ +import axiosIns from "./base"; + +export interface ProxyItem { + name: string; + type: string; + udp: boolean; + history: { + time: string; + delay: number; + }[]; + all?: string[]; + now?: string; +} + +export type ProxyGroupItem = Omit & { + all?: ProxyItem[]; + now?: string; +}; + +/// Get the Proxy infomation +export async function getProxyInfo() { + const response = (await axiosIns.get("/proxies")) as any; + const results = (response?.proxies ?? {}) as Record; + + const global = results["GLOBAL"] || results["global"]; + const proxies = Object.values(results).filter((each) => each.all == null); + + const groups = Object.values(results).filter( + (each) => each.name.toLocaleUpperCase() !== "GLOBAL" && each.all != null + ) as ProxyGroupItem[]; + + groups.forEach((each) => { + // @ts-ignore + each.all = each.all?.map((item) => results[item]).filter((e) => e); + }); + + return { + global, + groups, + proxies, + }; +} + +/// Update the Proxy Choose +export async function updateProxy(group: string, proxy: string) { + return axiosIns.put(`/proxies/${group}`, { name: proxy }); +}