Skip to content

add cli installer in app menu#1765

Merged
yujonglee merged 2 commits intomainfrom
yl-branch-34
Nov 21, 2025
Merged

add cli installer in app menu#1765
yujonglee merged 2 commits intomainfrom
yl-branch-34

Conversation

@yujonglee
Copy link
Contributor

No description provided.

@netlify
Copy link

netlify bot commented Nov 21, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit 6610aab
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/6920187d7668af0008292e00
😎 Deploy Preview https://deploy-preview-1765--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Refactors the CLI plugin to expose a concrete PluginCli and centralizes CLI operations behind app.plugin_cli(), adds public re-exports, updates CLI subcommands/handlers, and integrates install/uninstall CLI menu items into the tray plugin with the new workspace dependency.

Changes

Cohort / File(s) Summary
CLI Plugin Core Refactor
plugins/cli2/src/ext.rs
Replaces trait-only extension with a public PluginCli<R> struct and impl; moves CLI methods into impl PluginCli<R> (handle_cli_matches, get_cli_symlink_path, get_cli_executable_path, install_cli_to_path, uninstall_cli_from_path, check_cli_status); makes CliStatus fields public; adds CliPluginExt<R> trait with plugin_cli() accessor and impl for tauri::Manager<R>.
CLI Command Routing
plugins/cli2/src/commands.rs
Updates CLI command functions to call app.plugin_cli().<method>() and adds crate::CliPluginExt import; preserves previous error mapping and observable behavior.
CLI Handler & Subcommands
plugins/cli2/src/handler.rs, apps/desktop/src-tauri/tauri.conf.json
Handler now derives version from app package, adds/handles new subcommands (bug,web,changelog) and refactors hello -> generic URL handler; tauri.conf.json replaces hello subcommand with these three.
Public Exports
plugins/cli2/src/lib.rs
Adds pub use tauri_plugin_cli::CliExt; to publicly re-export CliExt.
Tray Plugin Dependency
plugins/tray/Cargo.toml
Adds workspace dependency tauri-plugin-cli2.
Tray Menu Integration
plugins/tray/src/ext.rs
Adds HyprMenuItem::AppCliInstall and AppCliUninstall; converts menu IDs for CLI items; adds app_cli_menu() to select install/uninstall based on PluginCli::check_cli_status; integrates CLI menu items into app menu and tray event handling and triggers install/uninstall via tauri_plugin_cli2.

Sequence Diagram(s)

sequenceDiagram
    participant App as App (Manager)
    participant PluginCli as PluginCli
    participant File as FileSystem
    participant Tray as Tray/Menu
    participant Ext as tauri_plugin_cli (CliExt)

    App->>PluginCli: plugin_cli()                          %% accessor
    activate PluginCli

    App->>PluginCli: check_cli_status()
    PluginCli->>File: resolve symlink & target
    File-->>PluginCli: exists / target path
    PluginCli-->>App: CliStatus { is_installed, symlink_path, target_path }

    alt User selects Install via Tray
        Tray->>App: Menu event (AppCliInstall)
        App->>PluginCli: install_cli_to_path()
        PluginCli->>PluginCli: get_cli_executable_path()
        PluginCli->>Ext: app.cli().matches() / plugin data
        Ext-->>PluginCli: CLI matches/info
        PluginCli->>File: create parent dir + create symlink or copy
        File-->>PluginCli: success
        PluginCli-->>App: Ok
        App->>Tray: refresh app menu (app_cli_menu)
    else User selects Uninstall via Tray
        Tray->>App: Menu event (AppCliUninstall)
        App->>PluginCli: uninstall_cli_from_path()
        PluginCli->>File: remove symlink/cleanup
        File-->>PluginCli: success
        PluginCli-->>App: Ok
        App->>Tray: refresh app menu (app_cli_menu)
    end

    deactivate PluginCli
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review focus areas:
    • plugins/cli2/src/ext.rs: platform-specific path/symlink logic, error handling, public API surface.
    • plugins/tray/src/ext.rs: menu integration, MenuId conversions, event wiring and post-action menu refresh.
    • plugins/cli2/src/handler.rs + apps/desktop/src-tauri/tauri.conf.json: new subcommands behavior and URL handling.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to assess whether the description relates to the changeset. Add a pull request description explaining the changes, such as why the CLI installer is being added to the app menu and how it integrates with the existing menu system.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'add cli installer in app menu' accurately describes the primary change—integrating CLI installation/uninstallation functionality into the app menu via new HyprMenuItem variants and menu handling.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d90a2ec and 6610aab.

📒 Files selected for processing (2)
  • apps/desktop/src-tauri/tauri.conf.json (1 hunks)
  • plugins/cli2/src/handler.rs (2 hunks)

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

Copy link
Contributor

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/tray/src/ext.rs (1)

63-88: Add submenu item count validation before remove operations (lines 76–77)

The code performs two consecutive remove_at(0)? calls on the submenu without validating that the submenu has at least 2 items. If the submenu has fewer items than expected, the second removal will fail at runtime. Add a guard on the submenu's item count before these operations, or use a more defensive approach to replace specific entries.

if let MenuItemKind::Submenu(submenu) = &items[0] {
    let submenu_items = submenu.items()?;
    if submenu_items.len() >= 2 {
        submenu.remove_at(0)?;
        submenu.remove_at(0)?;
        submenu.prepend(&cli_item)?;
        submenu.prepend(&info_item)?;
    }
}
🧹 Nitpick comments (3)
plugins/tray/src/ext.rs (2)

