feat: support new profile

This commit is contained in:
GyDi 2022-02-07 17:26:05 +08:00
parent 6082c2bcac
commit c53fe0ed1f
No known key found for this signature in database
GPG Key ID: 58B15242BA8277A6
5 changed files with 109 additions and 1 deletions

View File

@ -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(

View File

@ -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

View File

@ -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,

View File

@ -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}>

View File

@ -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 });
} }