mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-10-06 13:44:21 +08:00
CA 适配: - 移除 CA 模块对 macOS/Windows 的硬性限制,Linux 走完整初始化流程 - 按发行版自动选择安装命令:Debian 系 update-ca-certificates, Fedora/RHEL/Arch 系 update-ca-trust extract;已安装检测比对信任锚文件 - 删除不可达的 CaState::Unsupported 分支及前端"请使用 macOS 或 Windows"提示 静默启动(参考 cc-switch 实现逻辑): - 新增 DesktopSettings 持久化(service_settings 表)及 GET/PUT /api/settings/desktop - 主窗口统一以 visible(false) 创建,启动时读取配置决定是否显示 - 应用设置页:开启"开机启动"后显示"静默启动"子开关 安全修复: - ProviderEndpoint.api_key 增加 serde(skip_serializing), 避免明文 API Key 随 JSON 响应泄漏(provider_console 测试恢复通过) 其他: - Linux 补齐 open_terminal_with_command:按序探测 x-terminal-emulator / gnome-terminal / konsole 等并在新终端窗口执行命令 - "打开终端安装 CA"失败信息不再被前端静默吞掉 - 顺手修复上游遗留问题:desktop.rs 未使用导入、output.rs 测试模块位置、providers.rs 格式
129 lines
4.5 KiB
TypeScript
129 lines
4.5 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import {
|
|
currentAppVersion,
|
|
hasNativeAppLifecycle,
|
|
readAutostart,
|
|
readSilentStart,
|
|
writeAutostart,
|
|
writeSilentStart,
|
|
} from "../../native/appLifecycle";
|
|
import { updateStore, useUpdateStore } from "../../store/updateStore";
|
|
import { Button } from "../ui/Button";
|
|
import { Switch } from "../ui/Switch";
|
|
import { TitledCard } from "../ui/TitledCard";
|
|
import { useMessage } from "../ui/message";
|
|
import styles from "./AppLifecycleSettingsCard.module.scss";
|
|
|
|
export function AppLifecycleSettingsCard() {
|
|
const message = useMessage();
|
|
const native = hasNativeAppLifecycle();
|
|
const { availableVersion, checking, installing } = useUpdateStore();
|
|
const [version, setVersion] = useState("…");
|
|
const [autostart, setAutostart] = useState(false);
|
|
const [loadingAutostart, setLoadingAutostart] = useState(native);
|
|
const [silentStart, setSilentStart] = useState(false);
|
|
const [loadingSilentStart, setLoadingSilentStart] = useState(native);
|
|
|
|
useEffect(() => {
|
|
let disposed = false;
|
|
void currentAppVersion().then((next) => { if (!disposed) setVersion(next); });
|
|
if (native) {
|
|
void readAutostart()
|
|
.then((enabled) => { if (!disposed) setAutostart(enabled); })
|
|
.catch((cause) => message(cause instanceof Error ? cause.message : String(cause)))
|
|
.finally(() => { if (!disposed) setLoadingAutostart(false); });
|
|
void readSilentStart()
|
|
.then((silent) => { if (!disposed) setSilentStart(silent); })
|
|
.catch(() => {})
|
|
.finally(() => { if (!disposed) setLoadingSilentStart(false); });
|
|
}
|
|
return () => { disposed = true; };
|
|
}, [message, native]);
|
|
|
|
const toggleAutostart = async (enabled: boolean) => {
|
|
try {
|
|
setLoadingAutostart(true);
|
|
await writeAutostart(enabled);
|
|
setAutostart(await readAutostart());
|
|
message(enabled ? t("已开启开机启动") : t("已关闭开机启动"));
|
|
} catch (cause) {
|
|
message(cause instanceof Error ? cause.message : String(cause));
|
|
} finally {
|
|
setLoadingAutostart(false);
|
|
}
|
|
};
|
|
|
|
const toggleSilentStart = async (enabled: boolean) => {
|
|
try {
|
|
setLoadingSilentStart(true);
|
|
await writeSilentStart(enabled);
|
|
setSilentStart(await readSilentStart());
|
|
message(enabled ? t("已开启静默启动") : t("已关闭静默启动"));
|
|
} catch (cause) {
|
|
message(cause instanceof Error ? cause.message : String(cause));
|
|
} finally {
|
|
setLoadingSilentStart(false);
|
|
}
|
|
};
|
|
|
|
const checkUpdate = async () => {
|
|
try {
|
|
const nextVersion = await updateStore.check();
|
|
message(nextVersion ? t("发现新版本 {version}", { version: nextVersion }) : t("当前已是最新版本"));
|
|
} catch (cause) {
|
|
message(cause instanceof Error ? cause.message : String(cause));
|
|
}
|
|
};
|
|
|
|
const updateNow = async () => {
|
|
try {
|
|
await updateStore.install();
|
|
} catch (cause) {
|
|
message(cause instanceof Error ? cause.message : String(cause));
|
|
}
|
|
};
|
|
|
|
return <TitledCard title={t("应用设置")}>
|
|
<div className={styles.row}>
|
|
<div>
|
|
<strong>{t("开机启动")}</strong>
|
|
<small>{t("登录系统后自动启动 Cursor BYOK。")}</small>
|
|
</div>
|
|
<Switch
|
|
checked={autostart}
|
|
disabled={!native || loadingAutostart}
|
|
label={t("开机启动")}
|
|
onChange={(enabled) => void toggleAutostart(enabled)}
|
|
/>
|
|
</div>
|
|
{autostart && <div className={styles.row}>
|
|
<div>
|
|
<strong>{t("静默启动")}</strong>
|
|
<small>{t("开机启动时不显示主窗口,仅保留系统托盘图标。")}</small>
|
|
</div>
|
|
<Switch
|
|
checked={silentStart}
|
|
disabled={!native || loadingSilentStart}
|
|
label={t("静默启动")}
|
|
onChange={(enabled) => void toggleSilentStart(enabled)}
|
|
/>
|
|
</div>}
|
|
<div className={styles.row}>
|
|
<div>
|
|
<strong>{t("软件更新")}</strong>
|
|
<small>{availableVersion
|
|
? t("版本 {version} 可以安装", { version: availableVersion })
|
|
: t("当前版本 {version}", { version })}</small>
|
|
</div>
|
|
{availableVersion
|
|
? <Button size="small" variant="primary" disabled={installing} onClick={() => void updateNow()}>
|
|
{installing ? t("安装中…") : t("下载并安装")}
|
|
<span className={styles.updateDot} aria-hidden="true" />
|
|
</Button>
|
|
: <Button size="small" disabled={!native || checking} onClick={() => void checkUpdate()}>
|
|
{checking ? t("检查中…") : t("检查更新")}
|
|
</Button>}
|
|
</div>
|
|
</TitledCard>;
|
|
}
|