diff --git a/src/components/proxy/provider-button.tsx b/src/components/proxy/provider-button.tsx new file mode 100644 index 0000000000000000000000000000000000000000..29665a54412b3933959685f3a08962e1ee1ca810 --- /dev/null +++ b/src/components/proxy/provider-button.tsx @@ -0,0 +1,86 @@ +import dayjs from "dayjs"; +import useSWR, { mutate } from "swr"; +import { useState } from "react"; +import { + Button, + IconButton, + List, + ListItem, + ListItemText, +} from "@mui/material"; +import { RefreshRounded } from "@mui/icons-material"; +import { useTranslation } from "react-i18next"; +import { useLockFn } from "ahooks"; +import { getProviders, providerUpdate } from "@/services/api"; +import { BaseDialog } from "../base"; + +export const ProviderButton = () => { + const { t } = useTranslation(); + const { data } = useSWR("getProviders", getProviders); + + const [open, setOpen] = useState(false); + + const hasProvider = Object.keys(data || {}).length > 0; + + const handleUpdate = useLockFn(async (key: string) => { + await providerUpdate(key); + await mutate("getProxies"); + await mutate("getProviders"); + }); + + if (!hasProvider) return null; + + return ( + <> + <Button + size="small" + variant="outlined" + sx={{ textTransform: "capitalize" }} + onClick={() => setOpen(true)} + > + {t("Provider")} + </Button> + + <BaseDialog + open={open} + title={t("Proxy Provider")} + contentSx={{ width: 400 }} + disableOk + cancelBtn={t("Cancel")} + onClose={() => setOpen(false)} + onCancel={() => setOpen(false)} + > + <List sx={{ py: 0, minHeight: 250 }}> + {Object.entries(data || {}).map(([key, item]) => { + const time = dayjs(item.updatedAt); + return ( + <ListItem sx={{ p: 0 }}> + <ListItemText + primary={key} + secondary={ + <div> + <span style={{ marginRight: "4em" }}> + Type: {item.vehicleType} + </span> + <span title={time.format("YYYY-MM-DD HH:mm:ss")}> + Updated: {time.fromNow()} + </span> + </div> + } + /> + <IconButton + size="small" + color="inherit" + title="Update Provider" + onClick={() => handleUpdate(key)} + > + <RefreshRounded /> + </IconButton> + </ListItem> + ); + })} + </List> + </BaseDialog> + </> + ); +}; diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index 84263d5d37d3bdc1b0f69c654355cd0e5b0c7363..f0b1b963f9ad9431512af147405822bedefd438e 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -48,6 +48,7 @@ const Layout = () => { mutate("getProxies"); mutate("getVersion"); mutate("getClashConfig"); + mutate("getProviders"); }); // update the verge config diff --git a/src/pages/proxies.tsx b/src/pages/proxies.tsx index 2e2e62901f5d8f8d94286234b4a4687ea3b6d4da..39c777bdf6c3d82fc122172b0e277f6f931468d3 100644 --- a/src/pages/proxies.tsx +++ b/src/pages/proxies.tsx @@ -2,7 +2,7 @@ import useSWR from "swr"; import { useEffect, useMemo } from "react"; import { useLockFn } from "ahooks"; import { useTranslation } from "react-i18next"; -import { Button, ButtonGroup, Paper } from "@mui/material"; +import { Box, Button, ButtonGroup, Paper } from "@mui/material"; import { closeAllConnections, getClashConfig, @@ -12,6 +12,7 @@ import { patchClashConfig } from "@/services/cmds"; import { useVerge } from "@/hooks/use-verge"; import { BasePage } from "@/components/base"; import { ProxyGroups } from "@/components/proxy/proxy-groups"; +import { ProviderButton } from "@/components/proxy/provider-button"; const ProxyPage = () => { const { t } = useTranslation(); @@ -53,18 +54,22 @@ const ProxyPage = () => { contentStyle={{ height: "100%" }} title={t("Proxy Groups")} header={ - <ButtonGroup size="small"> - {modeList.map((mode) => ( - <Button - key={mode} - variant={mode === curMode ? "contained" : "outlined"} - onClick={() => onChangeMode(mode)} - sx={{ textTransform: "capitalize" }} - > - {t(mode)} - </Button> - ))} - </ButtonGroup> + <Box display="flex" alignItems="center" gap={1}> + <ProviderButton /> + + <ButtonGroup size="small"> + {modeList.map((mode) => ( + <Button + key={mode} + variant={mode === curMode ? "contained" : "outlined"} + onClick={() => onChangeMode(mode)} + sx={{ textTransform: "capitalize" }} + > + {t(mode)} + </Button> + ))} + </ButtonGroup> + </Box> } > <Paper diff --git a/src/services/api.ts b/src/services/api.ts index 65e72341a64831244ffa4744bd51d6e3fd94cc9b..263f90edb2d5c7e1309edff88cf27d3fb9261c4c 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -169,6 +169,11 @@ export const providerHealthCheck = async (name: string) => { ); }; +export const providerUpdate = async (name: string) => { + const instance = await getAxios(); + return instance.put(`/providers/proxies/${encodeURIComponent(name)}`); +}; + export const getConnections = async () => { const instance = await getAxios(); const result = await instance.get("/connections");