Fixed an issue with adding a profile when making changes in advanced settings.

This commit is contained in:
coolcoala
2025-08-23 03:03:07 +03:00
parent 25f5db82dc
commit 00cee81812
6 changed files with 99 additions and 18 deletions

View File

@@ -164,7 +164,16 @@ pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult
url
);
let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
wrap_err!(Config::profiles().data().append_item(item))
let new_uid = item.uid.clone().unwrap_or_default();
wrap_err!(Config::profiles().data().append_item(item))?;
if !new_uid.is_empty() {
let _ = patch_profiles_config(IProfiles {
current: Some(new_uid),
items: None,
})
.await?;
}
Ok(())
}
}
@@ -178,7 +187,17 @@ pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult {
#[tauri::command]
pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResult {
let item = wrap_err!(PrfItem::from(item, file_data).await)?;
wrap_err!(Config::profiles().data().append_item(item))
let new_uid = item.uid.clone().unwrap_or_default();
wrap_err!(Config::profiles().data().append_item(item))?;
if !new_uid.is_empty() {
let _ = patch_profiles_config(IProfiles {
current: Some(new_uid),
items: None,
})
.await?;
}
Ok(())
}
/// 更新配置文件

View File

@@ -504,13 +504,23 @@ impl PrfItem {
selected: None,
extra,
option: Some(PrfOption {
user_agent: user_agent.clone(),
with_proxy: if with_proxy { Some(true) } else { None },
self_proxy: if self_proxy { Some(true) } else { None },
update_interval,
update_always,
timeout_seconds: Some(timeout),
danger_accept_invalid_certs: if accept_invalid_certs {
Some(true)
} else {
None
},
merge,
script,
rules,
proxies,
groups,
use_hwid: Some(use_hwid),
..PrfOption::default()
}),
home,

View File

@@ -136,10 +136,9 @@ impl IProfiles {
.with_context(|| format!("failed to write to file \"{file}\""))?;
}
if self.current.is_none()
&& (item.itype == Some("remote".to_string()) || item.itype == Some("local".to_string()))
{
self.current = uid;
if item.itype == Some("remote".to_string()) || item.itype == Some("local".to_string()) {
// Always switch current to the newly created remote/local profile
self.current = uid.clone();
}
if self.items.is_none() {

View File

@@ -14,6 +14,7 @@ import {
importProfile,
enhanceProfiles,
createProfileFromShareLink,
getProfiles,
} from "@/services/cmds";
import { useProfiles } from "@/hooks/use-profiles";
import { showNotice } from "@/services/noticeService";
@@ -65,7 +66,7 @@ export const ProfileViewer = forwardRef<ProfileViewerRef, Props>(
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const [openType, setOpenType] = useState<"new" | "edit">("new");
const { profiles } = useProfiles();
const { profiles, patchProfiles } = useProfiles();
const fileDataRef = useRef<string | null>(null);
const [showAdvanced, setShowAdvanced] = useState(false);
@@ -210,33 +211,81 @@ export const ProfileViewer = forwardRef<ProfileViewerRef, Props>(
const handleSaveAdvanced = useLockFn(
handleSubmit(async (formData) => {
const form = { ...formData, url: formData.url || importUrl };
const form = { ...formData, url: formData.url || importUrl } as Partial<IProfileItem>;
setLoading(true);
try {
if (!form.type) throw new Error("`Type` should not be null");
if (form.type === "remote" && !form.url)
throw new Error("The URL should not be null");
if (form.option?.update_interval)
form.option.update_interval = +form.option.update_interval;
else delete form.option?.update_interval;
if (form.option?.user_agent === "") delete form.option.user_agent;
const name = form.name || `${form.type} file`;
const item = { ...form, name };
// Clean option fields: only send what user actually set
let option = form.option ? { ...form.option } : undefined;
if (option) {
if ((option as any).update_interval != null && (option as any).update_interval !== "") {
// ensure number
(option as any).update_interval = +((option as any).update_interval as any);
} else {
delete (option as any).update_interval;
}
if (typeof option.user_agent === "string" && option.user_agent.trim() === "") {
delete (option as any).user_agent;
}
}
const providedName = (form as any).name && String((form as any).name).trim();
const providedDesc = (form as any).desc && String((form as any).desc).trim();
const item: Partial<IProfileItem> = {
...form,
// Only include name/desc when user explicitly entered them
name: providedName ? (providedName as string) : undefined,
desc: providedDesc ? (providedDesc as string) : undefined,
option,
};
const isUpdate = openType === "edit";
const isActivating =
isUpdate && form.uid === (profiles?.current ?? "");
const wasCurrent = isUpdate && form.uid === (profiles?.current ?? "");
if (openType === "new") {
// Detect newly created profile and activate it explicitly
const before = await getProfiles().catch(() => null);
const beforeUids = new Set(
(before?.items || []).map((i: any) => i?.uid).filter(Boolean),
);
await createProfile(item, fileDataRef.current);
const after = await getProfiles().catch(() => null);
const newRemoteLocal = (after?.items || []).find(
(i: any) =>
i &&
(i.type === "remote" || i.type === "local") &&
i.uid &&
!beforeUids.has(i.uid),
);
const newUid = (newRemoteLocal && newRemoteLocal.uid) as
| string
| undefined;
if (newUid) {
try {
await patchProfiles({ current: newUid });
} catch {}
}
showNotice("success", t("Profile Created Successfully"));
setOpen(false);
props.onChange(true);
return;
} else {
if (!form.uid) throw new Error("UID not found");
await patchProfile(form.uid, item);
await patchProfile(form.uid as string, item);
showNotice("success", t("Profile Updated Successfully"));
}
setOpen(false);
props.onChange(isActivating);
props.onChange(wasCurrent);
} catch (err: any) {
showNotice("error", err.message || err.toString());
} finally {

View File

@@ -392,6 +392,8 @@
"Profile Imported Successfully": "Profile Imported Successfully",
"Profile Switched": "Profile Switched",
"Profile Reactivated": "Profile Reactivated",
"Profile Created Successfully": "Profile created successfully",
"Profile Updated Successfully": "Profile updated successfully",
"Profile switch interrupted by new selection": "Profile switch interrupted by new selection",
"Only YAML Files Supported": "Only YAML Files Supported",
"Settings Applied": "Settings Applied",

View File

@@ -392,6 +392,8 @@
"Profile Imported Successfully": "Профиль успешно импортирован",
"Profile Switched": "Профиль изменен",
"Profile Reactivated": "Профиль перезапущен",
"Profile Created Successfully": "Профиль успешно создан",
"Profile Updated Successfully": "Профиль успешно обновлён",
"Profile switch interrupted by new selection": "Переключение профилей прервано новым выбором",
"Only YAML Files Supported": "Поддерживаются только файлы YAML",
"Settings Applied": "Настройки применены",