mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 03:32:36 +08:00
feat: support new profile
This commit is contained in:
parent
6082c2bcac
commit
c53fe0ed1f
|
@ -43,6 +43,42 @@ pub async fn import_profile(
|
|||
}
|
||||
}
|
||||
|
||||
/// new a profile
|
||||
/// append a temp profile item file to the `profiles` dir
|
||||
/// view the temp profile file by using vscode or other editor
|
||||
#[tauri::command]
|
||||
pub async fn new_profile(
|
||||
name: String,
|
||||
desc: String,
|
||||
profiles_state: State<'_, ProfilesState>,
|
||||
) -> Result<(), String> {
|
||||
let mut profiles = profiles_state.0.lock().unwrap();
|
||||
|
||||
let (_, path) = profiles.append_item(name, desc)?;
|
||||
|
||||
if !path.exists() {
|
||||
return Err("the file not found".into());
|
||||
}
|
||||
|
||||
// use vscode first
|
||||
if let Ok(code) = which::which("code") {
|
||||
return match Command::new(code).arg(path).status() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err("failed to open file by VScode".into()),
|
||||
};
|
||||
}
|
||||
|
||||
// use `open` command
|
||||
if let Ok(open) = which::which("open") {
|
||||
return match Command::new(open).arg(path).status() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err("failed to open file by `open`".into()),
|
||||
};
|
||||
}
|
||||
|
||||
return Err("failed to open the file, please edit the file manually".into());
|
||||
}
|
||||
|
||||
/// Update the profile
|
||||
#[tauri::command]
|
||||
pub async fn update_profile(
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::collections::HashMap;
|
|||
use std::env::temp_dir;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// Define the `profiles.yaml` schema
|
||||
|
@ -23,6 +24,8 @@ pub struct Profiles {
|
|||
pub struct ProfileItem {
|
||||
/// profile name
|
||||
pub name: Option<String>,
|
||||
/// profile description
|
||||
pub desc: Option<String>,
|
||||
/// profile file
|
||||
pub file: Option<String>,
|
||||
/// current mode
|
||||
|
@ -109,6 +112,7 @@ impl Profiles {
|
|||
|
||||
items.push(ProfileItem {
|
||||
name: Some(result.name),
|
||||
desc: Some("imported url".into()),
|
||||
file: Some(result.file),
|
||||
mode: Some(format!("rule")),
|
||||
url: Some(url),
|
||||
|
@ -138,6 +142,49 @@ impl Profiles {
|
|||
self.save_file()
|
||||
}
|
||||
|
||||
/// append new item
|
||||
/// return the new item's index
|
||||
pub fn append_item(&mut self, name: String, desc: String) -> Result<(usize, PathBuf), String> {
|
||||
let mut items = self.items.take().unwrap_or(vec![]);
|
||||
|
||||
// create a new profile file
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
let file = format!("{}.yaml", now);
|
||||
let path = dirs::app_home_dir().join("profiles").join(&file);
|
||||
|
||||
let file_data = b"# Profile Template for clash verge\n
|
||||
# proxies defination (optional, the same as clash)
|
||||
proxies:\n
|
||||
# proxy-groups (optional, the same as clash)
|
||||
proxy-groups:\n
|
||||
# rules (optional, the same as clash)
|
||||
rules:\n\n
|
||||
";
|
||||
|
||||
match File::create(&path).unwrap().write(file_data) {
|
||||
Ok(_) => {
|
||||
items.push(ProfileItem {
|
||||
name: Some(name),
|
||||
desc: Some(desc),
|
||||
file: Some(file),
|
||||
mode: None,
|
||||
url: None,
|
||||
selected: Some(vec![]),
|
||||
extra: None,
|
||||
updated: Some(now as usize),
|
||||
});
|
||||
|
||||
let index = items.len();
|
||||
self.items = Some(items);
|
||||
Ok((index, path))
|
||||
}
|
||||
Err(_) => Err("failed to create file".into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// update the target profile
|
||||
/// and save to config file
|
||||
/// only support the url item
|
||||
|
|
|
@ -81,6 +81,7 @@ fn main() -> std::io::Result<()> {
|
|||
cmds::get_verge_config,
|
||||
cmds::patch_verge_config,
|
||||
// profile
|
||||
cmds::new_profile,
|
||||
cmds::view_profile,
|
||||
cmds::patch_profile,
|
||||
cmds::import_profile,
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
selectProfile,
|
||||
patchProfile,
|
||||
importProfile,
|
||||
newProfile,
|
||||
} from "../services/cmds";
|
||||
import { getProxies, updateProxy } from "../services/api";
|
||||
import noop from "../utils/noop";
|
||||
|
@ -94,6 +95,21 @@ const ProfilePage = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const lockNewRef = useRef(false);
|
||||
const onNew = async () => {
|
||||
if (lockNewRef.current) return;
|
||||
lockNewRef.current = true;
|
||||
|
||||
try {
|
||||
await newProfile("New Profile", "no desc");
|
||||
mutate("getProfiles");
|
||||
} catch (err: any) {
|
||||
err && Notice.error(err.toString());
|
||||
} finally {
|
||||
lockNewRef.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<BasePage title="Profiles">
|
||||
<Box sx={{ display: "flex", mb: 3 }}>
|
||||
|
@ -105,15 +121,19 @@ const ProfilePage = () => {
|
|||
fullWidth
|
||||
value={url}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
sx={{ mr: 2 }}
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
<Button
|
||||
disabled={!url || disabled}
|
||||
variant="contained"
|
||||
onClick={onImport}
|
||||
sx={{ mr: 1 }}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Button variant="contained" onClick={onNew}>
|
||||
New
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
|
|
|
@ -9,6 +9,10 @@ export async function syncProfiles() {
|
|||
return invoke<void>("sync_profiles");
|
||||
}
|
||||
|
||||
export async function newProfile(name: string, desc: string) {
|
||||
return invoke<void>("new_profile", { name, desc });
|
||||
}
|
||||
|
||||
export async function viewProfile(index: number) {
|
||||
return invoke<void>("view_profile", { index });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user