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 });
+}