mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 11:42:21 +08:00
feat: get network interface
This commit is contained in:
parent
ee56080af0
commit
1bd51be99c
|
@ -322,6 +322,17 @@ pub fn copy_icon_file(path: String, name: String) -> CmdResult<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn get_network_interfaces() -> Vec<String> {
|
||||||
|
use sysinfo::Networks;
|
||||||
|
let mut result = Vec::new();
|
||||||
|
let networks = Networks::new_with_refreshed_list();
|
||||||
|
for (interface_name, _) in &networks {
|
||||||
|
result.push(interface_name.clone());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn open_devtools(app_handle: tauri::AppHandle) {
|
pub fn open_devtools(app_handle: tauri::AppHandle) {
|
||||||
if let Some(window) = app_handle.get_window("main") {
|
if let Some(window) = app_handle.get_window("main") {
|
||||||
|
|
|
@ -51,6 +51,7 @@ fn main() -> std::io::Result<()> {
|
||||||
cmds::open_web_url,
|
cmds::open_web_url,
|
||||||
cmds::open_core_dir,
|
cmds::open_core_dir,
|
||||||
cmds::get_portable_flag,
|
cmds::get_portable_flag,
|
||||||
|
cmds::get_network_interfaces,
|
||||||
// cmds::kill_sidecar,
|
// cmds::kill_sidecar,
|
||||||
cmds::restart_sidecar,
|
cmds::restart_sidecar,
|
||||||
// clash
|
// clash
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReactNode, useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
@ -30,7 +30,11 @@ import {
|
||||||
styled,
|
styled,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { GroupItem } from "@/components/profile/group-item";
|
import { GroupItem } from "@/components/profile/group-item";
|
||||||
import { readProfileFile, saveProfileFile } from "@/services/cmds";
|
import {
|
||||||
|
getNetworkInterfaces,
|
||||||
|
readProfileFile,
|
||||||
|
saveProfileFile,
|
||||||
|
} from "@/services/cmds";
|
||||||
import { Notice, Switch } from "@/components/base";
|
import { Notice, Switch } from "@/components/base";
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
import { BaseSearchBox } from "../base/base-search-box";
|
import { BaseSearchBox } from "../base/base-search-box";
|
||||||
|
@ -60,7 +64,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||||
const [currData, setCurrData] = useState("");
|
const [currData, setCurrData] = useState("");
|
||||||
const [visualization, setVisualization] = useState(true);
|
const [visualization, setVisualization] = useState(true);
|
||||||
const [match, setMatch] = useState(() => (_: string) => true);
|
const [match, setMatch] = useState(() => (_: string) => true);
|
||||||
|
const [interfaceNameList, setInterfaceNameList] = useState<string[]>([]);
|
||||||
const { control, watch, register, ...formIns } = useForm<IProxyGroupConfig>({
|
const { control, watch, register, ...formIns } = useForm<IProxyGroupConfig>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
type: "select",
|
type: "select",
|
||||||
|
@ -251,6 +255,10 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||||
setProxyProviderList(Object.keys(provider));
|
setProxyProviderList(Object.keys(provider));
|
||||||
setGroupList(originGroupsObj?.["proxy-groups"] || []);
|
setGroupList(originGroupsObj?.["proxy-groups"] || []);
|
||||||
};
|
};
|
||||||
|
const getInterfaceNameList = async () => {
|
||||||
|
let list = await getNetworkInterfaces();
|
||||||
|
setInterfaceNameList(list);
|
||||||
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchProxyPolicy();
|
fetchProxyPolicy();
|
||||||
}, [prependSeq, appendSeq, deleteSeq]);
|
}, [prependSeq, appendSeq, deleteSeq]);
|
||||||
|
@ -259,6 +267,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||||
fetchContent();
|
fetchContent();
|
||||||
fetchProxyPolicy();
|
fetchProxyPolicy();
|
||||||
fetchProfile();
|
fetchProfile();
|
||||||
|
getInterfaceNameList();
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
const validateGroup = () => {
|
const validateGroup = () => {
|
||||||
|
@ -485,11 +494,13 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Item>
|
<Item>
|
||||||
<ListItemText primary={t("Interface Name")} />
|
<ListItemText primary={t("Interface Name")} />
|
||||||
<TextField
|
<Autocomplete
|
||||||
autoComplete="new-password"
|
|
||||||
size="small"
|
size="small"
|
||||||
sx={{ width: "calc(100% - 150px)" }}
|
sx={{ width: "calc(100% - 150px)" }}
|
||||||
{...field}
|
options={interfaceNameList}
|
||||||
|
value={field.value}
|
||||||
|
onChange={(_, value) => value && field.onChange(value)}
|
||||||
|
renderInput={(params) => <TextField {...params} />}
|
||||||
/>
|
/>
|
||||||
</Item>
|
</Item>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -475,64 +475,78 @@ export const ProfileItem = (props: Props) => {
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
{fileOpen && (
|
||||||
|
<EditorViewer
|
||||||
|
open={true}
|
||||||
|
initialData={readProfileFile(uid)}
|
||||||
|
language="yaml"
|
||||||
|
schema="clash"
|
||||||
|
onSave={async (prev, curr) => {
|
||||||
|
await saveProfileFile(uid, curr ?? "");
|
||||||
|
onSave && onSave(prev, curr);
|
||||||
|
}}
|
||||||
|
onClose={() => setFileOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{rulesOpen && (
|
||||||
|
<RulesEditorViewer
|
||||||
|
groupsUid={option?.groups ?? ""}
|
||||||
|
mergeUid={option?.merge ?? ""}
|
||||||
|
profileUid={uid}
|
||||||
|
property={option?.rules ?? ""}
|
||||||
|
open={true}
|
||||||
|
onSave={onSave}
|
||||||
|
onClose={() => setRulesOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{proxiesOpen && (
|
||||||
|
<ProxiesEditorViewer
|
||||||
|
profileUid={uid}
|
||||||
|
property={option?.proxies ?? ""}
|
||||||
|
open={true}
|
||||||
|
onSave={onSave}
|
||||||
|
onClose={() => setProxiesOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{groupsOpen && (
|
||||||
|
<GroupsEditorViewer
|
||||||
|
mergeUid={option?.merge ?? ""}
|
||||||
|
proxiesUid={option?.proxies ?? ""}
|
||||||
|
profileUid={uid}
|
||||||
|
property={option?.groups ?? ""}
|
||||||
|
open={true}
|
||||||
|
onSave={onSave}
|
||||||
|
onClose={() => {
|
||||||
|
setGroupsOpen(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{mergeOpen && (
|
||||||
|
<EditorViewer
|
||||||
|
open={true}
|
||||||
|
initialData={readProfileFile(option?.merge ?? "")}
|
||||||
|
language="yaml"
|
||||||
|
schema="clash"
|
||||||
|
onSave={async (prev, curr) => {
|
||||||
|
await saveProfileFile(option?.merge ?? "", curr ?? "");
|
||||||
|
onSave && onSave(prev, curr);
|
||||||
|
}}
|
||||||
|
onClose={() => setMergeOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{scriptOpen && (
|
||||||
|
<EditorViewer
|
||||||
|
open={true}
|
||||||
|
initialData={readProfileFile(option?.script ?? "")}
|
||||||
|
language="javascript"
|
||||||
|
onSave={async (prev, curr) => {
|
||||||
|
await saveProfileFile(option?.script ?? "", curr ?? "");
|
||||||
|
onSave && onSave(prev, curr);
|
||||||
|
}}
|
||||||
|
onClose={() => setScriptOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<EditorViewer
|
|
||||||
open={fileOpen}
|
|
||||||
initialData={readProfileFile(uid)}
|
|
||||||
language="yaml"
|
|
||||||
schema="clash"
|
|
||||||
onSave={async (prev, curr) => {
|
|
||||||
await saveProfileFile(uid, curr ?? "");
|
|
||||||
onSave && onSave(prev, curr);
|
|
||||||
}}
|
|
||||||
onClose={() => setFileOpen(false)}
|
|
||||||
/>
|
|
||||||
<RulesEditorViewer
|
|
||||||
groupsUid={option?.groups ?? ""}
|
|
||||||
mergeUid={option?.merge ?? ""}
|
|
||||||
profileUid={uid}
|
|
||||||
property={option?.rules ?? ""}
|
|
||||||
open={rulesOpen}
|
|
||||||
onSave={onSave}
|
|
||||||
onClose={() => setRulesOpen(false)}
|
|
||||||
/>
|
|
||||||
<ProxiesEditorViewer
|
|
||||||
profileUid={uid}
|
|
||||||
property={option?.proxies ?? ""}
|
|
||||||
open={proxiesOpen}
|
|
||||||
onSave={onSave}
|
|
||||||
onClose={() => setProxiesOpen(false)}
|
|
||||||
/>
|
|
||||||
<GroupsEditorViewer
|
|
||||||
mergeUid={option?.merge ?? ""}
|
|
||||||
proxiesUid={option?.proxies ?? ""}
|
|
||||||
profileUid={uid}
|
|
||||||
property={option?.groups ?? ""}
|
|
||||||
open={groupsOpen}
|
|
||||||
onSave={onSave}
|
|
||||||
onClose={() => setGroupsOpen(false)}
|
|
||||||
/>
|
|
||||||
<EditorViewer
|
|
||||||
open={mergeOpen}
|
|
||||||
initialData={readProfileFile(option?.merge ?? "")}
|
|
||||||
language="yaml"
|
|
||||||
schema="clash"
|
|
||||||
onSave={async (prev, curr) => {
|
|
||||||
await saveProfileFile(option?.merge ?? "", curr ?? "");
|
|
||||||
onSave && onSave(prev, curr);
|
|
||||||
}}
|
|
||||||
onClose={() => setMergeOpen(false)}
|
|
||||||
/>
|
|
||||||
<EditorViewer
|
|
||||||
open={scriptOpen}
|
|
||||||
initialData={readProfileFile(option?.script ?? "")}
|
|
||||||
language="javascript"
|
|
||||||
onSave={async (prev, curr) => {
|
|
||||||
await saveProfileFile(option?.script ?? "", curr ?? "");
|
|
||||||
onSave && onSave(prev, curr);
|
|
||||||
}}
|
|
||||||
onClose={() => setScriptOpen(false)}
|
|
||||||
/>
|
|
||||||
<ConfirmViewer
|
<ConfirmViewer
|
||||||
title={t("Confirm deletion")}
|
title={t("Confirm deletion")}
|
||||||
message={t("This operation is not reversible")}
|
message={t("This operation is not reversible")}
|
||||||
|
|
|
@ -167,25 +167,27 @@ export const ProfileMore = (props: Props) => {
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
{fileOpen && (
|
||||||
<EditorViewer
|
<EditorViewer
|
||||||
open={fileOpen}
|
open={true}
|
||||||
title={`${t("Global " + id)}`}
|
title={`${t("Global " + id)}`}
|
||||||
initialData={readProfileFile(id)}
|
initialData={readProfileFile(id)}
|
||||||
language={id === "Merge" ? "yaml" : "javascript"}
|
language={id === "Merge" ? "yaml" : "javascript"}
|
||||||
schema={id === "Merge" ? "clash" : undefined}
|
schema={id === "Merge" ? "clash" : undefined}
|
||||||
onSave={async (prev, curr) => {
|
onSave={async (prev, curr) => {
|
||||||
await saveProfileFile(id, curr ?? "");
|
await saveProfileFile(id, curr ?? "");
|
||||||
onSave && onSave(prev, curr);
|
onSave && onSave(prev, curr);
|
||||||
}}
|
}}
|
||||||
onClose={() => setFileOpen(false)}
|
onClose={() => setFileOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<LogViewer
|
{logOpen && (
|
||||||
open={logOpen}
|
<LogViewer
|
||||||
logInfo={logInfo}
|
open={logOpen}
|
||||||
onClose={() => setLogOpen(false)}
|
logInfo={logInfo}
|
||||||
/>
|
onClose={() => setLogOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,9 +20,10 @@ export const ConfigViewer = forwardRef<DialogRef>((_, ref) => {
|
||||||
close: () => setOpen(false),
|
close: () => setOpen(false),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (!open) return null;
|
||||||
return (
|
return (
|
||||||
<EditorViewer
|
<EditorViewer
|
||||||
open={open}
|
open={true}
|
||||||
title={
|
title={
|
||||||
<Box>
|
<Box>
|
||||||
{t("Runtime Config")}
|
{t("Runtime Config")}
|
||||||
|
|
|
@ -261,20 +261,22 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
>
|
>
|
||||||
{t("Edit")} PAC
|
{t("Edit")} PAC
|
||||||
</Button>
|
</Button>
|
||||||
<EditorViewer
|
{editorOpen && (
|
||||||
open={editorOpen}
|
<EditorViewer
|
||||||
title={`${t("Edit")} PAC`}
|
open={true}
|
||||||
initialData={Promise.resolve(value.pac_content ?? "")}
|
title={`${t("Edit")} PAC`}
|
||||||
language="javascript"
|
initialData={Promise.resolve(value.pac_content ?? "")}
|
||||||
onSave={(_prev, curr) => {
|
language="javascript"
|
||||||
let pac = DEFAULT_PAC;
|
onSave={(_prev, curr) => {
|
||||||
if (curr && curr.trim().length > 0) {
|
let pac = DEFAULT_PAC;
|
||||||
pac = curr;
|
if (curr && curr.trim().length > 0) {
|
||||||
}
|
pac = curr;
|
||||||
setValue((v) => ({ ...v, pac_content: pac }));
|
}
|
||||||
}}
|
setValue((v) => ({ ...v, pac_content: pac }));
|
||||||
onClose={() => setEditorOpen(false)}
|
}}
|
||||||
/>
|
onClose={() => setEditorOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -123,19 +123,21 @@ export const ThemeViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
>
|
>
|
||||||
{t("Edit")} CSS
|
{t("Edit")} CSS
|
||||||
</Button>
|
</Button>
|
||||||
<EditorViewer
|
{editorOpen && (
|
||||||
open={editorOpen}
|
<EditorViewer
|
||||||
title={`${t("Edit")} CSS`}
|
open={true}
|
||||||
initialData={Promise.resolve(theme.css_injection ?? "")}
|
title={`${t("Edit")} CSS`}
|
||||||
language="css"
|
initialData={Promise.resolve(theme.css_injection ?? "")}
|
||||||
onSave={(_prev, curr) => {
|
language="css"
|
||||||
theme.css_injection = curr;
|
onSave={(_prev, curr) => {
|
||||||
handleChange("css_injection");
|
theme.css_injection = curr;
|
||||||
}}
|
handleChange("css_injection");
|
||||||
onClose={() => {
|
}}
|
||||||
setEditorOpen(false);
|
onClose={() => {
|
||||||
}}
|
setEditorOpen(false);
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Item>
|
</Item>
|
||||||
</List>
|
</List>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -233,3 +233,7 @@ export async function copyIconFile(
|
||||||
export async function downloadIconCache(url: string, name: string) {
|
export async function downloadIconCache(url: string, name: string) {
|
||||||
return invoke<string>("download_icon_cache", { url, name });
|
return invoke<string>("download_icon_cache", { url, name });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getNetworkInterfaces() {
|
||||||
|
return invoke<string[]>("get_network_interfaces");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user