mirror of
https://github.com/dream-pep/koring-launcher.git
synced 2026-09-12 05:45:18 +08:00
feat(update): 实现更新通道管理系统与更新调试页面
本次提交完成以下变更: 1. 实现完整的更新通道管理功能,支持慢走/跑步两种更新模式,可在设置页切换且配置持久化生效 2. 新增更新调试页面,集成检查更新、版本比对、设置测试版本等调试工具 3. 新增快速打开Chromium DevTools的按钮,方便开发调试 4. 完善自动更新后端逻辑,新增版本比对、测试版本覆盖、通道动态获取等IPC接口 5. 调整GitHub Release构建脚本,修复prerelease版本的命名与发布问题 6. 添加semver依赖与类型定义,完善全量类型声明 7. 更新自动更新文档,补充更新通道相关的设计说明 8. 微调默认配置,添加主题暗黑模式的初始配置
This commit is contained in:
@@ -22,6 +22,7 @@ import { Debug } from "./pages/debug";
|
||||
import { SplashDebug } from "./pages/debug/splash-debug";
|
||||
import { DisplayDebug } from "./pages/debug/display-debug";
|
||||
import { VersionCardDebug } from "./pages/debug/version-card-debug";
|
||||
import { UpdateDebug } from "./pages/debug/update-debug";
|
||||
import { TaskDebug } from "./pages/debug/task-debug";
|
||||
import { CrashDebug } from "./pages/debug/crash-debug";
|
||||
import { Oobe } from "./pages/oobe";
|
||||
@@ -59,6 +60,7 @@ const pageMap = {
|
||||
"debug-splash": SplashDebug,
|
||||
"debug-display": DisplayDebug,
|
||||
"debug-version-card": VersionCardDebug,
|
||||
"debug-update": UpdateDebug,
|
||||
"debug-task": TaskDebug,
|
||||
"debug-crash": CrashDebug,
|
||||
} as const;
|
||||
|
||||
@@ -89,6 +89,7 @@ export interface UpdateConfig {
|
||||
transferred: number;
|
||||
total: number;
|
||||
source: string;
|
||||
channel: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,14 @@ export type UpdateState =
|
||||
| "installing"
|
||||
| "error";
|
||||
|
||||
/** 更新通道定义(主进程注册表,可扩展) */
|
||||
export interface UpdateChannelDef {
|
||||
key: string;
|
||||
label: string;
|
||||
desc: string;
|
||||
allowPrerelease: boolean;
|
||||
}
|
||||
|
||||
/** 主进程广播的更新状态 payload(update:status) */
|
||||
export interface UpdateStatusPayload {
|
||||
state: UpdateState;
|
||||
@@ -27,6 +35,8 @@ export interface UpdateStatusPayload {
|
||||
bytesPerSecond?: number;
|
||||
/** 当前使用的更新源(github / 加速源域名) */
|
||||
source?: string;
|
||||
/** 当前更新通道(woker / runner) */
|
||||
channel?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
@@ -86,3 +96,27 @@ export const getReleaseNotes = (tag?: string): Promise<ReleaseNotesResult | null
|
||||
/** 订阅更新状态变化 */
|
||||
export const onUpdateStatus = (cb: (status: UpdateStatusPayload) => void): (() => void) =>
|
||||
onIpcEvent<UpdateStatusPayload>("update:status", cb);
|
||||
|
||||
/** 获取更新通道定义列表(UI 动态渲染,可扩展) */
|
||||
export const getUpdateChannels = (): Promise<UpdateChannelDef[]> =>
|
||||
ipcInvoke<UpdateChannelDef[]>("update:getChannels");
|
||||
|
||||
/** 切换更新通道(woker 慢走 / runner 跑步;持久化并立即生效) */
|
||||
export const setUpdateChannel = (channel: string): Promise<UpdateStatusPayload> =>
|
||||
ipcInvoke<UpdateStatusPayload>("update:setChannel", { channel });
|
||||
|
||||
/** 开发者工具:设置测试版本号(覆盖当前识别版本) */
|
||||
export const setTestVersion = (version: string): Promise<UpdateStatusPayload> =>
|
||||
ipcInvoke<UpdateStatusPayload>("update:setTestVersion", { version });
|
||||
|
||||
/** 开发者工具:版本比对结果 */
|
||||
export interface VersionCompareResult {
|
||||
a: string;
|
||||
b: string;
|
||||
result: "a>b" | "a<b" | "a==b" | "invalid";
|
||||
detail: string;
|
||||
}
|
||||
|
||||
/** 开发者工具:版本比对(semver) */
|
||||
export const compareVersions = (a: string, b: string): Promise<VersionCompareResult> =>
|
||||
ipcInvoke<VersionCompareResult>("update:compareVersions", { a, b });
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { useRouteStore } from "@/stores/routeStore";
|
||||
import { Monitor, Paintbrush, CreditCard, ListTodo, ChevronRight, FlaskConical, Rocket, AlertTriangle } from "lucide-react";
|
||||
import { Monitor, Paintbrush, CreditCard, ListTodo, ChevronRight, FlaskConical, Rocket, AlertTriangle, RefreshCw, SquareTerminal } from "lucide-react";
|
||||
|
||||
const debugPages = [
|
||||
{
|
||||
key: "debug-update" as const,
|
||||
icon: RefreshCw,
|
||||
title: "更新功能测试",
|
||||
desc: "设置测试版本号、检查更新、获取发布说明、版本比对与下载",
|
||||
color: "text-emerald-500",
|
||||
bg: "bg-emerald-500/10",
|
||||
},
|
||||
{
|
||||
key: "debug-crash" as const,
|
||||
icon: AlertTriangle,
|
||||
@@ -67,6 +75,23 @@ export function Debug() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 打开浏览器调试工具(DevTools) */}
|
||||
<button
|
||||
onClick={() => window.electronAPI?.openDevTools()}
|
||||
className="glass-card w-full px-5 py-4 text-left hover:scale-[1.01] active:scale-[0.99] transition-transform cursor-pointer group mb-4"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="p-2.5 rounded-xl bg-foreground/[0.08]">
|
||||
<SquareTerminal className="w-5 h-5 text-foreground/60" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-foreground">打开开发者工具</p>
|
||||
<p className="text-[13px] text-muted-foreground mt-0.5">打开浏览器调试工具(Chromium DevTools),查看控制台与网络请求</p>
|
||||
</div>
|
||||
<ChevronRight className="w-4 h-4 text-foreground/20 group-hover:text-foreground/40 transition-colors shrink-0" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div className="space-y-3">
|
||||
{debugPages.map((p) => (
|
||||
<button
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { GlassCard, PageHeader } from "./components";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
cancelUpdate,
|
||||
checkForUpdates,
|
||||
compareVersions,
|
||||
downloadUpdate,
|
||||
getReleaseNotes,
|
||||
getUpdateState,
|
||||
onUpdateStatus,
|
||||
pauseUpdate,
|
||||
quitAndInstall,
|
||||
resumeUpdate,
|
||||
setTestVersion,
|
||||
type ReleaseNotesResult,
|
||||
type UpdateStatusPayload,
|
||||
type VersionCompareResult,
|
||||
} from "@/api/update";
|
||||
|
||||
/** 更新功能测试:版本识别 / 检查 / 介绍 / 比对 / 下载 */
|
||||
export function UpdateDebug() {
|
||||
const [status, setStatus] = useState<UpdateStatusPayload | null>(null);
|
||||
const [testVersion, setTestVersionInput] = useState("");
|
||||
const [versionMsg, setVersionMsg] = useState("");
|
||||
const [notesTag, setNotesTag] = useState("");
|
||||
const [notes, setNotes] = useState<ReleaseNotesResult | null>(null);
|
||||
const [notesMsg, setNotesMsg] = useState("");
|
||||
const [cmpA, setCmpA] = useState("");
|
||||
const [cmpB, setCmpB] = useState("");
|
||||
const [cmpResult, setCmpResult] = useState<VersionCompareResult | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const unsub = onUpdateStatus(setStatus);
|
||||
getUpdateState().then(setStatus).catch(() => {});
|
||||
return unsub;
|
||||
}, []);
|
||||
|
||||
const s = status;
|
||||
const pct = s?.percent ?? 0;
|
||||
|
||||
const run = async (fn: () => Promise<unknown>, setMsg: (m: string) => void) => {
|
||||
try {
|
||||
setMsg("执行中...");
|
||||
const r = await fn();
|
||||
setMsg(JSON.stringify(r));
|
||||
} catch (e) {
|
||||
setMsg(`失败:${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto p-8 space-y-6">
|
||||
<PageHeader title="更新功能测试" desc="测试更新检查、版本识别、发布说明、版本比对与下载" />
|
||||
|
||||
{/* 1. 版本识别列表 */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-foreground/40 uppercase tracking-wider mb-3">
|
||||
版本识别列表
|
||||
</h3>
|
||||
<GlassCard>
|
||||
<div className="space-y-1.5 text-[13px] font-mono">
|
||||
<p className="flex justify-between"><span className="text-muted-foreground">当前版本</span><span>{s?.currentVersion ?? "-"}</span></p>
|
||||
<p className="flex justify-between"><span className="text-muted-foreground">目标/最新版本</span><span>{s?.version ?? "-"}</span></p>
|
||||
<p className="flex justify-between"><span className="text-muted-foreground">更新状态</span><span>{s?.state ?? "-"}</span></p>
|
||||
<p className="flex justify-between"><span className="text-muted-foreground">更新通道</span><span>{s?.channel ?? "-"}</span></p>
|
||||
<p className="flex justify-between"><span className="text-muted-foreground">更新源</span><span className="max-w-[60%] truncate">{s?.source ?? "-"}</span></p>
|
||||
{s?.error && <p className="flex justify-between text-red-500"><span className="text-muted-foreground">错误</span><span className="max-w-[60%] truncate">{s.error}</span></p>}
|
||||
</div>
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
{/* 2. 设置版本号 */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-foreground/40 uppercase tracking-wider mb-3">
|
||||
设置测试版本号
|
||||
</h3>
|
||||
<GlassCard>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
value={testVersion}
|
||||
onChange={(e) => setTestVersionInput(e.target.value)}
|
||||
placeholder="如 1.2.1-beta.13"
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button size="sm" onClick={() => run(async () => {
|
||||
const r = await setTestVersion(testVersion.trim());
|
||||
setStatus(r);
|
||||
return r;
|
||||
}, setVersionMsg)}>
|
||||
设置
|
||||
</Button>
|
||||
</div>
|
||||
{versionMsg && <p className="mt-2 text-[12px] text-muted-foreground font-mono break-all">{versionMsg}</p>}
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
{/* 3. 检查更新 */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-foreground/40 uppercase tracking-wider mb-3">
|
||||
检查更新
|
||||
</h3>
|
||||
<GlassCard>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button size="sm" onClick={() => run(async () => {
|
||||
const r = await checkForUpdates(true);
|
||||
setStatus(r);
|
||||
return r;
|
||||
}, setVersionMsg)}>
|
||||
检查更新
|
||||
</Button>
|
||||
</div>
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
{/* 4. 获取更新介绍 */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-foreground/40 uppercase tracking-wider mb-3">
|
||||
获取更新介绍
|
||||
</h3>
|
||||
<GlassCard>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
value={notesTag}
|
||||
onChange={(e) => setNotesTag(e.target.value)}
|
||||
placeholder="留空=当前版本;或填 tag 如 v1.2.1-beta.13"
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button size="sm" onClick={() => run(async () => {
|
||||
const r = await getReleaseNotes(notesTag.trim() || undefined);
|
||||
setNotes(r);
|
||||
return r ? { tag: r.tag, source: r.source, version: r.version, len: r.notes.length } : null;
|
||||
}, setNotesMsg)}>
|
||||
获取
|
||||
</Button>
|
||||
</div>
|
||||
{notes && (
|
||||
<div className="mt-3 text-[12px] text-muted-foreground font-mono break-all">
|
||||
<p>tag: {notes.tag} · 来源: {notes.source} · 长度: {notes.notes.length}</p>
|
||||
<div className="mt-1 max-h-40 overflow-y-auto border border-border/40 rounded-lg p-2 bg-foreground/[0.03] whitespace-pre-wrap">
|
||||
{notes.notes.slice(0, 600)}{notes.notes.length > 600 ? "…" : ""}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{notesMsg && <p className="mt-2 text-[12px] text-muted-foreground font-mono break-all">{notesMsg}</p>}
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
{/* 5. 版本比对 */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-foreground/40 uppercase tracking-wider mb-3">
|
||||
版本比对
|
||||
</h3>
|
||||
<GlassCard>
|
||||
<div className="flex gap-2">
|
||||
<Input value={cmpA} onChange={(e) => setCmpA(e.target.value)} placeholder="版本 A" className="flex-1" />
|
||||
<span className="self-center text-muted-foreground text-[13px]">vs</span>
|
||||
<Input value={cmpB} onChange={(e) => setCmpB(e.target.value)} placeholder="版本 B" className="flex-1" />
|
||||
<Button size="sm" onClick={() => run(async () => {
|
||||
const r = await compareVersions(cmpA.trim(), cmpB.trim());
|
||||
setCmpResult(r);
|
||||
return r;
|
||||
}, setNotesMsg)}>
|
||||
比对
|
||||
</Button>
|
||||
</div>
|
||||
{cmpResult && (
|
||||
<p className="mt-2 text-[13px] font-mono">
|
||||
<span className={cmpResult.result === "a>b" ? "text-emerald-500" : cmpResult.result === "a<b" ? "text-red-500" : "text-foreground"}>
|
||||
{cmpResult.detail}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
{/* 6. 下载版本 */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-foreground/40 uppercase tracking-wider mb-3">
|
||||
下载版本
|
||||
</h3>
|
||||
<GlassCard>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button size="sm" onClick={() => run(downloadUpdate, setNotesMsg)}>下载</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => run(pauseUpdate, setNotesMsg)}>暂停</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => run(resumeUpdate, setNotesMsg)}>继续</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => run(cancelUpdate, setNotesMsg)}>取消</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => run(quitAndInstall, setNotesMsg)}>安装</Button>
|
||||
</div>
|
||||
{(s?.state === "downloading" || s?.state === "paused") && (
|
||||
<div className="mt-3">
|
||||
<div className="h-1.5 w-full rounded-full bg-foreground/10 overflow-hidden">
|
||||
<div className="h-full bg-blue-500 transition-all" style={{ width: `${pct}%` }} />
|
||||
</div>
|
||||
<p className="mt-1.5 text-[12px] text-muted-foreground font-mono">
|
||||
{pct.toFixed(1)}% · {s.state}
|
||||
{s.transferred != null && s.total ? ` · ${(s.transferred / 1024 / 1024).toFixed(1)} / ${(s.total / 1024 / 1024).toFixed(1)} MB` : ""}
|
||||
{s.bytesPerSecond ? ` · ${(s.bytesPerSecond / 1024 / 1024).toFixed(1)} MB/s` : ""}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
<p className="text-[12px] text-muted-foreground/50 text-center">
|
||||
仅用于开发调试;下载/安装会真实执行,请谨慎操作
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,10 +2,18 @@ import { useState, useEffect } from "react";
|
||||
import { VersionCard } from "@/components/VersionCard";
|
||||
import { BUILD_MODE } from "@/lib/mode";
|
||||
import { BUILD_COMMIT, BUILD_ID } from "@/lib/buildInfo";
|
||||
import { ExternalLink, GitFork, RotateCcw } from "lucide-react";
|
||||
import { Link } from "@heroui/react";
|
||||
import { ExternalLink, GitFork, RotateCcw, ChevronDown } from "lucide-react";
|
||||
import { Link, Select, ListBox, ListBoxItem } from "@heroui/react";
|
||||
import { SettingCard, SettingRow, PageHeader, SectionTitle } from "@/components/setting";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
getUpdateChannels,
|
||||
getUpdateState,
|
||||
onUpdateStatus,
|
||||
setUpdateChannel,
|
||||
type UpdateChannelDef,
|
||||
} from "@/api/update";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogTrigger,
|
||||
@@ -27,11 +35,50 @@ const modeLabels: Record<string, string> = {
|
||||
const GITHUB_URL = "https://github.com/lingke-net/koring-launcher";
|
||||
const OFFICIAL_URL = "https://koring.space";
|
||||
|
||||
/** 兜底通道列表:主进程 update:getChannels 不可用时使用,保证下拉框始终有选项 */
|
||||
const FALLBACK_CHANNELS: UpdateChannelDef[] = [
|
||||
{ key: "woker", label: "慢走模式", desc: "仅获取正式版更新(稳定)", allowPrerelease: false },
|
||||
{ key: "runner", label: "跑步模式", desc: "可获取预览版(测试版)更新", allowPrerelease: true },
|
||||
];
|
||||
|
||||
export function AboutSetting() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [countdown, setCountdown] = useState(5);
|
||||
const canConfirm = countdown <= 0;
|
||||
|
||||
// 更新通道(下拉框,选项来自主进程通道注册表)
|
||||
const [channels, setChannels] = useState<UpdateChannelDef[]>([]);
|
||||
const [activeChannel, setActiveChannel] = useState("woker");
|
||||
|
||||
useEffect(() => {
|
||||
getUpdateChannels()
|
||||
.then((list) => setChannels(list.length ? list : FALLBACK_CHANNELS))
|
||||
.catch((e) => {
|
||||
console.error("[update] 获取更新通道失败,使用内置列表:", e);
|
||||
setChannels(FALLBACK_CHANNELS);
|
||||
});
|
||||
const unsub = onUpdateStatus((s) => {
|
||||
if (s.channel) setActiveChannel(s.channel);
|
||||
});
|
||||
getUpdateState()
|
||||
.then((s) => {
|
||||
if (s.channel) setActiveChannel(s.channel);
|
||||
})
|
||||
.catch(() => {});
|
||||
return unsub;
|
||||
}, []);
|
||||
|
||||
const handleChannelChange = async (key: unknown) => {
|
||||
if (typeof key !== "string" || !key || key === activeChannel) return;
|
||||
try {
|
||||
await setUpdateChannel(key);
|
||||
setActiveChannel(key);
|
||||
toast.success("更新通道已切换,下次检查更新生效");
|
||||
} catch (e) {
|
||||
toast.error(e instanceof Error ? e.message : String(e));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
setCountdown(5);
|
||||
@@ -87,6 +134,48 @@ export function AboutSetting() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<SectionTitle>更新设置</SectionTitle>
|
||||
<div className="space-y-3">
|
||||
<SettingCard>
|
||||
<SettingRow label="更新通道" desc="慢走模式仅获取正式版;跑步模式可获取预览版">
|
||||
<Select.Root
|
||||
selectedKey={activeChannel}
|
||||
onSelectionChange={handleChannelChange}
|
||||
aria-label="更新通道"
|
||||
className="w-48"
|
||||
>
|
||||
<Select.Trigger className="h-8 rounded-lg border border-border/40 dark:border-white/[0.08] bg-white/60 dark:bg-black/30 px-3 hover:border-primary/30 transition-colors">
|
||||
<Select.Value className="text-[13px] text-foreground">
|
||||
{channels.find((c) => c.key === activeChannel)?.label ?? "慢走模式"}
|
||||
</Select.Value>
|
||||
<Select.Indicator>
|
||||
<ChevronDown className="w-3.5 h-3.5 text-muted-foreground" />
|
||||
</Select.Indicator>
|
||||
</Select.Trigger>
|
||||
<Select.Popover className="z-50 rounded-xl border border-border/50 dark:border-white/[0.08] bg-background shadow-xl p-1.5 w-52">
|
||||
<ListBox className="outline-none">
|
||||
{channels.map((c) => (
|
||||
<ListBoxItem
|
||||
key={c.key}
|
||||
id={c.key}
|
||||
textValue={c.label}
|
||||
className="text-[13px] py-1.5 px-2.5 rounded-lg data-[selected=true]:bg-primary/10 data-[selected=true]:text-primary outline-none cursor-pointer"
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span>{c.label}</span>
|
||||
<span className="text-[12px] text-muted-foreground">{c.desc}</span>
|
||||
</div>
|
||||
</ListBoxItem>
|
||||
))}
|
||||
</ListBox>
|
||||
</Select.Popover>
|
||||
</Select.Root>
|
||||
</SettingRow>
|
||||
</SettingCard>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<SectionTitle>相关链接</SectionTitle>
|
||||
<div className="space-y-3">
|
||||
|
||||
@@ -59,7 +59,7 @@ const DEFAULT_CONFIG: AppConfig = {
|
||||
download: { fileSource: "mirror", versionSource: "mirror", threads: 16, speedLimit: 0 },
|
||||
network: { securityId: { enabled: false, authUrl: "" } },
|
||||
ui: { showInstanceTitle: true, showTaskButton: true },
|
||||
update: { state: "idle", version: "", percent: 0, transferred: 0, total: 0, source: "github", error: "" },
|
||||
update: { state: "idle", version: "", percent: 0, transferred: 0, total: 0, source: "github", channel: "woker", error: "" },
|
||||
instances: [],
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ interface KoringAuthState {
|
||||
logout: () => Promise<void>;
|
||||
}
|
||||
|
||||
export const useKoringAuthStore = create<KoringAuthState>((set) => ({
|
||||
export const useKoringAuthStore = create<KoringAuthState>((set, get) => ({
|
||||
user: null,
|
||||
authData: null,
|
||||
loading: false,
|
||||
|
||||
@@ -24,6 +24,7 @@ export type RouteKey =
|
||||
| "debug-splash"
|
||||
| "debug-display"
|
||||
| "debug-version-card"
|
||||
| "debug-update"
|
||||
| "debug-task"
|
||||
| "debug-crash";
|
||||
|
||||
@@ -67,6 +68,7 @@ export const allRoutes: RouteItem[] = [
|
||||
{ key: "debug-splash", label: "启动动画调试", path: "/debug/splash", hidden: true },
|
||||
{ key: "debug-display", label: "显示效果调试", path: "/debug/display", hidden: true },
|
||||
{ key: "debug-version-card", label: "版本卡片调试", path: "/debug/version-card", hidden: true },
|
||||
{ key: "debug-update", label: "更新功能测试", path: "/debug/update", hidden: true },
|
||||
{ key: "debug-task", label: "任务队列调试", path: "/debug/task", hidden: true },
|
||||
];
|
||||
|
||||
|
||||
Vendored
+5
@@ -7,6 +7,7 @@ interface ElectronAPI {
|
||||
maximize: () => Promise<void>;
|
||||
close: () => Promise<void>;
|
||||
isMaximized: () => Promise<boolean>;
|
||||
openDevTools: () => Promise<unknown>;
|
||||
onResized: (callback: () => void) => () => void;
|
||||
|
||||
getTheme: () => Promise<'light' | 'dark' | 'system' | null>;
|
||||
@@ -33,6 +34,10 @@ interface ElectronAPI {
|
||||
quitAndInstall: () => Promise<unknown>;
|
||||
getUpdateState: () => Promise<unknown>;
|
||||
getReleaseNotes: (tag?: string) => Promise<unknown>;
|
||||
getUpdateChannels: () => Promise<unknown>;
|
||||
setUpdateChannel: (channel: string) => Promise<unknown>;
|
||||
setTestVersion: (version: string) => Promise<unknown>;
|
||||
compareVersions: (a: string, b: string) => Promise<unknown>;
|
||||
onUpdateStatus: (callback: (data: unknown) => void) => () => void;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user