fix(desktop): leave sign-in activation to the completion page
This commit is contained in:
1 parent
10b6ffec3f
commit
4283f62d01
5 files changed
+27
-10
No files matched your search
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write apps/desktop/README.md
|
||||
README.md: 372ea4a0ac1ccb6ec7aeedd99899111f9b5801c7
|
||||
README.zh.md: b155745f68e9a3f706650f81309c8d1e7d179586
|
||||
README.md: f00608919c1a44441bffa57d2b601c12b47724a8
|
||||
README.zh.md: 76862075461d651a4d25235d57eb1855602ea90e
|
||||
@@ -411,7 +411,7 @@ An unpackaged Electron process uses `.desktop-build/development/project` under i
|
||||
- Dependency lifecycle scripts follow pnpm’s build permissions; Desktop provides no separate approval dialog.
|
||||
- The desktop shell shares sessions, settings, credentials, workspaces, and storage under `$DSH_HOME` with CLI dsh, while executable packages, plugin activation, and lockfiles remain separate.
|
||||
|
||||
Sign in opens the configured platform page in the system browser. The Host owns PKCE and a temporary loopback callback, saves the credential before entering the workspace, and redirects the browser to the platform completion page. Opened and copied authorization links carry the effective Desktop theme as `theme=light` or `theme=dark`; `system` resolves at the time of the action. Cancel withdraws the local attempt even if the platform page later approves it. Settings offers Account sign-out; without a separate API key, sign-out returns to the welcome window. Packaged applications register dsh://open to show the window without passing credentials. On macOS, the development launcher prepares an ad-hoc-signed `Harness Dev.app` under `.desktop-build/development`, declares `dsh` in its Info.plist, and registers it with Launch Services. It loads the current workspace and records the selected development home, browser-data path, and debug settings for cold starts. Starting this bundle makes it the default `dsh://` handler; starting the packaged application registers the packaged handler again. The generated bundle does not contain account tokens and requires the workspace and prepared runtime to remain available.
|
||||
Sign in opens the configured platform page in the system browser. The Host owns PKCE and a temporary loopback callback, saves the credential before entering the workspace, and redirects the browser to the platform completion page. Opened and copied authorization links carry the effective Desktop theme as `theme=light` or `theme=dark`; `system` resolves at the time of the action. Cancel withdraws the local attempt even if the platform page later approves it. Settings offers Account sign-out; without a separate API key, sign-out returns to the welcome window. Successful browser sign-in switches Welcome to the workspace without activating the application; the completion page’s dsh://open link brings it to the foreground. Packaged applications register dsh://open to show the window without passing credentials. On macOS, the development launcher prepares an ad-hoc-signed `Harness Dev.app` under `.desktop-build/development`, declares `dsh` in its Info.plist, and registers it with Launch Services. It loads the current workspace and records the selected development home, browser-data path, and debug settings for cold starts. Starting this bundle makes it the default `dsh://` handler; starting the packaged application registers the packaged handler again. The generated bundle does not contain account tokens and requires the workspace and prepared runtime to remain available.
|
||||
|
||||
When an expired account returns to Welcome, the main process retains a one-time notification until the renderer requests it over window-owned IPC. Reloading Welcome does not repeat the notice; manual sign-out and cold startup do not create it.
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ node apps/desktop/node_modules/pnpm/bin/pnpm.mjs --dir apps/desktop run test:upd
|
||||
- 依赖的生命周期脚本遵循 pnpm 的构建权限;Desktop 不提供单独的审批对话框。
|
||||
- 桌面壳与 CLI dsh 共享 `$DSH_HOME` 下的会话、设置、凭据、工作区和存储,但可执行包、插件激活和锁文件彼此隔离。
|
||||
|
||||
登录会在系统浏览器中打开配置的平台页面。Host 负责 PKCE 和临时本机回调,在进入工作区前保存凭证,再将浏览器跳转到平台完成页。打开和复制的授权链接通过 `theme=light` 或 `theme=dark` 携带当前生效的 Desktop 主题;`system` 在执行操作时解析。即使平台页面随后批准,取消仍会撤销本地尝试。设置中的账号页面提供退出;没有独立 API Key 时,退出后返回欢迎窗。打包应用注册 dsh://open,只显示窗口而不传递凭证。macOS 开发启动器在 `.desktop-build/development` 下准备经临时签名的 `Harness Dev.app`,在 Info.plist 中声明 `dsh` 并注册到 Launch Services。它加载当前工作区,并记录选定的开发 home、浏览器数据路径和调试设置,以供冷启动使用。启动此应用会将其设为 `dsh://` 默认处理程序;启动打包应用会重新注册打包版处理程序。生成的应用包不包含账号 token,依赖工作区和已准备的运行环境继续存在。
|
||||
登录会在系统浏览器中打开配置的平台页面。Host 负责 PKCE 和临时本机回调,在进入工作区前保存凭证,再将浏览器跳转到平台完成页。打开和复制的授权链接通过 `theme=light` 或 `theme=dark` 携带当前生效的 Desktop 主题;`system` 在执行操作时解析。即使平台页面随后批准,取消仍会撤销本地尝试。设置中的账号页面提供退出;没有独立 API Key 时,退出后返回欢迎窗。浏览器登录成功后,Welcome 切换到工作区但不激活应用;完成页的 dsh://open 链接负责将客户端置前。打包应用注册 dsh://open,只显示窗口而不传递凭证。macOS 开发启动器在 `.desktop-build/development` 下准备经临时签名的 `Harness Dev.app`,在 Info.plist 中声明 `dsh` 并注册到 Launch Services。它加载当前工作区,并记录选定的开发 home、浏览器数据路径和调试设置,以供冷启动使用。启动此应用会将其设为 `dsh://` 默认处理程序;启动打包应用会重新注册打包版处理程序。生成的应用包不包含账号 token,依赖工作区和已准备的运行环境继续存在。
|
||||
|
||||
账号失效并返回 Welcome 时,主进程保留一次性通知,直到渲染器通过所属窗口的 IPC 领取。重新加载 Welcome 不会重复提示;主动退登和冷启动不会生成该通知。
|
||||
|
||||
|
||||
@@ -395,7 +395,7 @@ async function main(): Promise<void> {
|
||||
returnedAttempt = attempt.id
|
||||
focusPrimaryWindow()
|
||||
}
|
||||
if (attempt?.phase === 'succeeded' && welcomeWindow !== undefined) void enterWorkspace().catch(() => undefined)
|
||||
if (attempt?.phase === 'succeeded' && welcomeWindow !== undefined) void enterWorkspace({ activate: false }).catch(() => undefined)
|
||||
if (previousAccountStatus === 'credential-stored' && state.status === 'signed-out') {
|
||||
void readWelcomeState().then(async (value) => {
|
||||
if (needsWelcome(value) && !quitting) {
|
||||
@@ -924,19 +924,20 @@ async function main(): Promise<void> {
|
||||
})
|
||||
return window
|
||||
}
|
||||
const enterWorkspace = async (): Promise<void> => {
|
||||
const enterWorkspace = async ({ activate = true }: { activate?: boolean } = {}): Promise<void> => {
|
||||
if (quitting) return
|
||||
const window = mainWindow ?? createMainWindow()
|
||||
await navigateMain(applicationUrl)
|
||||
if (isQuitting() || recovery.active || window.isDestroyed()) return
|
||||
window.show()
|
||||
if (activate) window.show()
|
||||
else window.showInactive()
|
||||
enteredWorkspace = true
|
||||
if (welcomeWindow !== undefined) {
|
||||
welcomeWindow.close()
|
||||
window.webContents.send(DESKTOP_IPC.enterWorkspace)
|
||||
}
|
||||
welcomeWindow = undefined
|
||||
if (development && process.env.DSH_DESKTOP_OPEN_DEVTOOLS !== '0') {
|
||||
if (activate && development && process.env.DSH_DESKTOP_OPEN_DEVTOOLS !== '0') {
|
||||
window.webContents.openDevTools({ mode: 'detach' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ const state = vi.hoisted(() => ({
|
||||
stopHost: vi.fn<() => Promise<void>>().mockResolvedValue(undefined),
|
||||
loadWorkspace: vi.fn<(url: string) => Promise<void>>().mockResolvedValue(undefined),
|
||||
showWorkspace: vi.fn(),
|
||||
showInactiveWorkspace: vi.fn(),
|
||||
focusWorkspace: vi.fn(),
|
||||
openDevTools: vi.fn(),
|
||||
closeWelcome: vi.fn(),
|
||||
welcomeLocale: undefined as DesktopLocale | undefined,
|
||||
preference: 'zh',
|
||||
@@ -64,16 +67,18 @@ vi.mock('electron', () => ({
|
||||
BrowserWindow: class {
|
||||
constructor(options: BrowserWindowConstructorOptions) { state.windowOptions = options }
|
||||
private ready: (() => void) | undefined
|
||||
webContents = { mainFrame: { url: 'dsh-app://app/' }, setWindowOpenHandler: vi.fn(), on: vi.fn(), once: vi.fn(), send: vi.fn(), openDevTools: vi.fn() }
|
||||
webContents = { mainFrame: { url: 'dsh-app://app/' }, setWindowOpenHandler: vi.fn(),
|
||||
on: vi.fn(), once: vi.fn(), send: vi.fn(), openDevTools: state.openDevTools }
|
||||
static getAllWindows() { return [] }
|
||||
once(name: string, callback: () => void) { if (name === 'ready-to-show') this.ready = callback; return this }
|
||||
on() { return this }
|
||||
isDestroyed() { return false }
|
||||
isMinimized() { return false }
|
||||
restore = vi.fn()
|
||||
focus = vi.fn()
|
||||
focus = state.focusWorkspace
|
||||
hide = vi.fn()
|
||||
show = state.showWorkspace
|
||||
showInactive = state.showInactiveWorkspace
|
||||
async loadURL(url: string) { state.contents = this.webContents; await state.loadWorkspace(url); this.ready?.() }
|
||||
},
|
||||
net: { fetch: vi.fn() },
|
||||
@@ -251,5 +256,16 @@ it('starts the Host for welcome onboarding and opens the workspace on skip witho
|
||||
state.accountListener!({ ...account, status: 'signed-out', attempt: null })
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
expect(await state.operations!.takeNotice()).toBeUndefined()
|
||||
state.showWorkspace.mockClear()
|
||||
state.focusWorkspace.mockClear()
|
||||
vi.stubEnv('DSH_DESKTOP_OPEN_DEVTOOLS', '1')
|
||||
state.accountListener!({ ...account, status: 'credential-stored', attempt: { id: attemptId, phase: 'succeeded' } })
|
||||
await vi.waitFor(() => { expect(state.showInactiveWorkspace).toHaveBeenCalledOnce() })
|
||||
expect(state.showWorkspace).not.toHaveBeenCalled()
|
||||
expect(state.focusWorkspace).not.toHaveBeenCalled()
|
||||
expect(state.openDevTools).not.toHaveBeenCalled()
|
||||
state.appListeners.get('open-url')!({ preventDefault: vi.fn() }, 'dsh://open')
|
||||
expect(state.showWorkspace).toHaveBeenCalledOnce()
|
||||
expect(state.focusWorkspace).toHaveBeenCalledOnce()
|
||||
|
||||
})
|
||||
Reference in new issue
Block a user