Skip to content

fix: support token paste on first login#54

Merged
AmintaCCCP merged 3 commits intomainfrom
fix/issue-52-login-token-paste
Mar 8, 2026
Merged

fix: support token paste on first login#54
AmintaCCCP merged 3 commits intomainfrom
fix/issue-52-login-token-paste

Conversation

@AmintaCCCP
Copy link
Owner

@AmintaCCCP AmintaCCCP commented Mar 8, 2026

Summary\nFixes the issue where users on v2.0-v2.2 cannot paste GitHub token during first login.\n\n## Changes\n- Add keyboard fallback for Ctrl/Cmd + V in login token input\n- Read clipboard text via and populate token field\n- Keep default behavior unchanged for normal typing and Enter submit\n- No functional logic changes outside login input handling\n\n## Testing\n-

github-stars-manager@0.2.2 build
vite build

vite v5.4.8 building for production...
transforming...
✓ 1810 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 1.11 kB │ gzip: 0.65 kB
dist/assets/index-DW9FpI6u.css 39.40 kB │ gzip: 6.68 kB
dist/assets/index-Djqhd4g9.js 387.01 kB │ gzip: 111.39 kB
✓ built in 2.63s passes\n- Verified no type/build errors\n\nFixes #52

Summary by CodeRabbit

  • New Features

    • Desktop paste shortcut on the login screen (Ctrl/Cmd+V) to paste tokens.
    • Global search shortcuts: Ctrl/Cmd+K, Ctrl/Cmd+Shift+F, /, and Esc to focus, clear, and toggle search/filter UI.
    • Production menu bar made visible with an Edit menu (undo, redo, cut, copy, paste, select all).
  • Bug Fixes

    • Improved Enter key handling on the login screen to prevent duplicate or unintended submissions.

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 2026

📝 Walkthrough

Walkthrough

Adds clipboard paste handling (Ctrl/Cmd+V) to the login input; registers global search keyboard shortcuts to focus/clear search and toggle filters; and exposes the Edit menu plus disables auto-hide of the menu bar in the Electron production build configuration.

Changes

Cohort / File(s) Summary
Clipboard Paste Enhancement
src/components/LoginScreen.tsx
Adds Ctrl/Cmd+V handling: reads navigator.clipboard.readText(), trims and sets the token, clears errors, and logs a warning on read failure; preserves loading guard and existing Enter behavior.
Search Shortcut Integration
src/components/SearchBar.tsx
Wires useSearchShortcuts callbacks to focus the input, clear+refocus search, show/hide history, and toggle filters in response to global shortcuts (e.g., Ctrl/Cmd+K, Ctrl/Cmd+Shift+F, /, Escape).
Menu / Desktop Build
.github/workflows/build-desktop.yml
Sets autoHideMenuBar: false and inserts an Edit submenu (undo/redo/cut/copy/paste/selectAll) into the production menu template for consistency across platforms.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LoginScreen as LoginScreen/Input
    participant Clipboard as SystemClipboard
    participant AppState as TokenState

    User->>LoginScreen: Press Ctrl/Cmd+V
    LoginScreen->>Clipboard: navigator.clipboard.readText()
    Clipboard-->>LoginScreen: clipboardText
    LoginScreen->>AppState: setToken(trim(clipboardText))
    LoginScreen->>LoginScreen: clearErrors()
    LoginScreen-->>User: token populated in input
Loading
sequenceDiagram
    participant User
    participant ShortcutHook as GlobalShortcutHook
    participant SearchBar as SearchBar/Input
    participant UI as Filters/HistoryPanel

    User->>ShortcutHook: Press Ctrl/Cmd+K or /
    ShortcutHook->>SearchBar: focusInput()
    ShortcutHook->>UI: showHistory(true)
    User->>ShortcutHook: Press Ctrl/Cmd+Shift+F
    ShortcutHook->>UI: toggleFilters()
    User->>ShortcutHook: Press Escape
    ShortcutHook->>SearchBar: clearAndRefocus()
    ShortcutHook->>UI: hideHistory()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I nibble keys and sniff the paste,
Ctrl+V hops in with gentle haste,
Shortcuts drum a joyful tune,
Menus wake beneath the moon,
Little rabbit claps — features taste! 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main fix: adding support for token paste during login, which addresses issue #52.
Linked Issues check ✅ Passed The PR implements the required functionality to restore token paste capability during first login by adding Ctrl/Cmd+V keyboard support and reading clipboard text.
Out of Scope Changes check ✅ Passed The PR includes restoration of useSearchShortcuts in SearchBar and Edit menu additions in build config, which address related shortcut regressions mentioned in issue #52 comments.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-52-login-token-paste

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/components/LoginScreen.tsx (2)

