fix: single-instance lock, tray open-on-double-click, and activity commit counts - #21
Conversation
The app keeps running in the tray (window-all-closed is a no-op and the close button hides the window), so relaunching the binary spawned a second process with its own window and its own tray icon. Acquire the Electron single-instance lock before whenReady: a duplicate launch quits, and the primary instance focuses its existing window via the second-instance event. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub reduced the PushEvent payload: it no longer includes size,
distinct_size, or commits, so the activity feed always rendered "0
commits" for every push. Carry the before/head SHAs through normalization
and resolve each push group's real commit count from
GET /repos/{owner}/{repo}/compare/{before}...{head}, as concurrency-limited
progressive enhancement mirroring the existing repo-card enrichment. When
the count is unknown (new branch, force-push, lost access, or still
resolving) render a count-less "pushed to {repo} · {branch}" sentence
instead of a fake 0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Double-clicking the tray / status-bar icon now restores and focuses the window (creating it if the app was closed to the tray), matching the standard desktop expectation. Right-click still opens the context menu. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| const ref = pushCountRefForEvent(props.event) | ||
| // For a push, hand the resolved compare count down (null while pending/unavailable so | ||
| // the sentence stays count-less instead of showing a stale 0); non-push events ignore it. | ||
| const resolved = ref ? (props.pushCounts?.get(ref.key) ?? null) : undefined |
There was a problem hiding this comment.
这里把 Map#get() miss 也折叠成 null,会跳过 presentFeedEvent 里的 payload fallback。API normalization 仍保留了 payload.size / commits.length 的真实 count;在 compare 请求还没回来或失败时,这里会把一个原本可用的 count 展示成 pushedUnknown。建议用 props.pushCounts?.has(ref.key) ? props.pushCounts.get(ref.key)! : undefined,只有确实 resolved 为 null 且 payload 也没有 count 时再显示无计数文案。
There was a problem hiding this comment.
已修复 (cf0dfbd):改成 has() 判定——Map miss(pending / 非 push)保持 undefined,让 presentFeedEvent 回退到 payload.commitCount;只有缓存里确实是 null(compare 查过但拿不到)才走 pushedUnknown。
| const presentation = computed(() => presentFeedGroup(props.group)) | ||
| const presentation = computed(() => { | ||
| const ref = pushCountRefForGroup(props.group) | ||
| const resolved = ref ? (props.pushCounts?.get(ref.key) ?? null) : undefined |
There was a problem hiding this comment.
同上,group 的 aggregate count 也会被 Map miss -> null 覆盖掉。这里会让 presentFeedGroup 无法使用 payloadTotal,尤其是旧 payload 中仍有 size / commits 的事件,或者 compare 还在 pending 的阶段。建议保持 miss = undefined,让 helper 自己回退到 payloadTotal。
There was a problem hiding this comment.
同样已修 (cf0dfbd):group 也用 has(),miss 时回退到 payloadTotal,只有缓存 null 才无计数。
| const gotSingleInstanceLock = app.requestSingleInstanceLock() | ||
|
|
||
| if (!gotSingleInstanceLock) { | ||
| app.quit() |
There was a problem hiding this comment.
建议把后续 app.whenReady().then(...) 初始化整个放进 else,或在 duplicate instance 分支直接 early-return/exit。当前调用 app.quit() 后,模块下面仍会注册 whenReady 初始化回调;大多时候进程会退出,但这个结构让副进程的 IPC/window/tray 初始化路径仍可被排队,读起来也偏离 Electron single-instance 官方示例。
There was a problem hiding this comment.
已重构 (cf0dfbd):把 whenReady 及 before-quit / updater / window-all-closed 全部放进单实例锁的 else,副实例 app.quit() 后不再排队任何 window/tray/IPC 初始化,贴合 Electron 官方示例结构。
…nce init Address review feedback on the fix branch: - Activity rows collapsed a pushCounts Map *miss* into `null`, which forced the count-less sentence even when the payload still carried a real count (legacy size/commits) or the compare request was still pending. Distinguish a miss (has() === false → undefined → payload fallback) from a resolved `null` (looked up, unavailable → count-less), in both the event and group rows. - Wrap the whenReady bootstrap and the before-quit / updater / window-all-closed handlers inside the single-instance-lock `else`, so a duplicate instance quits without queuing any window/tray/IPC init — matching Electron's example. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Three related desktop-shell fixes, all verified locally.
fix(client): single-instance lock (#18)
The app keeps running in the tray (
window-all-closedis a no-op, the close button hides to tray), so relaunching the binary spawned a second process with its own window and its own tray icon. Acquire the Electron single-instance lock beforewhenReady: a duplicate launch quits, and the primary instance focuses its existing window via thesecond-instanceevent.Closes #18.
fix: recover activity push commit counts via the compare API (#14)
GitHub reduced the
PushEventpayload — it no longer includessize/distinct_size/commits, so the Activity feed always showed "0 commits" for every push (verified against real events, including public accounts). Carry thebefore/headSHAs through normalization and resolve each push group's real count fromGET /repos/{owner}/{repo}/compare/{before}...{head}as concurrency-limited progressive enhancement (mirroring the existing repo-card enrichment). When the count is unknown (new branch, force-push, lost access, or still resolving) render a count-less "pushed to {repo} · {branch}" sentence instead of a fake0.Closes #14.
fix(client): open the app on tray icon double-click
Double-clicking the tray / status-bar icon now restores and focuses the window (creating it if the app was closed to the tray). Right-click still opens the context menu.
Test plan
pnpm -r typecheck✓pnpm --filter @oh-my-github/api test— incl. new reduced-payload +getPushCommitCountscases ✓pnpm --filter @oh-my-github/client test— incl. new resolved-count / unknown-sentence cases ✓pnpm --filter @oh-my-github/client build✓🤖 Generated with Claude Code