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
|
/// Update the profile
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn update_profile(
|
pub async fn update_profile(
|
||||||
|
@ -7,6 +7,7 @@ use std::collections::HashMap;
|
|||||||
use std::env::temp_dir;
|
use std::env::temp_dir;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
/// Define the `profiles.yaml` schema
|
/// Define the `profiles.yaml` schema
|
||||||
@ -23,6 +24,8 @@ pub struct Profiles {
|
|||||||
pub struct ProfileItem {
|
pub struct ProfileItem {
|
||||||
/// profile name
|
/// profile name
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
/// profile description
|
||||||
|
pub desc: Option<String>,
|
||||||
/// profile file
|
/// profile file
|
||||||
pub file: Option<String>,
|
pub file: Option<String>,
|
||||||
/// current mode
|
/// current mode
|
||||||
@ -109,6 +112,7 @@ impl Profiles {
|
|||||||
|
|
||||||
items.push(ProfileItem {
|
items.push(ProfileItem {
|
||||||
name: Some(result.name),
|
name: Some(result.name),
|
||||||
|
desc: Some("imported url".into()),
|
||||||
file: Some(result.file),
|
file: Some(result.file),
|
||||||
mode: Some(format!("rule")),
|
mode: Some(format!("rule")),
|
||||||
url: Some(url),
|
url: Some(url),
|
||||||
@ -138,6 +142,49 @@ impl Profiles {
|
|||||||
self.save_file()
|
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
|
/// update the target profile
|
||||||
/// and save to config file
|
/// and save to config file
|
||||||
/// only support the url item
|
/// only support the url item
|
||||||
|
@ -81,6 +81,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
cmds::get_verge_config,
|
cmds::get_verge_config,
|
||||||
cmds::patch_verge_config,
|
cmds::patch_verge_config,
|
||||||
// profile
|
// profile
|
||||||
|
cmds::new_profile,
|
||||||
cmds::view_profile,
|
cmds::view_profile,
|
||||||
cmds::patch_profile,
|
cmds::patch_profile,
|
||||||
cmds::import_profile,
|
cmds::import_profile,
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
selectProfile,
|
selectProfile,
|
||||||
patchProfile,
|
patchProfile,
|
||||||
importProfile,
|
importProfile,
|
||||||
|
newProfile,
|
||||||
} from "../services/cmds";
|
} from "../services/cmds";
|
||||||
import { getProxies, updateProxy } from "../services/api";
|
import { getProxies, updateProxy } from "../services/api";
|
||||||
import noop from "../utils/noop";
|
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 (
|
return (
|
||||||
<BasePage title="Profiles">
|
<BasePage title="Profiles">
|
||||||
<Box sx={{ display: "flex", mb: 3 }}>
|
<Box sx={{ display: "flex", mb: 3 }}>
|
||||||
@ -105,15 +121,19 @@ const ProfilePage = () => {
|
|||||||
fullWidth
|
fullWidth
|
||||||
value={url}
|
value={url}
|
||||||
onChange={(e) => setUrl(e.target.value)}
|
onChange={(e) => setUrl(e.target.value)}
|
||||||
sx={{ mr: 2 }}
|
sx={{ mr: 1 }}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
disabled={!url || disabled}
|
disabled={!url || disabled}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={onImport}
|
onClick={onImport}
|
||||||
|
sx={{ mr: 1 }}
|
||||||
>
|
>
|
||||||
Import
|
Import
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button variant="contained" onClick={onNew}>
|
||||||
|
New
|
||||||
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
|
@ -9,6 +9,10 @@ export async function syncProfiles() {
|
|||||||
return invoke<void>("sync_profiles");
|
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) {
|
export async function viewProfile(index: number) {
|
||||||
return invoke<void>("view_profile", { index });
|
return invoke<void>("view_profile", { index });
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user