Conversation
📝 WalkthroughWalkthroughAdds an anchored tray “Quick Panel” flyout: backend/capability/config updates, flyout window manager and positioning, tray event/menu integration, renderer entry + Vue components, styles, locales, and run-mode helpers. ChangesTray Quick Panel Feature
Sequence Diagram(s)sequenceDiagram
participant TauriApp as Tauri App
participant FlyoutMgr as managers::flyout
participant AppState as AppState.tray_anchor
participant Webview as WebviewWindow
participant Monitor as Monitor
TauriApp->>FlyoutMgr: setup_flyout(app)
TauriApp->>FlyoutMgr: cache_tray_rect(rect, scale)
FlyoutMgr->>AppState: store (x,y,w,h)
TauriApp->>FlyoutMgr: toggle_flyout()
alt hidden -> show
FlyoutMgr->>Monitor: resolve monitor from anchor or cursor
FlyoutMgr->>Webview: set_position & show & set_focus
FlyoutMgr->>TauriApp: emit flyout:show
else visible -> hide
FlyoutMgr->>Webview: (maybe update macOS policy) hide
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
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. Comment |
There was a problem hiding this comment.
5 issues found across 24 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src-tauri/capabilities/default.json`:
- Line 4: The default "tray-panel" entry currently inherits the full "windows"
capability; create a new minimal capability object (e.g., "tray-panel-minimal")
in the JSON that only grants the specific window operations and read-only
backend commands used by the flyout—include the window show/hide APIs and the
exact commands show_window, get_global_stat, tell_active, tell_waiting, and
tell_stopped—and remove all broad permissions (filesystem, shell, process, OS)
from that profile, then replace the "tray-panel" reference in the top-level
capabilities list with the new minimal profile name so the tray webview is
scoped to those limited commands only.
In `@src-tauri/src/lib.rs`:
- Around line 357-360: The CloseRequested handler currently returns early for
non-"main" windows, which lets the "tray-panel" be destroyed; change the logic
so that when event matches tauri::WindowEvent::CloseRequested you check for
window.label() == "tray-panel" and, instead of returning, call
api.prevent_close() and window.hide() (mirroring the main-window behavior) so
the tray-panel is hidden rather than closed, ensuring toggle_flyout/setup_flyout
can still operate on the existing window instance.
In `@src/renderer/components/Flyout/Flyout.vue`:
- Line 8: Replace the hardcoded aria-label on the element with a localized
binding (e.g. change aria-label="Total transfer speed" to a dynamic binding like
:aria-label="$t('flyout.totalTransferSpeed')" or
this.$t('flyout.totalTransferSpeed')) and add the corresponding translation key
("flyout.totalTransferSpeed") to your locale files; ensure the Flyout component
uses the app i18n instance (or this.$t) so the aria-label is translated at
runtime.
- Around line 225-242: The emit calls in methods newTask, openPreferences, and
quit can reject and prevent this.hideFlyout() from running; update each of these
methods (newTask, openPreferences, quit in Flyout.vue) to wrap the await
emit(...) call in a try { await emit(...); } finally { await this.hideFlyout();
} so hideFlyout() always runs (you may still catch/log errors inside the try if
desired) — leave openMain as-is since it only calls showMain() then
hideFlyout().
In `@src/renderer/components/Flyout/FlyoutTaskItem.vue`:
- Around line 34-47: The task action buttons in FlyoutTaskItem.vue rely only on
title for accessibility; update the button element (the one iterating
v-for="action in actions" with class "flyout-task-action") to add an explicit
aria-label attribute set to the same accessible text returned by
actionTitle(action) (i.e., aria-label="actionTitle(action)") so screen readers
get a consistent name; leave the existing :title and
`@click.stop`="onActionClick(action)" intact and ensure no visual change to the
icons Play/Pause/Square/FolderOpen/Trash2.
In `@src/renderer/pages/index/tray.html`:
- Around line 10-20: The inline <style> block currently placed outside the
<head> (the HTML/CSS block starting with "html, body { margin: 0; ... }") must
be moved into the document <head>; locate the <style> element in
src/renderer/pages/index/tray.html, cut it from its current position and paste
it inside the <head> section (or create a <head> if missing) before the <body>,
ensuring the same CSS rules are preserved and the duplicate/empty style is
removed from the original location so document structure is valid.
In `@src/renderer/pages/index/tray.ts`:
- Around line 52-54: The current setInterval call schedules the async function
tick without awaiting it, allowing overlapping runs of tick (and its async calls
fetchGlobalStat and fetchList) when they take longer than POLL_INTERVAL; fix by
replacing the setInterval usage with a self-scheduling pattern or a running-flag
guard: modify the code around tick, timer and POLL_INTERVAL so that tick awaits
its async work before scheduling the next invocation (e.g., use await tick();
then setTimeout to call tick again or add a boolean isRunning checked at the top
of tick to early-return if already running), ensuring fetchGlobalStat and
fetchList never run concurrently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 26945d6a-d86b-4c74-9631-979c8615fe17
📒 Files selected for processing (24)
src-tauri/Cargo.tomlsrc-tauri/capabilities/default.jsonsrc-tauri/risuko-bt/src/torrent.rssrc-tauri/src/commands/file_cmds.rssrc-tauri/src/lib.rssrc-tauri/src/managers/flyout.rssrc-tauri/src/managers/mod.rssrc-tauri/src/managers/tray.rssrc-tauri/src/state.rssrc-tauri/tauri.conf.jsonsrc/renderer/components/Flyout/Flyout.vuesrc/renderer/components/Flyout/FlyoutTaskItem.vuesrc/renderer/pages/index/main.tssrc/renderer/pages/index/tray.htmlsrc/renderer/pages/index/tray.tssrc/renderer/styles/flyout.csssrc/shared/constants.tssrc/shared/locales/en-US/app.tssrc/shared/locales/en-US/task.tssrc/shared/locales/zh-CN/app.tssrc/shared/locales/zh-CN/task.tssrc/shared/locales/zh-TW/app.tssrc/shared/locales/zh-TW/task.tsvite.renderer.config.ts
| "identifier": "default", | ||
| "description": "Default capabilities for Risuko", | ||
| "windows": ["main"], | ||
| "windows": ["main", "tray-panel"], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Inspect tray/flyout renderer invoke surface (what permissions are actually needed).
fd -i 'tray\.ts|Flyout\.vue|FlyoutTaskItem\.vue' src/renderer \
| xargs -r rg -n -C2 '\binvoke\s*\('
# 2) Inspect backend command exposure list for mapping.
rg -n -C2 'generate_handler!\[' src-tauri/src/lib.rs
# 3) Review current capability grants applied to tray-panel.
cat src-tauri/capabilities/default.jsonRepository: YueMiyuki/Risuko
Length of output: 2430
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Get full list of handlers exposed by generate_handler!
rg -n 'generate_handler!\[' src-tauri/src/lib.rs -A 100
# 2) Search all invoke calls in Flyout and related tray components (broader search)
find src/renderer -type f \( -name "*.vue" -o -name "*.ts" \) -path "*[Ff]lyout*" -o -path "*[Tt]ray*" | head -20
# 3) Check if other capability profiles exist
find src-tauri/capabilities -type f -name "*.json"
# 4) Search for all invoke calls across tray-related files more thoroughly
rg -n 'invoke\(' src/renderer --glob '*[Tt]ray*' -B 2 -A 2Repository: YueMiyuki/Risuko
Length of output: 5773
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Check desktop.json to understand capability profiles
cat src-tauri/capabilities/desktop.json
# 2) Check tray.ts for all invoke calls (may have more than Flyout.vue)
cat src/renderer/pages/index/tray.ts
# 3) Check tray.worker.ts for invoke calls
cat src/renderer/workers/tray.worker.ts
# 4) Check if main/tauri.conf.json shows which capability applies to which window
find src-tauri -name "tauri.conf.json" -o -name "tauri.conf.*.json" | xargs -r cat 2>/dev/null | head -200Repository: YueMiyuki/Risuko
Length of output: 6698
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Search for tray-panel window creation/registration
rg -n 'tray-panel' src-tauri --type rust -B 3 -A 3
# 2) Check where tray window/panel is spawned
rg -n 'tray' src-tauri/src --type rust -i | grep -i 'window\|spawn\|create' | head -20
# 3) Check store methods to understand what commands are invoked
rg -n 'fetchGlobalStat\|fetchList' src/renderer --type ts -B 2 -A 5 | head -50Repository: YueMiyuki/Risuko
Length of output: 686
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find and read the store files to see what commands are actually invoked
find src/renderer/store -type f -name "*.ts" | head -10
# 2) Check app store specifically for what commands are invoked
rg -n 'fetchGlobalStat|fetchList' src/renderer/store --type ts -B 2 -A 8 | head -80
# 3) Check complete WebviewWindowBuilder setup for tray-panel to confirm capability assignment
cat src-tauri/src/managers/flyout.rsRepository: YueMiyuki/Risuko
Length of output: 10200
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the api object definition to understand what commands are invoked
find src/renderer -name "api.ts" -o -name "api.js" | head -5
# Check what fetchGlobalStat and fetchList actually call
rg -n 'fetchGlobalStat|fetchList' src/renderer/store/app.ts -B 2 -A 8
# Verify the api calls for these methods
rg -n 'fetchTaskList\|fetchGlobalStat' src/renderer -A 3 -B 1 | grep -E '(invoke|api\.)' | head -30Repository: YueMiyuki/Risuko
Length of output: 734
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find api definitions
find src/renderer -type f \( -name "*.ts" -o -name "*.js" \) | xargs rg -l "getGlobalStat\|fetchTaskList" | head -5
# Look for the api module/service
find src/renderer -type d -name "api*" -o -name "service*" | head -5
# Search for where getGlobalStat is defined
rg -n "getGlobalStat|fetchTaskList" src/renderer --type ts | grep "=\|:" | head -20Repository: YueMiyuki/Risuko
Length of output: 44
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Simple search for where api is imported/defined
rg -n "const api\|export.*api\|import.*api" src/renderer/store/app.ts
# Also check the imports at top of app.ts
head -30 src/renderer/store/app.ts
# Find all files with "api" in the name
fd -i "api" src/renderer --type fRepository: YueMiyuki/Risuko
Length of output: 42
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the beginning of app.ts to see imports
head -50 src/renderer/store/app.ts
# Simple list of files in store directory
ls -la src/renderer/store/
# Try to find where "api" variable comes from
rg "import.*api\|const api" src/renderer/store/ --type ts -nRepository: YueMiyuki/Risuko
Length of output: 1902
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the api directory/file
find src/renderer -path "*api*" -type f | grep -v node_modules
# Check if it's a directory
ls -la src/renderer/api/ 2>/dev/null || ls -la src/renderer/api.ts 2>/dev/null || echo "Not found, searching..."
# Search for `@/api` alias definition and api files
rg -n "getGlobalStat|get_global_stat" src/renderer --type ts -B 1 -A 3 | head -50Repository: YueMiyuki/Risuko
Length of output: 967
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the complete Api.ts file to see all commands tray-panel can invoke
cat src/renderer/api/Api.tsRepository: YueMiyuki/Risuko
Length of output: 20797
Scope tray-panel to a minimal capability set.
Line 4 adds tray-panel to the default capability, which grants it all 80+ exposed commands and broad permissions including shell execution, file access, process control, and OS operations. However, the flyout only calls 4 read-only backend commands: show_window, get_global_stat, tell_active, tell_waiting, and tell_stopped. If the tray panel webview is compromised, an attacker gains access to file operations, process management, and shell execution across the entire application. Create a dedicated minimal capability profile for tray-panel with only the window show/hide operations and the specific read-only query commands it uses.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src-tauri/capabilities/default.json` at line 4, The default "tray-panel"
entry currently inherits the full "windows" capability; create a new minimal
capability object (e.g., "tray-panel-minimal") in the JSON that only grants the
specific window operations and read-only backend commands used by the
flyout—include the window show/hide APIs and the exact commands show_window,
get_global_stat, tell_active, tell_waiting, and tell_stopped—and remove all
broad permissions (filesystem, shell, process, OS) from that profile, then
replace the "tray-panel" reference in the top-level capabilities list with the
new minimal profile name so the tray webview is scoped to those limited commands
only.
…p, fix macOS activation on hide
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/renderer/pages/index/tray.ts (1)
149-156:⚠️ Potential issue | 🟠 Major | ⚡ Quick winStartup
.catchdoes not handleinit()failures.Line 152 calls
init(config)but does not return/await it, so a rejection frominitcan bypass the.catchat Line 154.Proposed fix
usePreferenceStore() .fetchPreference() .then((config) => { - init(config); + return init(config); }) .catch((err: unknown) => { logger.warn("[Risuko] flyout init failed:", err); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/renderer/pages/index/tray.ts` around lines 149 - 156, The current startup chain calls init(config) inside the .then callback without returning or awaiting it, so any rejection from init(config) escapes the outer .catch; modify the .then handler to return the Promise from init(config) (or make the callback async and await init(config)) so that rejections propagate to the existing .catch; look for the fetchPreference().then(...) block in tray.ts and ensure init(config) is returned/awaited there.
♻️ Duplicate comments (1)
src/renderer/pages/index/tray.ts (1)
57-67:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPolling still allows concurrent fetch cycles.
Line 74 triggers
tick()and Line 75 schedulesloopimmediately; iftick()is still running when the timeout fires,fetchGlobalStat/fetchListcan overlap. Line 130 can also start another unsynchronizedtick().Proposed fix
function startPolling() { const appStore = useAppStore(); const taskStore = useTaskStore(); let timer: number | null = null; let running = false; + let inFlight = false; + const pollOnce = async () => { + if (document.hidden || inFlight) { + return; + } + inFlight = true; + try { + await appStore.fetchGlobalStat(); + await taskStore.fetchList(); + } catch (err) { + logger.warn("[Risuko] flyout poll failed:", (err as Error).message); + } finally { + inFlight = false; + } + }; + const scheduleNext = () => { if (running) { timer = window.setTimeout(loop, POLL_INTERVAL); } }; const loop = async () => { - if (!running || document.hidden) { + if (!running) { scheduleNext(); return; } - try { - await appStore.fetchGlobalStat(); - await taskStore.fetchList(); - } catch (err) { - logger.warn("[Risuko] flyout poll failed:", (err as Error).message); - } + await pollOnce(); scheduleNext(); }; - const tick = async () => { - if (document.hidden) { - return; - } - try { - await appStore.fetchGlobalStat(); - await taskStore.fetchList(); - } catch (err) { - logger.warn("[Risuko] flyout poll failed:", (err as Error).message); - } - }; + const tick = async () => pollOnce();Also applies to: 69-76, 127-131
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/renderer/pages/index/tray.ts` around lines 57 - 67, The poll allows overlapping runs because tick() is called without synchronization; change the polling logic to serialize invocations by adding a reentrancy guard (e.g., a boolean "isPolling" or a simple mutex) used by tick() and any external triggers so that if isPolling is true you skip or queue the request; ensure the loop/scheduler waits for tick() to finish before scheduling the next timeout (i.e., schedule setTimeout after awaiting tick()), and update any other callers (the unsynchronized start at the other trigger) to check the same guard or enqueue a single run so appStore.fetchGlobalStat and taskStore.fetchList cannot run concurrently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src-tauri/capabilities/tray-panel.json`:
- Around line 4-11: The tray-panel window currently still inherits full default
permissions because the "tray-panel" entry remains in the default capabilities'
"windows" list; remove "tray-panel" from the default capability's windows array
(so only the specialized tray-panel manifest's "windows": ["tray-panel"]
manifest applies) and verify no other capability manifests include "tray-panel"
in their "windows" scopes to enforce the intended least-privilege isolation.
---
Outside diff comments:
In `@src/renderer/pages/index/tray.ts`:
- Around line 149-156: The current startup chain calls init(config) inside the
.then callback without returning or awaiting it, so any rejection from
init(config) escapes the outer .catch; modify the .then handler to return the
Promise from init(config) (or make the callback async and await init(config)) so
that rejections propagate to the existing .catch; look for the
fetchPreference().then(...) block in tray.ts and ensure init(config) is
returned/awaited there.
---
Duplicate comments:
In `@src/renderer/pages/index/tray.ts`:
- Around line 57-67: The poll allows overlapping runs because tick() is called
without synchronization; change the polling logic to serialize invocations by
adding a reentrancy guard (e.g., a boolean "isPolling" or a simple mutex) used
by tick() and any external triggers so that if isPolling is true you skip or
queue the request; ensure the loop/scheduler waits for tick() to finish before
scheduling the next timeout (i.e., schedule setTimeout after awaiting tick()),
and update any other callers (the unsynchronized start at the other trigger) to
check the same guard or enqueue a single run so appStore.fetchGlobalStat and
taskStore.fetchList cannot run concurrently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 25a7f4c7-864b-420c-adf7-fee32ae8b4b8
📒 Files selected for processing (11)
src-tauri/capabilities/tray-panel.jsonsrc-tauri/src/lib.rssrc-tauri/src/managers/flyout.rssrc/renderer/components/Flyout/Flyout.vuesrc/renderer/components/Flyout/FlyoutTaskItem.vuesrc/renderer/pages/index/tray.htmlsrc/renderer/pages/index/tray.tssrc/renderer/styles/flyout.csssrc/shared/locales/en-US/app.tssrc/shared/locales/zh-CN/app.tssrc/shared/locales/zh-TW/app.ts
There was a problem hiding this comment.
4 issues found across 11 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src-tauri/capabilities/tray-panel.json">
<violation number="1" location="src-tauri/capabilities/tray-panel.json:1">
P2: Misleading security description: `tray-panel.json` claims "No filesystem, shell, process, OS, or dialog access", but `default.json` already includes `"tray-panel"` in its `windows` list and grants all of those permissions. In Tauri v2, capability permissions are unioned — so the restrictive intent is entirely defeated. Remove `"tray-panel"` from `default.json`'s windows array if the intent is genuine restriction, or update the description to match reality.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| @@ -0,0 +1,13 @@ | |||
| { | |||
There was a problem hiding this comment.
P2: Misleading security description: tray-panel.json claims "No filesystem, shell, process, OS, or dialog access", but default.json already includes "tray-panel" in its windows list and grants all of those permissions. In Tauri v2, capability permissions are unioned — so the restrictive intent is entirely defeated. Remove "tray-panel" from default.json's windows array if the intent is genuine restriction, or update the description to match reality.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src-tauri/capabilities/tray-panel.json:
<comment>Misleading security description: `tray-panel.json` claims "No filesystem, shell, process, OS, or dialog access", but `default.json` already includes `"tray-panel"` in its `windows` list and grants all of those permissions. In Tauri v2, capability permissions are unioned — so the restrictive intent is entirely defeated. Remove `"tray-panel"` from `default.json`'s windows array if the intent is genuine restriction, or update the description to match reality.</comment>
<file context>
@@ -0,0 +1,13 @@
+{
+ "identifier": "tray-panel",
+ "description": "Minimal capabilities for the tray flyout panel. Grants only window management, store access, and the invoke channel needed for flyout commands (show_window, get_global_stat, tell_active, tell_waiting, tell_stopped, pause/unpause/remove task, add_uri, open_path, reveal_in_folder). No filesystem, shell, process, OS, or dialog access.",
+ "windows": ["tray-panel"],
+ "permissions": [
+ "core:default",
+ "core:window:allow-show",
+ "core:window:allow-hide",
+ "core:window:allow-set-focus",
</file context>
There was a problem hiding this comment.
1 issue found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src-tauri/capabilities/tray-panel.json">
<violation number="1" location="src-tauri/capabilities/tray-panel.json:1">
P2: Misleading security description: `tray-panel.json` claims "No filesystem, shell, process, OS, or dialog access", but `default.json` already includes `"tray-panel"` in its `windows` list and grants all of those permissions. In Tauri v2, capability permissions are unioned — so the restrictive intent is entirely defeated. Remove `"tray-panel"` from `default.json`'s windows array if the intent is genuine restriction, or update the description to match reality.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/renderer/pages/index/tray.ts (1)
36-70:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUnify poll concurrency guard across both poll paths.
isPollingprotectstick(), butloop()bypasses it and can still overlap the same fetches withtick(). The race source is split polling logic.Proposed fix
let timer: number | null = null; let running = false; let isPolling = false; +const pollOnce = async () => { + if (document.hidden || isPolling) { + return; + } + isPolling = true; + try { + await appStore.fetchGlobalStat(); + await taskStore.fetchList(); + } catch (err) { + logger.warn("[Risuko] flyout poll failed:", (err as Error).message); + } finally { + isPolling = false; + } +}; + const loop = async () => { if (!running || document.hidden) { scheduleNext(); return; } - try { - await appStore.fetchGlobalStat(); - await taskStore.fetchList(); - } catch (err) { - logger.warn("[Risuko] flyout poll failed:", (err as Error).message); - } + await pollOnce(); scheduleNext(); }; const tick = async () => { - if (document.hidden || isPolling) { - return; - } - isPolling = true; - try { - await appStore.fetchGlobalStat(); - await taskStore.fetchList(); - } catch (err) { - logger.warn("[Risuko] flyout poll failed:", (err as Error).message); - } finally { - isPolling = false; - } + await pollOnce(); };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/renderer/pages/index/tray.ts` around lines 36 - 70, The loop() and tick() functions both perform the same fetches but only tick() uses the isPolling guard, causing overlapping polls; refactor so both paths share a single guarded polling routine (e.g. extract a doPoll/performPoll function) that checks and sets isPolling (or uses an equivalent atomic guard) and does the await appStore.fetchGlobalStat() and await taskStore.fetchList(), then have loop() and tick() call that shared function and scheduleNext() as before; ensure the guard is set before the awaits and cleared in finally so no concurrent fetches occur.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/renderer/components/Flyout/Flyout.vue`:
- Around line 316-321: The logger.warn call in the Flyout.vue catch block is
exposing the raw user-provided uri; modify the catch to avoid logging full URIs
by removing the raw uri from the log and instead logging a redacted/hashed
identifier or a static message. Update the block around taskStore.addUri and
logger.warn so errors still push the err.message into errors, but logger.warn
only includes a safe placeholder or derived non-sensitive token (e.g., a
truncated/hashed uri or "REDACTED_URI") along with the error object; ensure
references remain to taskStore.addUri, errors, and logger.warn so the change is
localized.
---
Duplicate comments:
In `@src/renderer/pages/index/tray.ts`:
- Around line 36-70: The loop() and tick() functions both perform the same
fetches but only tick() uses the isPolling guard, causing overlapping polls;
refactor so both paths share a single guarded polling routine (e.g. extract a
doPoll/performPoll function) that checks and sets isPolling (or uses an
equivalent atomic guard) and does the await appStore.fetchGlobalStat() and await
taskStore.fetchList(), then have loop() and tick() call that shared function and
scheduleNext() as before; ensure the guard is set before the awaits and cleared
in finally so no concurrent fetches occur.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 27d3f121-4465-4488-85d8-6d4a76c3dcc7
📒 Files selected for processing (5)
src-tauri/capabilities/tray-panel.jsonsrc-tauri/src/lib.rssrc-tauri/src/managers/flyout.rssrc/renderer/components/Flyout/Flyout.vuesrc/renderer/pages/index/tray.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src-tauri/src/utils/run_mode.rs`:
- Around line 4-7: is_tray_mode references RUN_MODE_TRAY and
RUN_MODE_HIDE_TRAY_LEGACY but those constants are currently only defined under
#[cfg(target_os = "macos")], causing cross-target compile failures; remove the
macOS-only cfg on the constants so RUN_MODE_TRAY and RUN_MODE_HIDE_TRAY_LEGACY
are defined for all targets (keep their numeric values), ensuring is_tray_mode
can compile anywhere without changing its logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 388dcfe5-8dcf-43ed-9d05-6e5c988f3863
📒 Files selected for processing (7)
src-tauri/src/commands/app_cmds.rssrc-tauri/src/lib.rssrc-tauri/src/managers/flyout.rssrc-tauri/src/utils/mod.rssrc-tauri/src/utils/run_mode.rssrc/renderer/components/Flyout/Flyout.vuesrc/renderer/pages/index/tray.ts
There was a problem hiding this comment.
1 issue found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src-tauri/capabilities/tray-panel.json">
<violation number="1" location="src-tauri/capabilities/tray-panel.json:1">
P2: Misleading security description: `tray-panel.json` claims "No filesystem, shell, process, OS, or dialog access", but `default.json` already includes `"tray-panel"` in its `windows` list and grants all of those permissions. In Tauri v2, capability permissions are unioned — so the restrictive intent is entirely defeated. Remove `"tray-panel"` from `default.json`'s windows array if the intent is genuine restriction, or update the description to match reality.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Summary by cubic
Adds a new tray “Quick Panel” flyout for fast task control without opening the main app. Improves anchoring, focus/blur auto‑hide, and macOS activation for a smoother, more consistent experience.
New Features
tray-panelwith task list, total transfer speeds, per‑task actions (pause/resume/stop seeding/open/delete), search/filter, add‑URI input, and keyboard tab navigation.en-US,zh-CN,zh-TW; consistent border‑radius; removed menu bar gap; on macOS, uses Accessory activation policy when hiding in tray modes.Dependencies
taurifeaturemacos-private-api; setapp.macOSPrivateApito true.tray-panelcapability and a flyout manager; stored tray anchor in app state.utils/run_modeto centralize run‑mode and macOS activation policy; used by commands and flyout.Vitebuild to includetray.htmlviarollupOptions.input.Written for commit b1fe40a. Summary will update on new commits.
Summary by CodeRabbit