52-52: Add a feature check for navigator.clipboard availability.

navigator.clipboard may be undefined in non-secure contexts (non-HTTPS) or older browsers. While the try-catch handles errors, accessing readText() on undefined throws a TypeError before entering the try block's async operation.

🛡️ Proposed defensive check
     if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v' && !isLoading) {
+      if (!navigator.clipboard?.readText) {
+        return; // Let default paste behavior handle it
+      }
+      e.preventDefault();
       try {
         const text = await navigator.clipboard.readText();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/LoginScreen.tsx` at line 52, Wrap the clipboard access in a
defensive feature check inside the LoginScreen component: before calling await
navigator.clipboard.readText() (the line declaring const text), verify that
window.navigator && navigator.clipboard && typeof navigator.clipboard.readText
=== 'function'; if the check fails, handle the fallback (show user-facing
message or return early) otherwise proceed to call readText inside the existing
try/catch so errors are still caught; update the code path that references const
text accordingly (look for the const text = await navigator.clipboard.readText()
usage in LoginScreen.tsx).

43-43: Replace onKeyPress with onKeyDown for reliable keyboard event handling.

onKeyPress is deprecated in web standards and doesn't reliably capture modifier key combinations (Ctrl/Cmd+key) across browsers. onKeyDown is the recommended event for handling keyboard shortcuts including your Ctrl/Cmd+V paste functionality.

Update the handler at line 43 and its binding at line 122:

♻️ Changes needed
-  const handleKeyPress = async (e: React.KeyboardEvent<HTMLInputElement>) => {
+  const handleKeyDown = async (e: React.KeyboardEvent<HTMLInputElement>) => {
-                  onKeyPress={handleKeyPress}
+                  onKeyDown={handleKeyDown}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/LoginScreen.tsx` at line 43, Replace the deprecated onKeyPress
usage with onKeyDown by renaming the handler function handleKeyPress to
handleKeyDown (or update its usage) and attach it to the input's onKeyDown prop;
ensure the function signature remains (e: React.KeyboardEvent<HTMLInputElement>)
=> Promise<void> and that any logic checking e.ctrlKey / e.metaKey and e.key ===
'v' (the Ctrl/Cmd+V paste shortcut) continues to run in the new handler so
keyboard shortcuts work reliably across browsers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/LoginScreen.tsx`:
- Around line 50-56: In the LoginScreen key handler where you detect Ctrl/Cmd+V
and call navigator.clipboard.readText(), add e.preventDefault() immediately when
the paste hotkey is detected (before the await) to stop the browser's default
paste from also firing; keep the existing logic that awaits
navigator.clipboard.readText(), trims and calls setToken(...) and clears
setError(...), but ensure e.preventDefault() is invoked first to avoid the race
with the onChange handler.

---

Nitpick comments:
In `@src/components/LoginScreen.tsx`:
- Line 52: Wrap the clipboard access in a defensive feature check inside the
LoginScreen component: before calling await navigator.clipboard.readText() (the
line declaring const text), verify that window.navigator && navigator.clipboard
&& typeof navigator.clipboard.readText === 'function'; if the check fails,
handle the fallback (show user-facing message or return early) otherwise proceed
to call readText inside the existing try/catch so errors are still caught;
update the code path that references const text accordingly (look for the const
text = await navigator.clipboard.readText() usage in LoginScreen.tsx).
- Line 43: Replace the deprecated onKeyPress usage with onKeyDown by renaming
the handler function handleKeyPress to handleKeyDown (or update its usage) and
attach it to the input's onKeyDown prop; ensure the function signature remains
(e: React.KeyboardEvent<HTMLInputElement>) => Promise<void> and that any logic
checking e.ctrlKey / e.metaKey and e.key === 'v' (the Ctrl/Cmd+V paste shortcut)
continues to run in the new handler so keyboard shortcuts work reliably across
browsers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 002dd6e0-5856-43ed-8e77-11e594f7695e

📥 Commits

Reviewing files that changed from the base of the PR and between 7725b58 and db8ac52.

📒 Files selected for processing (1)
  • src/components/LoginScreen.tsx

Comment on lines +50 to +56
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v' && !isLoading) {
try {
const text = await navigator.clipboard.readText();
if (text) {
setToken(text.trim());
setError('');
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing e.preventDefault() may cause double paste behavior.

When the manual clipboard read succeeds, the browser's default paste also fires (via onChange), potentially causing a race condition between the async setToken(text.trim()) and the synchronous setToken(e.target.value) from onChange. This can lead to inconsistent state or the untrimmed value winning.

Call e.preventDefault() before the async clipboard read to suppress the default paste when handling it manually.

🐛 Proposed fix
     // 兼容桌面端首次登录场景下 Ctrl/Cmd + V 无法触发默认粘贴的问题
     if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v' && !isLoading) {
+      e.preventDefault();
       try {
         const text = await navigator.clipboard.readText();
         if (text) {
           setToken(text.trim());
           setError('');
         }
       } catch (error) {
         // 忽略读取剪贴板失败,让浏览器/系统默认行为继续兜底
         console.warn('Clipboard read failed:', error);
       }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/LoginScreen.tsx` around lines 50 - 56, In the LoginScreen key
handler where you detect Ctrl/Cmd+V and call navigator.clipboard.readText(), add
e.preventDefault() immediately when the paste hotkey is detected (before the
await) to stop the browser's default paste from also firing; keep the existing
logic that awaits navigator.clipboard.readText(), trims and calls setToken(...)
and clears setError(...), but ensure e.preventDefault() is invoked first to
avoid the race with the onChange handler.

@AmintaCCCP
Copy link
Owner Author

补充 Root Cause 分析(针对 #52 评论中“快捷键失效”):

我对比了 v0.2.0 ~ v0.2.2 的提交链,确认不是 devtools 集成导致。

触发点在 v0.2.0 期间对 SearchBar.tsx 的一次重构:

  • 在 commit fede78a 中,useSearchShortcuts 被移除(同时 SearchShortcutsHelp 也被移除)
  • 结果是 Ctrl/Cmd+K、Ctrl/Cmd+Shift+F、/、Esc 这些全局搜索快捷键从该版本开始失效

本 PR 已一并修复:

  • SearchBar 中恢复挂载 useSearchShortcuts
  • 重新接回 focus/clear/toggle filter 的快捷键行为
  • 同时保留本次 issue 的 token 粘贴修复

这样 #52 反馈的“首次登录无法粘贴 token + 快捷键失效”两个问题都覆盖到了。

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/components/SearchBar.tsx (1)

513-528: Consider memoizing callbacks with useCallback to reduce listener churn.

The inline arrow functions are recreated on every render, causing the hook's useEffect to re-register the keydown listener each time. While the cleanup works correctly (no listener stacking), this results in unnecessary DOM operations.

♻️ Proposed optimization
+  const focusSearch = useCallback(() => {
+    searchInputRef.current?.focus();
+    if (!searchQuery && searchHistory.length > 0) {
+      setShowSearchHistory(true);
+    }
+  }, [searchQuery, searchHistory.length]);
+
+  const clearSearchAndFocus = useCallback(() => {
+    handleClearSearch();
+    searchInputRef.current?.focus();
+  }, [handleClearSearch]);
+
+  const toggleFilters = useCallback(() => {
+    setShowFilters(prev => !prev);
+  }, []);
+
   // 全局快捷键支持(Ctrl/Cmd+K、Ctrl/Cmd+Shift+F、/、Escape)
   useSearchShortcuts({
-    onFocusSearch: () => {
-      searchInputRef.current?.focus();
-      if (!searchQuery && searchHistory.length > 0) {
-        setShowSearchHistory(true);
-      }
-    },
-    onClearSearch: () => {
-      handleClearSearch();
-      searchInputRef.current?.focus();
-    },
-    onToggleFilters: () => {
-      setShowFilters(prev => !prev);
-    },
+    onFocusSearch: focusSearch,
+    onClearSearch: clearSearchAndFocus,
+    onToggleFilters: toggleFilters,
   });

Note: You'll also need to wrap handleClearSearch in useCallback for this to be fully effective.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/SearchBar.tsx` around lines 513 - 528, The inline callbacks
passed to useSearchShortcuts (onFocusSearch, onClearSearch, onToggleFilters) are
recreated each render and cause the hook to re-register its keydown listener;
wrap these handlers in React.useCallback (e.g., memoize onFocusSearch,
onClearSearch, onToggleFilters) and update useSearchShortcuts to receive the
memoized functions, and also memoize handleClearSearch itself so onClearSearch
remains stable; ensure dependencies include searchInputRef, searchQuery,
searchHistory, setShowSearchHistory, handleClearSearch, setShowFilters as
appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/components/SearchBar.tsx`:
- Around line 513-528: The inline callbacks passed to useSearchShortcuts
(onFocusSearch, onClearSearch, onToggleFilters) are recreated each render and
cause the hook to re-register its keydown listener; wrap these handlers in
React.useCallback (e.g., memoize onFocusSearch, onClearSearch, onToggleFilters)
and update useSearchShortcuts to receive the memoized functions, and also
memoize handleClearSearch itself so onClearSearch remains stable; ensure
dependencies include searchInputRef, searchQuery, searchHistory,
setShowSearchHistory, handleClearSearch, setShowFilters as appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 99bfb0ca-301d-4373-b4c7-1612a2171160

📥 Commits

Reviewing files that changed from the base of the PR and between db8ac52 and 6cd2794.

📒 Files selected for processing (1)
  • src/components/SearchBar.tsx

@AmintaCCCP
Copy link
Owner Author

收到最新反馈后做了二次 root cause 定位:

这次不是前端输入框逻辑,而是 Electron 桌面构建脚本生成的应用菜单配置 导致。

在 v0.2.x 的桌面构建里:

  • autoHideMenuBar: true
  • 菜单只保留了 View,没有 Edit 菜单项(cut/copy/paste/selectAll)

这会导致在部分平台/打包场景下,系统级编辑快捷键(Ctrl/Cmd + C/V)无法正确工作。

已在本 PR 追加修复:

  • autoHideMenuBar 改为 false
  • 菜单模板补回 Edit 菜单,包含 undo/redo/cut/copy/paste/selectAll

现在 #52 对应的三类问题都覆盖:

  1. 首次登录 token 粘贴失败
  2. 搜索快捷键失效
  3. 通用输入框 Ctrl/Cmd + C/V 失效(桌面端菜单层)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build-desktop.yml:
- Line 212: Revert the unrelated UX change: remove or restore the
autoHideMenuBar configuration change (the autoHideMenuBar: false setting) so
menu visibility is not tied to the clipboard shortcut fix, and keep the actual
paste shortcut restoration code (the block that re-enables native clipboard
accelerators via Menu.setApplicationMenu / the paste role) intact; ensure the
paste-fix remains limited to the code that manipulates Menu.setApplicationMenu
or accelerator handling and does not modify the autoHideMenuBar UI setting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c7f19c87-90b2-4ab1-b87c-8988b321f1d8

📥 Commits

Reviewing files that changed from the base of the PR and between 6cd2794 and 29227f3.

📒 Files selected for processing (1)
  • .github/workflows/build-desktop.yml

' titleBarStyle: \\'default\\', // 使用默认标题栏,避免重叠问题\\n' +
' show: false,\\n' +
' autoHideMenuBar: true, // 隐藏菜单栏\\n' +
' autoHideMenuBar: false, // 显示菜单栏,确保编辑快捷键行为一致\\n' +
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

In Electron, do menu-item accelerators from Menu.setApplicationMenu()—especially the built-in pasterole—still work whenBrowserWindow.autoHideMenuBaristrue on Windows and Linux?

💡 Result:

Yes. On Windows and Linux, setting BrowserWindow.autoHideMenuBar: true only auto-hides the visible menu bar (it reappears with Alt) and does not disable the application menu’s registered accelerators. (electronjs.org)

Electron’s own MenuItem docs note that the “accelerator works when hidden” switch is macOS-only because accelerators always work when items are hidden on Windows and Linux—so menu accelerators (including role-based ones) keep firing even if the menu bar isn’t visible. (electronjs.org)

That includes the built-in paste role (as long as you’ve set an application menu via Menu.setApplicationMenu() and you haven’t disabled registration via registerAccelerator: false). (electronjs.org)

Citations:


Decouple the menu-bar visibility change from the paste-fix.

On Windows and Linux, menu-item accelerators from Menu.setApplicationMenu()—including the built-in paste role—remain active even when autoHideMenuBar: true; the menu bar only hides visually but does not disable accelerators. Lines 287-297 alone restore native clipboard shortcuts; line 212 is an unrelated UX change and should be reconsidered.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-desktop.yml at line 212, Revert the unrelated UX
change: remove or restore the autoHideMenuBar configuration change (the
autoHideMenuBar: false setting) so menu visibility is not tied to the clipboard
shortcut fix, and keep the actual paste shortcut restoration code (the block
that re-enables native clipboard accelerators via Menu.setApplicationMenu / the
paste role) intact; ensure the paste-fix remains limited to the code that
manipulates Menu.setApplicationMenu or accelerator handling and does not modify
the autoHideMenuBar UI setting.

@AmintaCCCP AmintaCCCP merged commit 017d098 into main Mar 8, 2026
5 checks passed
@AmintaCCCP AmintaCCCP deleted the fix/issue-52-login-token-paste branch March 8, 2026 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant