fix(browser): 导入彻底无感——分区轮换替代文件热替换,搁置/重启路径全部删除

This commit is contained in:
Rick Ye
2026-09-13 00:34:50 +08:00
parent 95044c3a15
commit 06a316b6d1
7 changed files with 331 additions and 331 deletions
@@ -2,12 +2,20 @@
* 本机浏览器登录态导入表单(面板浮层与设置页二级页共用)。
* 选择本机浏览器(Chrome/Edge/Brave/Chromium)的一个 Profile,
* 把各站点登录态(Cookie / Local Storage)迁移到受管浏览器分区。
* 导入全程无感:无需重启应用;已导入的来源常驻展示,可一键「同步」复导。
* 自含数据源:直接调用 window.api(browserDetectSources / browserImportProfile)。
*/
import { useEffect, useState, type JSX } from 'react'
import { LuChevronDown } from 'react-icons/lu'
import { LuChevronDown, LuRefreshCw } from 'react-icons/lu'
import type { BrowserImportResult, BrowserSource, BrowserUiState } from '@shared/types'
function formatAt(iso: string): string {
const d = new Date(iso)
if (Number.isNaN(d.getTime())) return ''
const pad = (n: number): string => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}
export function BrowserImportForm(): JSX.Element {
const [state, setState] = useState<BrowserUiState | null>(null)
const [sources, setSources] = useState<BrowserSource[] | null>(null)
@@ -51,29 +59,53 @@ export function BrowserImportForm(): JSX.Element {
}
}, [])
const runImport = (): void => {
if (!selected) return
const runImport = (target: { sourceId: string; profileDir: string } | null): void => {
if (!target || busy) return
setBusy(true)
setError(null)
setResult(null)
window.api
.browserImportProfile(selected.sourceId, selected.profileDir)
.browserImportProfile(target.sourceId, target.profileDir)
.then(setResult)
.catch((err) => setError(err instanceof Error ? err.message : String(err)))
.finally(() => setBusy(false))
}
const imported = state?.imported ?? null
return (
<div className="text-[12px] text-ink-2">
<p className="mb-3 leading-relaxed text-ink-3">
迁移 Cookie / Local Storage 登录态。导入前请
<span className="font-medium text-ink-2">完全退出</span>源浏览器,并关闭本面板所有标签页。
迁移 Cookie / Local Storage 登录态,导入后立即生效。导入前请
<span className="font-medium text-ink-2">完全退出</span>源浏览器(含后台进程)。
</p>
{state?.imported && (
<div className="mb-3 rounded border border-line bg-inset px-2.5 py-2 text-[11.5px] text-ink-3">
当前导入来源:{state.imported.browser} · {state.imported.profile}
{state.imported.cookies ? '(含 Cookie)' : ''}
{imported && (
<div className="mb-3 rounded border border-line bg-inset px-2.5 py-2">
<div className="flex items-center gap-2">
<span className="shrink-0 text-[11px] text-ink-3">已导入</span>
<span className="min-w-0 flex-1 truncate text-[12px] text-ink">
{imported.browser} · {imported.profile}
{imported.profileDir && <span className="ml-1.5 text-[10.5px] text-ink-3">{imported.profileDir}</span>}
</span>
{imported.sourceId && imported.profileDir && (
<button
type="button"
disabled={busy}
onClick={() => runImport({ sourceId: imported.sourceId!, profileDir: imported.profileDir! })}
className="flex shrink-0 items-center gap-1 rounded border border-line-strong px-2 py-0.5 text-[11px] text-ink-2 transition-colors hover:bg-hover hover:text-ink disabled:opacity-40"
>
<LuRefreshCw size={11} className={busy ? 'animate-spin' : undefined} />
同步
</button>
)}
</div>
<div className="mt-1 text-[10.5px] text-ink-3">
{formatAt(imported.at)}
{imported.cookieCount ? ` · Cookie ${imported.cookieCount} 条` : imported.cookies ? ' · 含 Cookie' : ''}
{imported.localStorage ? ' · LocalStorage' : ''}
</div>
{imported.note && <div className="mt-1 text-[10.5px] leading-relaxed text-ink-3">{imported.note}</div>}
</div>
)}
@@ -128,26 +160,12 @@ export function BrowserImportForm(): JSX.Element {
</div>
)}
{/* 操作区:始终集中在底部一行;被搁置时以「重启并完成导入」为主操作 */}
<div className="mt-3 flex items-center justify-end gap-2">
{result?.deferred && (
<button
type="button"
onClick={() => void window.api.appRelaunch()}
className="rounded bg-accent px-3.5 py-1.5 text-[12px] font-medium text-page transition-opacity hover:opacity-90"
>
重启并完成导入
</button>
)}
<div className="mt-3 flex items-center justify-end">
<button
type="button"
disabled={!selected || busy}
onClick={runImport}
className={`rounded px-3.5 py-1.5 text-[12px] transition-colors disabled:opacity-40 ${
result?.deferred
? 'border border-line-strong text-ink-2 hover:bg-hover hover:text-ink'
: 'bg-accent font-medium text-page hover:opacity-90'
}`}
onClick={() => runImport(selected)}
className="rounded bg-accent px-3.5 py-1.5 text-[12px] font-medium text-page transition-opacity hover:opacity-90 disabled:opacity-40"
>
{busy ? '导入中…' : '导入浏览器数据'}
</button>
-1
View File
@@ -58,7 +58,6 @@ declare global {
stop: () => Promise<void>
getState: () => Promise<SessionState>
versions: () => Promise<{ app: string; electron: string; node: string; chrome: string; user: string }>
appRelaunch: () => Promise<void>
listSessions: () => Promise<SessionMeta[]>
newSession: () => Promise<void>
openSession: (path: string) => Promise<void>