123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- import { mutate } from "swr";
- import { useEffect, useState } from "react";
- import { useLockFn, useSetState } from "ahooks";
- import { useTranslation } from "react-i18next";
- import {
- Button,
- Collapse,
- Dialog,
- DialogActions,
- DialogContent,
- DialogTitle,
- FormControlLabel,
- IconButton,
- Switch,
- TextField,
- } from "@mui/material";
- import { Settings } from "@mui/icons-material";
- import { patchProfile } from "@/services/cmds";
- import { version } from "@root/package.json";
- import { Notice } from "@/components/base";
- interface Props {
- open: boolean;
- itemData: IProfileItem;
- onClose: () => void;
- }
- // edit the profile item
- // remote / local file / merge / script
- const InfoEditor = (props: Props) => {
- const { open, itemData, onClose } = props;
- const { t } = useTranslation();
- const [form, setForm] = useSetState({ ...itemData });
- const [option, setOption] = useSetState(itemData.option ?? {});
- const [showOpt, setShowOpt] = useState(!!itemData.option);
- useEffect(() => {
- if (itemData) {
- const { option } = itemData;
- setForm({ ...itemData });
- setOption(option ?? {});
- setShowOpt(
- itemData.type === "remote" &&
- (!!option?.user_agent ||
- !!option?.update_interval ||
- !!option?.self_proxy ||
- !!option?.with_proxy)
- );
- }
- }, [itemData]);
- const onUpdate = useLockFn(async () => {
- try {
- const { uid } = itemData;
- const { name, desc, url } = form;
- const option_ =
- itemData.type === "remote" || itemData.type === "local"
- ? option
- : undefined;
- if (itemData.type === "remote" && !url) {
- throw new Error("Remote URL should not be null");
- }
- await patchProfile(uid, { uid, name, desc, url, option: option_ });
- mutate("getProfiles");
- onClose();
- } catch (err: any) {
- Notice.error(err?.message || err.toString());
- }
- });
- const textFieldProps = {
- fullWidth: true,
- size: "small",
- margin: "normal",
- variant: "outlined",
- } as const;
- const type =
- form.type ||
- (form.url ? "remote" : form.file?.endsWith(".js") ? "script" : "local");
- return (
- <Dialog open={open} onClose={onClose}>
- <DialogTitle sx={{ pb: 0.5 }}>{t("Edit Info")}</DialogTitle>
- <DialogContent sx={{ width: 336, pb: 1 }}>
- <TextField
- {...textFieldProps}
- disabled
- label={t("Type")}
- value={type}
- sx={{ input: { textTransform: "capitalize" } }}
- />
- <TextField
- {...textFieldProps}
- autoFocus
- label={t("Name")}
- value={form.name}
- onChange={(e) => setForm({ name: e.target.value })}
- onKeyDown={(e) => e.key === "Enter" && onUpdate()}
- />
- <TextField
- {...textFieldProps}
- label={t("Descriptions")}
- value={form.desc}
- onChange={(e) => setForm({ desc: e.target.value })}
- onKeyDown={(e) => e.key === "Enter" && onUpdate()}
- />
- {type === "remote" && (
- <TextField
- {...textFieldProps}
- label={t("Subscription URL")}
- value={form.url}
- onChange={(e) => setForm({ url: e.target.value })}
- onKeyDown={(e) => e.key === "Enter" && onUpdate()}
- />
- )}
- {(type === "remote" || type === "local") && (
- <TextField
- {...textFieldProps}
- label={t("Update Interval(mins)")}
- value={option.update_interval}
- onChange={(e) => {
- const str = e.target.value?.replace(/\D/, "");
- setOption({ update_interval: !!str ? +str : undefined });
- }}
- onKeyDown={(e) => e.key === "Enter" && onUpdate()}
- />
- )}
- <Collapse
- in={type === "remote" && showOpt}
- timeout="auto"
- unmountOnExit
- >
- <TextField
- {...textFieldProps}
- label="User Agent"
- value={option.user_agent}
- placeholder={`clash-verge/v${version}`}
- onChange={(e) => setOption({ user_agent: e.target.value })}
- onKeyDown={(e) => e.key === "Enter" && onUpdate()}
- />
- <FormControlLabel
- label={t("Use System Proxy")}
- labelPlacement="start"
- sx={{ ml: 0, my: 1 }}
- control={
- <Switch
- color="primary"
- checked={option.with_proxy ?? false}
- onChange={(_e, c) =>
- setOption((o) => ({
- self_proxy: c ? false : o.self_proxy ?? false,
- with_proxy: c,
- }))
- }
- />
- }
- />
- <FormControlLabel
- label={t("Use Clash Proxy")}
- labelPlacement="start"
- sx={{ ml: 0, my: 1 }}
- control={
- <Switch
- color="primary"
- checked={option.self_proxy ?? false}
- onChange={(_e, c) =>
- setOption((o) => ({
- with_proxy: c ? false : o.with_proxy ?? false,
- self_proxy: c,
- }))
- }
- />
- }
- />
- </Collapse>
- </DialogContent>
- <DialogActions sx={{ px: 2, pb: 2, position: "relative" }}>
- {form.type === "remote" && (
- <IconButton
- size="small"
- color="inherit"
- sx={{ position: "absolute", left: 18 }}
- onClick={() => setShowOpt((o) => !o)}
- >
- <Settings />
- </IconButton>
- )}
- <Button onClick={onClose} variant="outlined">
- {t("Cancel")}
- </Button>
- <Button onClick={onUpdate} variant="contained">
- {t("Save")}
- </Button>
- </DialogActions>
- </Dialog>
- );
- };
- export default InfoEditor;
|