115-184: CLI install/uninstall actions silently ignore failures

For AppCliInstall/AppCliUninstall, errors from app.plugin_cli().{install,uninstall}_cli_from_path() and from app.create_app_menu() are discarded (if let Ok(_) = ... { let _ = ...; }). This keeps the flow simple but makes it hard to diagnose permission/path issues (e.g., Windows symlink privileges, non‑symlink path errors). You might want to at least log these errors (or surface a dialog) so users and logs can see why install/uninstall did nothing.


235-261: CLI menu label toggling based on CliStatus

app_cli_menu correctly checks plugin_cli().check_cli_status().map(|status| status.is_installed).unwrap_or(false) and switches between “Install CLI” and “Uninstall CLI” menu IDs/labels. On unsupported platforms where check_cli_status might error, this gracefully falls back to showing “Install CLI”. If you ever want to hide the CLI option entirely when the platform is unsupported, you could treat specific error variants (e.g., UnsupportedPlatform) differently here.

plugins/cli2/src/ext.rs (1)

53-112: Install/uninstall logic and safety checks

install_cli_to_path and uninstall_cli_from_path are generally well‑behaved:

  • Parent directories are created before symlink creation.
  • Existing files are removed before creating a new symlink.
  • Uninstall uses symlink_metadata and only removes the path when it’s actually a symlink, returning NonSymlinkCliPath otherwise.

This minimizes the risk of deleting an arbitrary non‑CLI file. The only behavior you might want to consider later is distinguishing UnsupportedPlatform at the call sites (e.g., to hide or disable CLI install UI) instead of letting it bubble up silently.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e52260 and d90a2ec.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • plugins/cli2/src/commands.rs (1 hunks)
  • plugins/cli2/src/ext.rs (6 hunks)
  • plugins/cli2/src/lib.rs (1 hunks)
  • plugins/tray/Cargo.toml (1 hunks)
  • plugins/tray/src/ext.rs (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
plugins/cli2/src/commands.rs (1)
plugins/cli2/src/ext.rs (1)
  • check_cli_status (114-132)
plugins/cli2/src/ext.rs (1)
plugins/cli2/src/commands.rs (1)
  • check_cli_status (23-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: fmt
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (7)
plugins/tray/Cargo.toml (1)

22-22: New tauri-plugin-cli2 workspace dependency

Adding tauri-plugin-cli2 = { workspace = true } matches the existing dependency style. Just ensure the crate is correctly defined as a workspace member (name and features) so this resolves as expected in all builds.

plugins/cli2/src/lib.rs (1)

9-10: Publicly re-exporting CliExt from tauri-plugin-cli

Re‑exporting CliExt here is fine and doesn’t conflict with local names; it effectively makes CliExt part of this crate’s public surface. Please confirm that exposing this trait from cli2 is intentional (i.e., expected to be used by downstream crates) and not just for internal convenience.

plugins/cli2/src/commands.rs (1)

1-29: Commands correctly routed through plugin_cli()

Using app.plugin_cli().{install_cli_to_path, uninstall_cli_from_path, check_cli_status} with the CliPluginExt import cleanly centralizes CLI behavior behind PluginCli while preserving the existing Result<_, String> surface via map_err(|e| e.to_string()). No functional regressions are apparent here.

plugins/tray/src/ext.rs (1)

15-53: Menu enum ↔ ID mapping looks consistent

The new HyprMenuItem::AppCliInstall / AppCliUninstall variants and their MenuId string mappings are symmetrical and consistent with the existing naming scheme, so event routing via HyprMenuItem::from(MenuId) should work as expected.

plugins/cli2/src/ext.rs (3)

3-25: PluginCli wrapper and handle_cli_matches behavior

Wrapping CLI operations in PluginCli<R> tied to an AppHandle is a clean way to centralize this logic. One notable semantic change is in handle_cli_matches: on error it now prints to stderr and calls std::process::exit(1) instead of propagating the error, while --help/--version exit with code 0. That’s appropriate for a CLI entrypoint, but it does mean callers cannot recover or log differently; please confirm this “hard exit” behavior is what you want for all usages of handle_cli_matches.


26-52: Symlink path selection and executable resolution

get_cli_symlink_path choosing $HOME/.local/bin/hyprnote (or %USERPROFILE%\\.local\\bin\\hyprnote.exe on Windows) keeps everything in user‑writable locations, with sensible fallbacks. get_cli_executable_path using std::env::current_exe() is also a straightforward way to locate the running binary for symlinking. Both look reasonable; just be aware that on Windows, creating symlinks may require additional privileges, so you’ll likely see PermissionDenied errors in the wild.


114-153: check_cli_status, CliPluginExt, and CliStatus API shape

check_cli_status returning a simple CliStatus with is_installed, symlink_path, and target_path matches the tray’s needs and keeps the API straightforward. The new CliPluginExt trait providing plugin_cli() for any Manager<R> (including AppHandle) is idiomatic and integrates cleanly with call sites like app.plugin_cli().check_cli_status(). Public fields on CliStatus are fine here given it’s a pure data carrier.

@yujonglee yujonglee merged commit fa40d0a into main Nov 21, 2025
6 of 8 checks passed
@yujonglee yujonglee deleted the yl-branch-34 branch November 21, 2025 07:45
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