feat: supports edit profile file
This commit is contained in:
parent
9d44668d5f
commit
f31349eaa0
@ -25,6 +25,7 @@
|
|||||||
"axios": "^0.26.0",
|
"axios": "^0.26.0",
|
||||||
"dayjs": "^1.10.8",
|
"dayjs": "^1.10.8",
|
||||||
"i18next": "^21.6.14",
|
"i18next": "^21.6.14",
|
||||||
|
"monaco-editor": "^0.33.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-i18next": "^11.15.6",
|
"react-i18next": "^11.15.6",
|
||||||
@ -49,7 +50,8 @@
|
|||||||
"pretty-quick": "^3.1.3",
|
"pretty-quick": "^3.1.3",
|
||||||
"sass": "^1.49.7",
|
"sass": "^1.49.7",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.5.5",
|
||||||
"vite": "^2.8.6"
|
"vite": "^2.8.6",
|
||||||
|
"vite-plugin-monaco-editor": "^1.0.10"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
|
@ -212,6 +212,35 @@ pub fn view_profile(index: String, profiles_state: State<'_, ProfilesState>) ->
|
|||||||
wrap_err!(open::that(path))
|
wrap_err!(open::that(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// read the profile item file data
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn read_profile_file(
|
||||||
|
index: String,
|
||||||
|
profiles_state: State<'_, ProfilesState>,
|
||||||
|
) -> Result<String, String> {
|
||||||
|
let profiles = profiles_state.0.lock().unwrap();
|
||||||
|
let item = wrap_err!(profiles.get_item(&index))?;
|
||||||
|
let data = wrap_err!(item.read_file())?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// save the profile item file data
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn save_profile_file(
|
||||||
|
index: String,
|
||||||
|
file_data: Option<String>,
|
||||||
|
profiles_state: State<'_, ProfilesState>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
if file_data.is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let profiles = profiles_state.0.lock().unwrap();
|
||||||
|
let item = wrap_err!(profiles.get_item(&index))?;
|
||||||
|
wrap_err!(item.save_file(file_data.unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
/// restart the sidecar
|
/// restart the sidecar
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn restart_sidecar(
|
pub fn restart_sidecar(
|
||||||
|
@ -279,6 +279,28 @@ impl PrfItem {
|
|||||||
file_data: Some(tmpl::ITEM_SCRIPT.into()),
|
file_data: Some(tmpl::ITEM_SCRIPT.into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get the file data
|
||||||
|
pub fn read_file(&self) -> Result<String> {
|
||||||
|
if self.file.is_none() {
|
||||||
|
bail!("could not find the file");
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = self.file.clone().unwrap();
|
||||||
|
let path = dirs::app_profiles_dir().join(file);
|
||||||
|
fs::read_to_string(path).context("failed to read the file")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// save the file data
|
||||||
|
pub fn save_file(&self, data: String) -> Result<()> {
|
||||||
|
if self.file.is_none() {
|
||||||
|
bail!("could not find the file");
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = self.file.clone().unwrap();
|
||||||
|
let path = dirs::app_profiles_dir().join(file);
|
||||||
|
fs::write(path, data.as_bytes()).context("failed to save the file")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -118,7 +118,9 @@ fn main() -> std::io::Result<()> {
|
|||||||
cmds::get_profiles,
|
cmds::get_profiles,
|
||||||
cmds::sync_profiles,
|
cmds::sync_profiles,
|
||||||
cmds::enhance_profiles,
|
cmds::enhance_profiles,
|
||||||
cmds::change_profile_chain
|
cmds::change_profile_chain,
|
||||||
|
cmds::read_profile_file,
|
||||||
|
cmds::save_profile_file
|
||||||
]);
|
]);
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
97
src/components/profile/file-editor.tsx
Normal file
97
src/components/profile/file-editor.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import useSWR from "swr";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import { useLockFn } from "ahooks";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@mui/material";
|
||||||
|
import {
|
||||||
|
getVergeConfig,
|
||||||
|
readProfileFile,
|
||||||
|
saveProfileFile,
|
||||||
|
} from "../../services/cmds";
|
||||||
|
import Notice from "../base/base-notice";
|
||||||
|
|
||||||
|
import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js";
|
||||||
|
import "monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js";
|
||||||
|
import "monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js";
|
||||||
|
import { editor } from "monaco-editor/esm/vs/editor/editor.api";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
uid: string;
|
||||||
|
open: boolean;
|
||||||
|
mode: "yaml" | "javascript";
|
||||||
|
onClose: () => void;
|
||||||
|
onChange?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileEditor = (props: Props) => {
|
||||||
|
const { uid, open, mode, onClose, onChange } = props;
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const editorRef = useRef<any>();
|
||||||
|
const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
|
||||||
|
const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig);
|
||||||
|
const { theme_mode } = vergeConfig ?? {};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
|
||||||
|
readProfileFile(uid).then((data) => {
|
||||||
|
const dom = editorRef.current;
|
||||||
|
|
||||||
|
if (!dom) return;
|
||||||
|
if (instanceRef.current) instanceRef.current.dispose();
|
||||||
|
|
||||||
|
instanceRef.current = editor.create(editorRef.current, {
|
||||||
|
value: data,
|
||||||
|
language: mode,
|
||||||
|
theme: theme_mode === "light" ? "vs" : "vs-dark",
|
||||||
|
minimap: { enabled: false },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (instanceRef.current) {
|
||||||
|
instanceRef.current.dispose();
|
||||||
|
instanceRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
|
const onSave = useLockFn(async () => {
|
||||||
|
const value = instanceRef.current?.getValue();
|
||||||
|
|
||||||
|
if (value == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await saveProfileFile(uid, value);
|
||||||
|
onChange?.();
|
||||||
|
} catch (err: any) {
|
||||||
|
Notice.error(err.message || err.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onClose={onClose}>
|
||||||
|
<DialogTitle>{t("Edit File")}</DialogTitle>
|
||||||
|
|
||||||
|
<DialogContent sx={{ width: 520, pb: 1 }}>
|
||||||
|
<div style={{ width: "100%", height: "420px" }} ref={editorRef} />
|
||||||
|
</DialogContent>
|
||||||
|
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose}>{t("Cancel")}</Button>
|
||||||
|
<Button onClick={onSave} variant="contained">
|
||||||
|
{t("Save")}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FileEditor;
|
@ -21,6 +21,7 @@ import { atomLoadingCache } from "../../services/states";
|
|||||||
import { updateProfile, deleteProfile, viewProfile } from "../../services/cmds";
|
import { updateProfile, deleteProfile, viewProfile } from "../../services/cmds";
|
||||||
import parseTraffic from "../../utils/parse-traffic";
|
import parseTraffic from "../../utils/parse-traffic";
|
||||||
import ProfileEdit from "./profile-edit";
|
import ProfileEdit from "./profile-edit";
|
||||||
|
import FileEditor from "./file-editor";
|
||||||
import Notice from "../base/base-notice";
|
import Notice from "../base/base-notice";
|
||||||
|
|
||||||
const Wrapper = styled(Box)(({ theme }) => ({
|
const Wrapper = styled(Box)(({ theme }) => ({
|
||||||
@ -54,7 +55,7 @@ const ProfileItem = (props: Props) => {
|
|||||||
const [position, setPosition] = useState({ left: 0, top: 0 });
|
const [position, setPosition] = useState({ left: 0, top: 0 });
|
||||||
const [loadingCache, setLoadingCache] = useRecoilState(atomLoadingCache);
|
const [loadingCache, setLoadingCache] = useRecoilState(atomLoadingCache);
|
||||||
|
|
||||||
const { name = "Profile", extra, updated = 0 } = itemData;
|
const { uid, name = "Profile", extra, updated = 0 } = itemData;
|
||||||
const { upload = 0, download = 0, total = 0 } = extra ?? {};
|
const { upload = 0, download = 0, total = 0 } = extra ?? {};
|
||||||
const from = parseUrl(itemData.url);
|
const from = parseUrl(itemData.url);
|
||||||
const expire = parseExpire(extra?.expire);
|
const expire = parseExpire(extra?.expire);
|
||||||
@ -70,18 +71,16 @@ const ProfileItem = (props: Props) => {
|
|||||||
const loading = loadingCache[itemData.uid] ?? false;
|
const loading = loadingCache[itemData.uid] ?? false;
|
||||||
|
|
||||||
const [editOpen, setEditOpen] = useState(false);
|
const [editOpen, setEditOpen] = useState(false);
|
||||||
const onEdit = () => {
|
const [fileOpen, setFileOpen] = useState(false);
|
||||||
|
|
||||||
|
const onEditInfo = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
setEditOpen(true);
|
setEditOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onView = async () => {
|
const onEditFile = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
try {
|
setFileOpen(true);
|
||||||
await viewProfile(itemData.uid);
|
|
||||||
} catch (err: any) {
|
|
||||||
Notice.error(err?.message || err.toString());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onForceSelect = () => {
|
const onForceSelect = () => {
|
||||||
@ -89,6 +88,15 @@ const ProfileItem = (props: Props) => {
|
|||||||
onSelect(true);
|
onSelect(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onOpenFile = useLockFn(async () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
try {
|
||||||
|
await viewProfile(itemData.uid);
|
||||||
|
} catch (err: any) {
|
||||||
|
Notice.error(err?.message || err.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const onUpdate = useLockFn(async (withProxy: boolean) => {
|
const onUpdate = useLockFn(async (withProxy: boolean) => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
setLoadingCache((cache) => ({ ...cache, [itemData.uid]: true }));
|
setLoadingCache((cache) => ({ ...cache, [itemData.uid]: true }));
|
||||||
@ -122,16 +130,18 @@ const ProfileItem = (props: Props) => {
|
|||||||
|
|
||||||
const urlModeMenu = [
|
const urlModeMenu = [
|
||||||
{ label: "Select", handler: onForceSelect },
|
{ label: "Select", handler: onForceSelect },
|
||||||
{ label: "Edit", handler: onEdit },
|
{ label: "Edit Info", handler: onEditInfo },
|
||||||
{ label: "File", handler: onView },
|
{ label: "Edit File", handler: onEditFile },
|
||||||
|
{ label: "Open File", handler: onOpenFile },
|
||||||
{ label: "Update", handler: () => onUpdate(false) },
|
{ label: "Update", handler: () => onUpdate(false) },
|
||||||
{ label: "Update(Proxy)", handler: () => onUpdate(true) },
|
{ label: "Update(Proxy)", handler: () => onUpdate(true) },
|
||||||
{ label: "Delete", handler: onDelete },
|
{ label: "Delete", handler: onDelete },
|
||||||
];
|
];
|
||||||
const fileModeMenu = [
|
const fileModeMenu = [
|
||||||
{ label: "Select", handler: onForceSelect },
|
{ label: "Select", handler: onForceSelect },
|
||||||
{ label: "Edit", handler: onEdit },
|
{ label: "Edit Info", handler: onEditInfo },
|
||||||
{ label: "File", handler: onView },
|
{ label: "Edit File", handler: onEditFile },
|
||||||
|
{ label: "Open File", handler: onOpenFile },
|
||||||
{ label: "Delete", handler: onDelete },
|
{ label: "Delete", handler: onDelete },
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -256,6 +266,7 @@ const ProfileItem = (props: Props) => {
|
|||||||
onClose={() => setAnchorEl(null)}
|
onClose={() => setAnchorEl(null)}
|
||||||
anchorPosition={position}
|
anchorPosition={position}
|
||||||
anchorReference="anchorPosition"
|
anchorReference="anchorPosition"
|
||||||
|
transitionDuration={225}
|
||||||
onContextMenu={(e) => {
|
onContextMenu={(e) => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -279,6 +290,15 @@ const ProfileItem = (props: Props) => {
|
|||||||
onClose={() => setEditOpen(false)}
|
onClose={() => setEditOpen(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{fileOpen && (
|
||||||
|
<FileEditor
|
||||||
|
uid={uid}
|
||||||
|
open={fileOpen}
|
||||||
|
mode="yaml"
|
||||||
|
onClose={() => setFileOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useLockFn } from "ahooks";
|
||||||
import {
|
import {
|
||||||
alpha,
|
alpha,
|
||||||
Box,
|
Box,
|
||||||
@ -12,9 +13,10 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { CmdType } from "../../services/types";
|
import { CmdType } from "../../services/types";
|
||||||
import { viewProfile } from "../../services/cmds";
|
import { viewProfile } from "../../services/cmds";
|
||||||
import ProfileEdit from "./profile-edit";
|
|
||||||
import Notice from "../base/base-notice";
|
|
||||||
import enhance from "../../services/enhance";
|
import enhance from "../../services/enhance";
|
||||||
|
import ProfileEdit from "./profile-edit";
|
||||||
|
import FileEditor from "./file-editor";
|
||||||
|
import Notice from "../base/base-notice";
|
||||||
|
|
||||||
const Wrapper = styled(Box)(({ theme }) => ({
|
const Wrapper = styled(Box)(({ theme }) => ({
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@ -57,6 +59,7 @@ const ProfileMore = (props: Props) => {
|
|||||||
const [anchorEl, setAnchorEl] = useState<any>(null);
|
const [anchorEl, setAnchorEl] = useState<any>(null);
|
||||||
const [position, setPosition] = useState({ left: 0, top: 0 });
|
const [position, setPosition] = useState({ left: 0, top: 0 });
|
||||||
const [editOpen, setEditOpen] = useState(false);
|
const [editOpen, setEditOpen] = useState(false);
|
||||||
|
const [fileOpen, setFileOpen] = useState(false);
|
||||||
const [status, setStatus] = useState(enhance.status(uid));
|
const [status, setStatus] = useState(enhance.status(uid));
|
||||||
|
|
||||||
// unlisten when unmount
|
// unlisten when unmount
|
||||||
@ -65,40 +68,47 @@ const ProfileMore = (props: Props) => {
|
|||||||
// error during enhanced mode
|
// error during enhanced mode
|
||||||
const hasError = selected && status?.status === "error";
|
const hasError = selected && status?.status === "error";
|
||||||
|
|
||||||
const onEdit = () => {
|
const onEditInfo = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
setEditOpen(true);
|
setEditOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onView = async () => {
|
const onEditFile = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
setFileOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onOpenFile = useLockFn(async () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
try {
|
try {
|
||||||
await viewProfile(itemData.uid);
|
await viewProfile(itemData.uid);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
Notice.error(err?.message || err.toString());
|
Notice.error(err?.message || err.toString());
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const closeWrapper = (fn: () => void) => () => {
|
const fnWrapper = (fn: () => void) => () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
return fn();
|
return fn();
|
||||||
};
|
};
|
||||||
|
|
||||||
const enableMenu = [
|
const enableMenu = [
|
||||||
{ label: "Disable", handler: closeWrapper(onDisable) },
|
{ label: "Disable", handler: fnWrapper(onDisable) },
|
||||||
{ label: "Refresh", handler: closeWrapper(onEnhance) },
|
{ label: "Refresh", handler: fnWrapper(onEnhance) },
|
||||||
{ label: "Edit", handler: onEdit },
|
{ label: "Edit Info", handler: onEditInfo },
|
||||||
{ label: "File", handler: onView },
|
{ label: "Edit File", handler: onEditFile },
|
||||||
{ label: "To Top", show: !hasError, handler: closeWrapper(onMoveTop) },
|
{ label: "Open File", handler: onOpenFile },
|
||||||
{ label: "To End", show: !hasError, handler: closeWrapper(onMoveEnd) },
|
{ label: "To Top", show: !hasError, handler: fnWrapper(onMoveTop) },
|
||||||
{ label: "Delete", handler: closeWrapper(onDelete) },
|
{ label: "To End", show: !hasError, handler: fnWrapper(onMoveEnd) },
|
||||||
|
{ label: "Delete", handler: fnWrapper(onDelete) },
|
||||||
];
|
];
|
||||||
|
|
||||||
const disableMenu = [
|
const disableMenu = [
|
||||||
{ label: "Enable", handler: closeWrapper(onEnable) },
|
{ label: "Enable", handler: fnWrapper(onEnable) },
|
||||||
{ label: "Edit", handler: onEdit },
|
{ label: "Edit Info", handler: onEditInfo },
|
||||||
{ label: "File", handler: onView },
|
{ label: "Edit File", handler: onEditFile },
|
||||||
{ label: "Delete", handler: closeWrapper(onDelete) },
|
{ label: "Open File", handler: onOpenFile },
|
||||||
|
{ label: "Delete", handler: fnWrapper(onDelete) },
|
||||||
];
|
];
|
||||||
|
|
||||||
const boxStyle = {
|
const boxStyle = {
|
||||||
@ -208,6 +218,7 @@ const ProfileMore = (props: Props) => {
|
|||||||
onClose={() => setAnchorEl(null)}
|
onClose={() => setAnchorEl(null)}
|
||||||
anchorPosition={position}
|
anchorPosition={position}
|
||||||
anchorReference="anchorPosition"
|
anchorReference="anchorPosition"
|
||||||
|
transitionDuration={225}
|
||||||
onContextMenu={(e) => {
|
onContextMenu={(e) => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -233,6 +244,15 @@ const ProfileMore = (props: Props) => {
|
|||||||
onClose={() => setEditOpen(false)}
|
onClose={() => setEditOpen(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{fileOpen && (
|
||||||
|
<FileEditor
|
||||||
|
uid={uid}
|
||||||
|
open={fileOpen}
|
||||||
|
mode={type === "merge" ? "yaml" : "javascript"}
|
||||||
|
onClose={() => setFileOpen(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
"New": "New",
|
"New": "New",
|
||||||
"Close All": "Close All",
|
"Close All": "Close All",
|
||||||
"Select": "Select",
|
"Select": "Select",
|
||||||
"Edit": "Edit",
|
"Edit Info": "Edit Info",
|
||||||
"File": "File",
|
"Edit File": "Edit File",
|
||||||
|
"Open File": "Open File",
|
||||||
"Update": "Update",
|
"Update": "Update",
|
||||||
"Update(Proxy)": "Update(Proxy)",
|
"Update(Proxy)": "Update(Proxy)",
|
||||||
"Delete": "Delete",
|
"Delete": "Delete",
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"Clash core": "Clash core",
|
"Clash core": "Clash core",
|
||||||
"Tun Mode": "Tun Mode",
|
"Tun Mode": "Tun Mode",
|
||||||
"Auto Launch": "Auto Launch",
|
"Auto Launch": "Auto Launch",
|
||||||
|
"Silent Start": "Silent Start",
|
||||||
"System Proxy": "System Proxy",
|
"System Proxy": "System Proxy",
|
||||||
"Proxy Guard": "Proxy Guard",
|
"Proxy Guard": "Proxy Guard",
|
||||||
"Proxy Bypass": "Proxy Bypass",
|
"Proxy Bypass": "Proxy Bypass",
|
||||||
@ -50,5 +52,8 @@
|
|||||||
"Language": "Language",
|
"Language": "Language",
|
||||||
"Open App Dir": "Open App Dir",
|
"Open App Dir": "Open App Dir",
|
||||||
"Open Logs Dir": "Open Logs Dir",
|
"Open Logs Dir": "Open Logs Dir",
|
||||||
"Version": "Version"
|
"Version": "Version",
|
||||||
|
|
||||||
|
"Save": "Save",
|
||||||
|
"Cancel": "Cancel"
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
"New": "新建",
|
"New": "新建",
|
||||||
"Close All": "关闭全部",
|
"Close All": "关闭全部",
|
||||||
"Select": "使用",
|
"Select": "使用",
|
||||||
"Edit": "编辑信息",
|
"Edit Info": "编辑信息",
|
||||||
"File": "打开文件",
|
"Edit File": "编辑文件",
|
||||||
|
"Open File": "打开文件",
|
||||||
"Update": "更新",
|
"Update": "更新",
|
||||||
"Update(Proxy)": "更新(代理)",
|
"Update(Proxy)": "更新(代理)",
|
||||||
"Delete": "删除",
|
"Delete": "删除",
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"Clash core": "Clash 内核",
|
"Clash core": "Clash 内核",
|
||||||
"Tun Mode": "Tun 模式",
|
"Tun Mode": "Tun 模式",
|
||||||
"Auto Launch": "开机自启",
|
"Auto Launch": "开机自启",
|
||||||
|
"Silent Start": "静默启动",
|
||||||
"System Proxy": "系统代理",
|
"System Proxy": "系统代理",
|
||||||
"Proxy Guard": "系统代理守卫",
|
"Proxy Guard": "系统代理守卫",
|
||||||
"Proxy Bypass": "Proxy Bypass",
|
"Proxy Bypass": "Proxy Bypass",
|
||||||
@ -50,5 +52,8 @@
|
|||||||
"Language": "语言设置",
|
"Language": "语言设置",
|
||||||
"Open App Dir": "应用目录",
|
"Open App Dir": "应用目录",
|
||||||
"Open Logs Dir": "日志目录",
|
"Open Logs Dir": "日志目录",
|
||||||
"Version": "版本"
|
"Version": "版本",
|
||||||
|
|
||||||
|
"Save": "保存",
|
||||||
|
"Cancel": "取消"
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,14 @@ export async function viewProfile(index: string) {
|
|||||||
return invoke<void>("view_profile", { index });
|
return invoke<void>("view_profile", { index });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function readProfileFile(index: string) {
|
||||||
|
return invoke<string>("read_profile_file", { index });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveProfileFile(index: string, fileData: string) {
|
||||||
|
return invoke<void>("save_profile_file", { index, fileData });
|
||||||
|
}
|
||||||
|
|
||||||
export async function importProfile(url: string) {
|
export async function importProfile(url: string) {
|
||||||
return invoke<void>("import_profile", {
|
return invoke<void>("import_profile", {
|
||||||
url,
|
url,
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import react from "@vitejs/plugin-react";
|
import react from "@vitejs/plugin-react";
|
||||||
|
import monaco from "vite-plugin-monaco-editor";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
root: "src",
|
root: "src",
|
||||||
plugins: [react()],
|
plugins: [react(), monaco()],
|
||||||
build: {
|
build: {
|
||||||
outDir: "../dist",
|
outDir: "../dist",
|
||||||
emptyOutDir: true,
|
emptyOutDir: true,
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -1476,6 +1476,11 @@ minimist@^1.2.5:
|
|||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||||
|
|
||||||
|
monaco-editor@^0.33.0:
|
||||||
|
version "0.33.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.33.0.tgz#842e244f3750a2482f8a29c676b5684e75ff34af"
|
||||||
|
integrity sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==
|
||||||
|
|
||||||
mri@^1.1.5:
|
mri@^1.1.5:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
|
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
|
||||||
@ -1922,6 +1927,11 @@ universalify@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
||||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||||
|
|
||||||
|
vite-plugin-monaco-editor@^1.0.10:
|
||||||
|
version "1.0.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.0.10.tgz#cd370f68d4121bced6f902c6284649cc8eca4170"
|
||||||
|
integrity sha512-7yTAFIE0SefjCmfnjrvXOl53wkxeSASc/ZIcB5tZeEK3vAmHhveV8y3f90Vp8b+PYdbUipjqf91mbFbSENkpcw==
|
||||||
|
|
||||||
vite@^2.8.6:
|
vite@^2.8.6:
|
||||||
version "2.8.6"
|
version "2.8.6"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-2.8.6.tgz#32d50e23c99ca31b26b8ccdc78b1d72d4d7323d3"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-2.8.6.tgz#32d50e23c99ca31b26b8ccdc78b1d72d4d7323d3"
|
||||||
|
Loading…
Reference in New Issue
Block a user