import useSWR, { useSWRConfig } from "swr"; import { useEffect, useRef, useState } from "react"; import { useLockFn } from "ahooks"; import { Virtuoso } from "react-virtuoso"; import { Box, Collapse, Divider, List, ListItem, ListItemText, } from "@mui/material"; import { SendRounded, ExpandLessRounded, ExpandMoreRounded, } from "@mui/icons-material"; import { providerHealthCheck, updateProxy } from "@/services/api"; import { getProfiles, patchProfile } from "@/services/cmds"; import delayManager from "@/services/delay"; import useSortProxy from "./use-sort-proxy"; import useHeadState from "./use-head-state"; import useFilterProxy from "./use-filter-proxy"; import ProxyHead from "./proxy-head"; import ProxyItem from "./proxy-item"; interface Props { group: ApiType.ProxyGroupItem; } const ProxyGroup = ({ group }: Props) => { const { mutate } = useSWRConfig(); const [now, setNow] = useState(group.now); const [headState, setHeadState] = useHeadState(group.name); const virtuosoRef = useRef(); const filterProxies = useFilterProxy( group.all, group.name, headState.filterText ); const sortedProxies = useSortProxy( filterProxies, group.name, headState.sortType ); const { data: profiles } = useSWR("getProfiles", getProfiles); const onChangeProxy = useLockFn(async (name: string) => { // Todo: support another proxy group type if (group.type !== "Selector") return; const oldValue = now; try { setNow(name); await updateProxy(group.name, name); } catch { setNow(oldValue); return; // do not update profile } try { const profile = profiles?.items?.find((p) => p.uid === profiles.current); if (!profile) return; if (!profile.selected) profile.selected = []; const index = profile.selected.findIndex( (item) => item.name === group.name ); if (index < 0) { profile.selected.push({ name: group.name, now: name }); } else { profile.selected[index] = { name: group.name, now: name }; } await patchProfile(profiles!.current!, { selected: profile.selected }); } catch (err) { console.error(err); } }); const onLocation = (smooth = true) => { const index = sortedProxies.findIndex((p) => p.name === now); if (index >= 0) { virtuosoRef.current?.scrollToIndex?.({ index, align: "center", behavior: smooth ? "smooth" : "auto", }); } }; const onCheckAll = useLockFn(async () => { const providers = new Set( sortedProxies.map((p) => p.provider!).filter(Boolean) ); if (providers.size) { Promise.allSettled( [...providers].map((p) => providerHealthCheck(p)) ).then(() => mutate("getProxies")); } await delayManager.checkListDelay( { names: sortedProxies.filter((p) => !p.provider).map((p) => p.name), groupName: group.name, skipNum: 16, }, () => mutate("getProxies") ); }); // auto scroll to current index useEffect(() => { if (headState.open) { setTimeout(() => onLocation(false), 5); } }, [headState.open]); return ( <> setHeadState({ open: !headState.open })} > {now} } secondaryTypographyProps={{ sx: { display: "flex", alignItems: "center" }, }} /> {headState.open ? : } {!sortedProxies.length && ( Empty )} {sortedProxies.length >= 10 ? ( ( )} /> ) : ( {sortedProxies.map((proxy) => ( ))} )} ); }; export default ProxyGroup;