|
@@ -1,26 +1,49 @@
|
|
import useSWR from "swr";
|
|
import useSWR from "swr";
|
|
|
|
+import { useState } from "react";
|
|
import { useLockFn } from "ahooks";
|
|
import { useLockFn } from "ahooks";
|
|
-import { Box, Grid, IconButton, Stack } from "@mui/material";
|
|
|
|
-import { RestartAltRounded } from "@mui/icons-material";
|
|
|
|
|
|
+import {
|
|
|
|
+ Box,
|
|
|
|
+ Divider,
|
|
|
|
+ Grid,
|
|
|
|
+ IconButton,
|
|
|
|
+ ListItemIcon,
|
|
|
|
+ ListItemText,
|
|
|
|
+ Menu,
|
|
|
|
+ MenuItem,
|
|
|
|
+ Stack,
|
|
|
|
+} from "@mui/material";
|
|
|
|
+import {
|
|
|
|
+ AddchartRounded,
|
|
|
|
+ CheckRounded,
|
|
|
|
+ MenuRounded,
|
|
|
|
+ RestartAltRounded,
|
|
|
|
+} from "@mui/icons-material";
|
|
import {
|
|
import {
|
|
getProfiles,
|
|
getProfiles,
|
|
deleteProfile,
|
|
deleteProfile,
|
|
enhanceProfiles,
|
|
enhanceProfiles,
|
|
changeProfileChain,
|
|
changeProfileChain,
|
|
|
|
+ changeProfileValid,
|
|
} from "../../services/cmds";
|
|
} from "../../services/cmds";
|
|
import { CmdType } from "../../services/types";
|
|
import { CmdType } from "../../services/types";
|
|
-import Notice from "../base/base-notice";
|
|
|
|
|
|
+import getSystem from "../../utils/get-system";
|
|
import ProfileMore from "./profile-more";
|
|
import ProfileMore from "./profile-more";
|
|
|
|
+import Notice from "../base/base-notice";
|
|
|
|
|
|
interface Props {
|
|
interface Props {
|
|
items: CmdType.ProfileItem[];
|
|
items: CmdType.ProfileItem[];
|
|
chain: string[];
|
|
chain: string[];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+const OS = getSystem();
|
|
|
|
+
|
|
const EnhancedMode = (props: Props) => {
|
|
const EnhancedMode = (props: Props) => {
|
|
const { items, chain } = props;
|
|
const { items, chain } = props;
|
|
|
|
|
|
- const { mutate } = useSWR("getProfiles", getProfiles);
|
|
|
|
|
|
+ const { data, mutate } = useSWR("getProfiles", getProfiles);
|
|
|
|
+ const valid = data?.valid || [];
|
|
|
|
+
|
|
|
|
+ const [anchorEl, setAnchorEl] = useState<any>(null);
|
|
|
|
|
|
// handler
|
|
// handler
|
|
const onEnhance = useLockFn(async () => {
|
|
const onEnhance = useLockFn(async () => {
|
|
@@ -74,6 +97,19 @@ const EnhancedMode = (props: Props) => {
|
|
mutate((conf = {}) => ({ ...conf, chain: newChain }), true);
|
|
mutate((conf = {}) => ({ ...conf, chain: newChain }), true);
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+ // update valid list
|
|
|
|
+ const onToggleValid = useLockFn(async (key: string) => {
|
|
|
|
+ try {
|
|
|
|
+ const newValid = valid.includes(key)
|
|
|
|
+ ? valid.filter((i) => i !== key)
|
|
|
|
+ : valid.concat(key);
|
|
|
|
+ await changeProfileValid(newValid);
|
|
|
|
+ mutate();
|
|
|
|
+ } catch (err: any) {
|
|
|
|
+ Notice.error(err.message || err.toString());
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
return (
|
|
return (
|
|
<Box sx={{ mt: 4 }}>
|
|
<Box sx={{ mt: 4 }}>
|
|
<Stack
|
|
<Stack
|
|
@@ -92,9 +128,74 @@ const EnhancedMode = (props: Props) => {
|
|
<RestartAltRounded />
|
|
<RestartAltRounded />
|
|
</IconButton>
|
|
</IconButton>
|
|
|
|
|
|
- {/* <IconButton size="small" color="inherit">
|
|
|
|
|
|
+ <IconButton
|
|
|
|
+ size="small"
|
|
|
|
+ color="inherit"
|
|
|
|
+ id="profile-use-button"
|
|
|
|
+ title="enable clash fields"
|
|
|
|
+ aria-controls={!!anchorEl ? "profile-use-menu" : undefined}
|
|
|
|
+ aria-haspopup="true"
|
|
|
|
+ aria-expanded={!!anchorEl ? "true" : undefined}
|
|
|
|
+ onClick={(e) => setAnchorEl(e.currentTarget)}
|
|
|
|
+ >
|
|
<MenuRounded />
|
|
<MenuRounded />
|
|
- </IconButton> */}
|
|
|
|
|
|
+ </IconButton>
|
|
|
|
+
|
|
|
|
+ <Menu
|
|
|
|
+ id="profile-use-menu"
|
|
|
|
+ open={!!anchorEl}
|
|
|
|
+ anchorEl={anchorEl}
|
|
|
|
+ onClose={() => setAnchorEl(null)}
|
|
|
|
+ transitionDuration={225}
|
|
|
|
+ TransitionProps={
|
|
|
|
+ OS === "macos" ? { style: { transitionDuration: "225ms" } } : {}
|
|
|
|
+ }
|
|
|
|
+ MenuListProps={{
|
|
|
|
+ dense: true,
|
|
|
|
+ "aria-labelledby": "profile-use-button",
|
|
|
|
+ }}
|
|
|
|
+ onContextMenu={(e) => {
|
|
|
|
+ setAnchorEl(null);
|
|
|
|
+ e.preventDefault();
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ <MenuItem>
|
|
|
|
+ <ListItemIcon color="inherit">
|
|
|
|
+ <AddchartRounded />
|
|
|
|
+ </ListItemIcon>
|
|
|
|
+ Use Clash Fields
|
|
|
|
+ </MenuItem>
|
|
|
|
+
|
|
|
|
+ <Divider />
|
|
|
|
+
|
|
|
|
+ {[
|
|
|
|
+ "tun",
|
|
|
|
+ "dns",
|
|
|
|
+ "hosts",
|
|
|
|
+ "script",
|
|
|
|
+ "profile",
|
|
|
|
+ "payload",
|
|
|
|
+ "interface-name",
|
|
|
|
+ "routing-mark",
|
|
|
|
+ ].map((key) => {
|
|
|
|
+ const has = valid.includes(key);
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <MenuItem
|
|
|
|
+ key={key}
|
|
|
|
+ sx={{ width: 180 }}
|
|
|
|
+ onClick={() => onToggleValid(key)}
|
|
|
|
+ >
|
|
|
|
+ {has && (
|
|
|
|
+ <ListItemIcon color="inherit">
|
|
|
|
+ <CheckRounded />
|
|
|
|
+ </ListItemIcon>
|
|
|
|
+ )}
|
|
|
|
+ <ListItemText inset={!has}>{key}</ListItemText>
|
|
|
|
+ </MenuItem>
|
|
|
|
+ );
|
|
|
|
+ })}
|
|
|
|
+ </Menu>
|
|
</Stack>
|
|
</Stack>
|
|
|
|
|
|
<Grid container spacing={2}>
|
|
<Grid container spacing={2}>
|