Skip to content

Comments

Location-Based Models#921

Closed
plyght wants to merge 16 commits intofastrepl:mainfrom
plyght:location-pro
Closed

Location-Based Models#921
plyght wants to merge 16 commits intofastrepl:mainfrom
plyght:location-pro

Conversation

@plyght
Copy link
Contributor

@plyght plyght commented Jun 6, 2025

fixes #918

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 6, 2025

📝 Walkthrough

Walkthrough

This change introduces a new "location-connectivity" plugin for Tauri, featuring both backend (Rust) and frontend (TypeScript/React) components. It enables the application to detect the current Wi-Fi SSID (with macOS support), manage trusted networks, and automatically switch to cloud AI when in trusted locations. The plugin is integrated into the desktop app, with new UI elements for managing location-based connectivity settings.

Changes

File(s) / Path(s) Change Summary
Cargo.toml, apps/desktop/package.json, apps/desktop/src-tauri/Cargo.toml, plugins/connector/Cargo.toml Added tauri-plugin-location-connectivity as a dependency in workspace, desktop app, and connector plugin
apps/desktop/src-tauri/src/lib.rs Initialized the location-connectivity plugin in the Tauri application builder
apps/desktop/src/components/settings/views/lab.tsx Added LocationBasedConnectivity React component and integrated it into the Lab settings view
apps/desktop/src/locales/en/messages.po, apps/desktop/src/locales/ko/messages.po, apps/docs/data/i18n.json Updated localization files with new message IDs and references for location-based connectivity
packages/utils/src/navigation.ts, packages/utils/src/stores/ongoing-session.ts, plugins/apple-calendar/src/sync.rs Refactored or removed internal comments for clarity; no logic changes
plugins/location-connectivity/ (multiple new files: Cargo.toml, build.rs, js/, src/, permissions/, etc.) Introduced new plugin: backend Rust implementation (SSID detection, trusted SSID management, state/event system, macOS support), TypeScript API bindings, permissions, and configuration files
plugins/connector/src/ext.rs Added cloud connection decision logic based on location status; integrated with new plugin
plugins/location-connectivity/js/index.ts, bindings.gen.ts Added TypeScript interface for plugin commands and events
plugins/location-connectivity/src/commands.rs, src/ext.rs, src/store.rs, src/types.rs, src/error.rs, src/wifi_macos.rs, src/lib.rs Implemented backend logic for location status, SSID detection, trusted SSID management, event emission, error handling, and plugin initialization
plugins/location-connectivity/permissions/, default.toml, schemas/schema.json, reference.md Added permissions configuration, schema, and documentation for plugin commands

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ReactUI as LocationBasedConnectivity (React)
    participant TypeScript as location-connectivity (TS API)
    participant Tauri as Tauri Backend
    participant Plugin as LocationConnectivity Plugin
    participant Store as Store2
    participant OS as macOS WiFi

    User->>ReactUI: Toggle location-based connectivity / manage SSIDs
    ReactUI->>TypeScript: Call commands (get/set SSIDs, enable/disable, get status)
    TypeScript->>Tauri: Invoke plugin commands
    Tauri->>Plugin: get_current_ssid / add_trusted_ssid / etc.
    Plugin->>OS: Query current WiFi SSID (macOS only)
    OS-->>Plugin: Return SSID
    Plugin->>Store: Read/write trusted SSIDs, settings
    Store-->>Plugin: Return data
    Plugin->>Tauri: Emit location event if status changes
    Tauri->>TypeScript: Forward event to JS
    TypeScript->>ReactUI: onLocationChanged callback
    ReactUI-->>User: Update UI
Loading
sequenceDiagram
    participant Tauri as Tauri Backend
    participant Connector as Connector Plugin
    participant Location as LocationConnectivity Plugin

    Tauri->>Connector: get_llm_connection / get_stt_connection
    Connector->>Location: should_use_cloud_for_location
    Location-->>Connector: Return should_use_cloud (true/false)
    Connector-->>Tauri: Return cloud connection if should_use_cloud is true, else fallback
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement location-based connectivity via MacOS location API or WiFi SSID detection (#918)
Provide ability to manage trusted WiFi SSIDs and enable/disable location-based switching (#918)
Integrate automatic model switching (cloud/local) based on trusted location status (#918)
Expose UI and API for managing location-based connectivity in the desktop app (#918)

Assessment against linked issues: Out-of-scope changes

No out-of-scope functional code changes were found. All significant changes align with the objectives of implementing location-based connectivity via WiFi SSID detection and trusted network management, as described in the linked issue. Minor comment refactoring and localization updates are incidental and not functionally out of scope.

✨ 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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 4

🔭 Outside diff range comments (2)
plugins/connector/src/ext.rs (2)

117-121: 🛠️ Refactor suggestion

Extract duplicated cloud connection logic to reduce code duplication.

The cloud connection creation logic is duplicated between the cloud preview check and the location-based check. This violates the DRY principle.

Extract the cloud connection creation to a helper method:

+    fn create_cloud_llm_connection(&self) -> Result<ConnectionLLM, crate::Error> {
+        let api_base = if cfg!(debug_assertions) {
+            "http://127.0.0.1:1234".to_string()
+        } else {
+            "https://app.hyprnote.com".to_string()
+        };
+
+        let api_key = if cfg!(debug_assertions) {
+            None
+        } else {
+            use tauri_plugin_auth::{AuthPluginExt, VaultKey};
+            self.get_from_vault(VaultKey::RemoteServer)?
+        };
+
+        Ok(ConnectionLLM::HyprCloud(Connection { api_base, api_key }))
+    }

Then use it in both locations:

-                let api_base = if cfg!(debug_assertions) {
-                    "http://127.0.0.1:1234".to_string()
-                } else {
-                    "https://app.hyprnote.com".to_string()
-                };
-
-                return Ok(ConnectionLLM::HyprCloud(Connection {
-                    api_base,
-                    api_key: None,
-                }));
+                return self.create_cloud_llm_connection();

Also applies to: 137-141


184-188: 🛠️ Refactor suggestion

Extract duplicated STT cloud connection logic.

Similar to the LLM connection, the STT cloud connection creation is duplicated.

Create a helper method for STT cloud connections:

+    fn create_cloud_stt_connection(&self) -> Result<ConnectionSTT, crate::Error> {
+        let api_base = if cfg!(debug_assertions) {
+            "http://127.0.0.1:1234".to_string()
+        } else {
+            "https://app.hyprnote.com".to_string()
+        };
+
+        let api_key = if cfg!(debug_assertions) {
+            None
+        } else {
+            use tauri_plugin_auth::{AuthPluginExt, VaultKey};
+            self.get_from_vault(VaultKey::RemoteServer)?
+        };
+
+        Ok(ConnectionSTT::HyprCloud(Connection { api_base, api_key }))
+    }

Also applies to: 204-208

🧹 Nitpick comments (13)
packages/utils/src/stores/ongoing-session.ts (2)

139-145: Avoid magic numbers and improve comment clarity.
The 1500ms debounce is a magic number—extract it into a named constant (e.g. REFRESH_DEBOUNCE_MS) and expand the comment to explain the rationale (ensuring session data consistency post-stop).


172-178: Extract debounce duration and clarify purpose.
Mirrors the pattern in the stop method: use the same REFRESH_DEBOUNCE_MS constant and update the comment to explain why we wait before refreshing (e.g. “Wait for backend to settle before refreshing UI state”).

plugins/location-connectivity/permissions/autogenerated/reference.md (1)

5-5: Fix heading level and punctuation
Increase the heading by one level (from #### to ###) and remove the trailing colon to maintain proper Markdown structure.

-#### This default permission set includes the following:
+### This default permission set includes the following
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

5-5: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4

(MD001, heading-increment)


5-5: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

apps/desktop/src/locales/ko/messages.po (1)

374-377: New message IDs require Korean translation.

The new location-based connectivity feature strings are untranslated. Consider adding Korean translations for:

  • "Automatically switch to cloud AI when in trusted locations"
  • "Location-Based Connectivity"
plugins/connector/src/ext.rs (2)

151-152: Remove empty else block.

The empty else block serves no purpose and should be removed.

-                } else {
-                }

218-219: Remove empty else block.

-                } else {
-                }
plugins/location-connectivity/src/wifi_macos.rs (2)

50-52: Include interface name in error message for better debugging.

The error message should include which interface failed for easier troubleshooting.

-                .map_err(|e| LocationConnectivityError::WifiDetection(
-                    format!("Failed to execute networksetup: {}", e)
-                ))?;
+                .map_err(|e| LocationConnectivityError::WifiDetection(
+                    format!("Failed to execute networksetup for {}: {}", interface, e)
+                ))?;

74-88: Include error details in debug log.

When the airport command fails, the error details should be included in the debug log for better troubleshooting.

-            let output = Command::new(airport_path)
-                .arg("-I")
-                .output();
-                
-            if let Ok(output) = output {
+            match Command::new(airport_path)
+                .arg("-I")
+                .output() {
+                Ok(output) => {
                 if output.status.success() {
                     let output_str = String::from_utf8_lossy(&output.stdout);
                     
                     if let Some(ssid) = parse_airport_output(&output_str) {
                         return Ok(Some(ssid));
                     }
                 }
-            } else {
-                tracing::debug!("Failed to execute airport command at {}", airport_path);
+                }
+                Err(e) => {
+                    tracing::debug!("Failed to execute airport command at {}: {}", airport_path, e);
+                }
             }
plugins/location-connectivity/src/types.rs (1)

12-17: Consider using a proper timestamp type for added_at.

Using a String for timestamps can lead to inconsistencies and parsing issues. Consider using chrono::DateTime<Utc> or a Unix timestamp (i64) for better type safety and standardization.

+use chrono::{DateTime, Utc};

 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct TrustedLocation {
     pub ssid: String,
     pub name: Option<String>,
-    pub added_at: String,
+    pub added_at: DateTime<Utc>,
 }
plugins/location-connectivity/src/commands.rs (4)

11-16: Remove unnecessary async modifier.

The get_trusted_ssids command is marked as async but calls a synchronous store function. This is unnecessary overhead.

-#[tauri::command]
-pub async fn get_trusted_ssids(
+#[tauri::command] 
+pub fn get_trusted_ssids(
     app: AppHandle<tauri::Wry>,
 ) -> Result<Vec<String>, String> {
     crate::store::get_trusted_ssids(app).map_err(|e| e.to_string())
 }

62-67: Remove unnecessary async modifier.

The is_location_based_enabled command is marked as async but calls a synchronous store function. This is unnecessary overhead.

-#[tauri::command]
-pub async fn is_location_based_enabled(
+#[tauri::command]
+pub fn is_location_based_enabled(
     app: AppHandle<tauri::Wry>,
 ) -> Result<bool, String> {
     crate::store::get_location_based_enabled(app).map_err(|e| e.to_string())
 }

28-37: Consider extracting common post-operation logic.

Both add_trusted_ssid and remove_trusted_ssid have identical patterns for updating location status and emitting events. This duplication could be reduced.

Consider creating a helper function to handle the common post-operation logic:

async fn update_and_emit_after_ssid_change(
    state: &State<'_, LocationConnectivityState<tauri::Wry>>,
) -> Result<(), String> {
    state.update_location_status().await.map_err(|e| e.to_string())?;
    let status = state.get_location_status().await.map_err(|e| e.to_string())?;
    state.emit_location_event(LocationEventType::SettingsChanged, &status).await;
    Ok(())
}

Then use it in both commands:

crate::store::add_trusted_ssid(app, ssid).await.map_err(|e| e.to_string())?;
update_and_emit_after_ssid_change(&state).await?;

Also applies to: 50-59


24-26: Consider enhancing SSID validation.

The current validation only checks for empty SSIDs. Consider adding more comprehensive validation for Wi-Fi SSID standards.

     if ssid.trim().is_empty() {
         return Err("SSID cannot be empty".to_string());
     }
+    if ssid.len() > 32 {
+        return Err("SSID cannot exceed 32 characters".to_string());
+    }

Wi-Fi SSIDs have a maximum length of 32 bytes according to the 802.11 standard.

Also applies to: 46-48

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a8c841 and ae54093.

⛔ Files ignored due to path filters (4)
  • Cargo.lock is excluded by !**/*.lock
  • bun.lock is excluded by !**/*.lock
  • plugins/location-connectivity/bun.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (37)
  • Cargo.toml (1 hunks)
  • apps/desktop/package.json (1 hunks)
  • apps/desktop/src-tauri/Cargo.toml (1 hunks)
  • apps/desktop/src-tauri/src/lib.rs (1 hunks)
  • apps/desktop/src/components/settings/views/lab.tsx (2 hunks)
  • apps/desktop/src/locales/en/messages.po (14 hunks)
  • apps/desktop/src/locales/ko/messages.po (14 hunks)
  • apps/docs/data/i18n.json (1 hunks)
  • packages/utils/src/navigation.ts (1 hunks)
  • packages/utils/src/stores/ongoing-session.ts (2 hunks)
  • plugins/apple-calendar/src/sync.rs (0 hunks)
  • plugins/connector/Cargo.toml (1 hunks)
  • plugins/connector/src/ext.rs (4 hunks)
  • plugins/location-connectivity/Cargo.toml (1 hunks)
  • plugins/location-connectivity/build.rs (1 hunks)
  • plugins/location-connectivity/js/bindings.gen.ts (1 hunks)
  • plugins/location-connectivity/js/index.ts (1 hunks)
  • plugins/location-connectivity/package.json (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/add_trusted_ssid.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/get_current_ssid.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/get_location_status.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/get_trusted_ssids.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/is_in_trusted_location.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/is_location_based_enabled.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/remove_trusted_ssid.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/commands/set_location_based_enabled.toml (1 hunks)
  • plugins/location-connectivity/permissions/autogenerated/reference.md (1 hunks)
  • plugins/location-connectivity/permissions/default.toml (1 hunks)
  • plugins/location-connectivity/permissions/schemas/schema.json (1 hunks)
  • plugins/location-connectivity/src/commands.rs (1 hunks)
  • plugins/location-connectivity/src/error.rs (1 hunks)
  • plugins/location-connectivity/src/ext.rs (1 hunks)
  • plugins/location-connectivity/src/lib.rs (1 hunks)
  • plugins/location-connectivity/src/store.rs (1 hunks)
  • plugins/location-connectivity/src/types.rs (1 hunks)
  • plugins/location-connectivity/src/wifi_macos.rs (1 hunks)
  • plugins/location-connectivity/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • plugins/apple-calendar/src/sync.rs
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{js,ts,tsx,rs}`: 1. No error handling. 2. No unused imports, variables, or functions. 3. For comments, keep it minimal. It should be about "Why", not "What".

**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

  • packages/utils/src/navigation.ts
  • packages/utils/src/stores/ongoing-session.ts
  • plugins/location-connectivity/build.rs
  • apps/desktop/src-tauri/src/lib.rs
  • plugins/location-connectivity/src/lib.rs
  • plugins/location-connectivity/js/bindings.gen.ts
  • plugins/location-connectivity/src/error.rs
  • apps/desktop/src/components/settings/views/lab.tsx
  • plugins/location-connectivity/src/store.rs
  • plugins/location-connectivity/src/ext.rs
  • plugins/connector/src/ext.rs
  • plugins/location-connectivity/src/types.rs
  • plugins/location-connectivity/src/commands.rs
  • plugins/location-connectivity/src/wifi_macos.rs
  • plugins/location-connectivity/js/index.ts
🧬 Code Graph Analysis (2)
plugins/location-connectivity/src/types.rs (3)
plugins/location-connectivity/js/bindings.gen.ts (3)
  • LocationStatus (12-18)
  • LocationEvent (5-10)
  • LocationEventType (3-3)
plugins/location-connectivity/js/index.ts (3)
  • LocationStatus (5-5)
  • LocationEvent (6-6)
  • LocationEventType (7-7)
plugins/location-connectivity/src/ext.rs (1)
  • new (33-52)
plugins/location-connectivity/src/commands.rs (4)
plugins/location-connectivity/js/bindings.gen.ts (2)
  • LocationEventType (3-3)
  • LocationStatus (12-18)
plugins/location-connectivity/js/index.ts (2)
  • LocationEventType (7-7)
  • LocationStatus (5-5)
plugins/location-connectivity/src/ext.rs (2)
  • get_current_ssid (54-56)
  • get_location_status (58-61)
plugins/location-connectivity/src/store.rs (11)
  • get_trusted_ssids (31-36)
  • app (17-17)
  • app (25-25)
  • app (34-34)
  • app (42-42)
  • store (18-18)
  • store (35-35)
  • add_trusted_ssid (48-60)
  • remove_trusted_ssid (62-70)
  • get_location_based_enabled (14-19)
  • set_location_based_enabled (21-29)
🪛 LanguageTool
plugins/location-connectivity/permissions/autogenerated/reference.md

[uncategorized] ~137-~137: Did you mean “there is”?
Context: ...-trusted-location` Enables the is_in_trusted_location command without any...

(THE_THERE)


[uncategorized] ~150-~150: Did you mean “there is”?
Context: ...n-trusted-location` Denies the is_in_trusted_location command without any...

(THE_THERE)


[uncategorized] ~163-~163: Did you mean “there is”?
Context: ...ion-based-enabled` Enables the is_location_based_enabled command without ...

(THE_THERE)


[uncategorized] ~176-~176: Did you mean “there is”?
Context: ...tion-based-enabled` Denies the is_location_based_enabled command without ...

(THE_THERE)

🪛 markdownlint-cli2 (0.17.2)
plugins/location-connectivity/permissions/autogenerated/reference.md

5-5: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4

(MD001, heading-increment)


5-5: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ci (macos, macos-latest)
  • GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (38)
apps/desktop/package.json (1)

29-29: Add location-connectivity workspace dependency
Integrates the new @hypr/plugin-location-connectivity into the desktop app’s dependency graph.

apps/desktop/src-tauri/Cargo.toml (1)

39-39: Introduce tauri-plugin-location-connectivity dependency
Ensures the desktop Tauri build includes the new location-connectivity plugin as a workspace member.

apps/docs/data/i18n.json (1)

4-6: Update translation entry counts for new strings
Bumps both the Korean and English totals to 264 and updates the missing count for Korean accordingly, reflecting the added location-connectivity messages.

Also applies to: 9-11

apps/desktop/src-tauri/src/lib.rs (1)

78-78: Integrate the location-connectivity plugin into Tauri builder
Inserts .plugin(tauri_plugin_location_connectivity::init()) immediately after the connector plugin, making its state available for downstream logic.

plugins/connector/Cargo.toml (1)

20-20: Add tauri-plugin-location-connectivity to connector dependencies
Allows the connector extension to leverage location-based connectivity state in its decision logic.

Cargo.toml (1)

87-87: Dependency integration is correct.
The tauri-plugin-location-connectivity entry is properly added in alphabetical order under workspace.dependencies.

plugins/location-connectivity/permissions/autogenerated/commands/remove_trusted_ssid.toml (1)

1-14: Permissions file looks good.
The autogenerated allow/deny entries follow the schema and naming conventions.

plugins/location-connectivity/tsconfig.json (1)

1-10: TSConfig is set up correctly.
Using composite projects with declarations, maps, and outDir is appropriate for building the plugin’s bindings.

plugins/location-connectivity/permissions/autogenerated/commands/get_current_ssid.toml (1)

1-14: Permission config is correct and consistent.

The schema reference, identifiers (allow-get-current-ssid, deny-get-current-ssid), and corresponding commands.allow/commands.deny entries follow the established pattern for autogenerated permission files. No edits required.

plugins/location-connectivity/permissions/autogenerated/commands/get_trusted_ssids.toml (1)

1-14: Configuration aligns with the plugin’s permission schema.

The TOML file correctly references the schema, and the allow-get-trusted-ssids / deny-get-trusted-ssids entries mirror the expected structure. Ready to merge.

plugins/location-connectivity/permissions/autogenerated/commands/add_trusted_ssid.toml (1)

1-14: Autogenerated permission entries are valid.

The file adheres to the schema, and the allow-add-trusted-ssid / deny-add-trusted-ssid blocks are properly defined. No changes needed.

plugins/location-connectivity/permissions/autogenerated/commands/get_location_status.toml (1)

1-14: Schema reference and permission blocks look good.

The allow-get-location-status and deny-get-location-status entries match the project’s conventions. This file can be approved as-is.

plugins/location-connectivity/permissions/autogenerated/commands/is_in_trusted_location.toml (1)

1-14: Permission definitions are correct.

Both allow and deny permissions for is_in_trusted_location follow the established autogenerated format and reference the correct schema. Approved.

packages/utils/src/navigation.ts (1)

4-4: Comment conciseness
The new single-line comment clearly explains why the visibility check is needed and omits unnecessary details, aligning well with our minimal-comment guideline.

plugins/location-connectivity/build.rs (2)

1-10: Command list definition
The COMMANDS array accurately enumerates all plugin commands. Ensure the order here matches the handlers in src/commands.rs to avoid registration mismatches.


12-14: Build script invocation
Using tauri_plugin::Builder::new(COMMANDS).build() correctly wires up the plugin at compile time. No further error handling is needed in this context.

plugins/location-connectivity/permissions/default.toml (1)

1-12: Default permission set
The [default] block lists allow permissions for all plugin commands, directly reflecting the capabilities defined in build.rs. This ensures a coherent out-of-the-box experience.

plugins/location-connectivity/permissions/autogenerated/commands/is_location_based_enabled.toml (1)

1-14: Verify permission identifier format
The autogenerated identifiers (allow-is-location-based-enabled, deny-is-location-based-enabled) lack the location-connectivity: namespace shown in the reference docs. Confirm whether the loader/schema auto-prefixes these, or adjust the identifiers for consistency.

plugins/location-connectivity/permissions/autogenerated/commands/set_location_based_enabled.toml (1)

1-14: LGTM! Autogenerated permissions file is correctly structured.

The TOML file properly defines both allow and deny permissions for the set_location_based_enabled command with appropriate schema references.

plugins/location-connectivity/src/lib.rs (3)

1-14: Well-structured module organization.

The module declarations and conditional compilation for macOS-specific functionality are properly organized. The public exports provide a clean API surface.


19-38: Plugin initialization looks correct.

The Tauri plugin properly registers all command handlers and sets up the shared state during initialization. The state management approach using app_handle.manage(state) follows Tauri best practices.


40-51: Basic test coverage is present.

The test verifies plugin instantiation in a mocked Tauri context, which provides a foundation for ensuring the plugin can be properly initialized.

apps/desktop/src/locales/en/messages.po (2)

374-377: English translations properly added for new feature.

The location-based connectivity feature strings are correctly translated and integrated into the localization system.


705-708: Location-based connectivity title properly localized.

The feature title "Location-Based Connectivity" is correctly added to the English localization.

apps/desktop/src/components/settings/views/lab.tsx (2)

3-10: LGTM: Imports are properly used throughout the component.

All imported icons, hooks, and UI components are utilized in the LocationBasedConnectivity component implementation.


57-225: Well-implemented location-based connectivity management with good UX patterns.

The component properly handles:

  • State management with React Query
  • Real-time SSID polling every 5 seconds
  • Optimistic UI updates with mutation callbacks
  • Proper loading states and disabled buttons
  • Clear visual indicators for trusted networks

The implementation follows React best practices and provides a solid user experience for managing trusted WiFi networks.

plugins/location-connectivity/js/bindings.gen.ts (1)

1-18: Well-designed type definitions for location connectivity events and status.

The types are comprehensive and clearly structured:

  • LocationEventType covers all necessary event scenarios
  • LocationEvent provides complete event payload information
  • LocationStatus includes all relevant state information

The naming is consistent and the structure supports the plugin's functionality well.

plugins/location-connectivity/Cargo.toml (1)

1-29: Well-configured Cargo.toml with appropriate dependencies for location connectivity.

The manifest is properly structured with:

  • Correct workspace dependency usage for consistency
  • Platform-specific macOS dependencies for WiFi detection
  • Appropriate exclusions for JS assets
  • Clear package metadata

All dependencies appear necessary for the plugin's functionality.

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

242-253: LGTM!

The implementation correctly handles the case when the location-connectivity plugin is not available and provides a sensible default.

plugins/location-connectivity/js/index.ts (1)

1-42: LGTM!

The TypeScript module provides a clean API surface for the location-connectivity plugin with proper type exports and consistent command/event patterns.

plugins/location-connectivity/src/types.rs (1)

1-11: LGTM!

The type definitions are well-structured with appropriate serialization support and sensible defaults.

Also applies to: 18-45

plugins/location-connectivity/src/store.rs (2)

14-46: ⚠️ Potential issue

Missing error handling in all store operations.

All functions only propagate errors using ? without any error handling, which violates the coding guideline requiring error handling.

Consider adding proper error handling, such as logging errors or providing fallback behavior:

 pub fn get_location_based_enabled<R: tauri::Runtime>(
     app: tauri::AppHandle<R>,
 ) -> Result<bool, LocationConnectivityError> {
-    let store = app.scoped_store::<StoreKey>("location-connectivity")?;
-    Ok(store.get::<bool>(StoreKey::LocationBasedEnabled)?.unwrap_or(false))
+    match app.scoped_store::<StoreKey>("location-connectivity") {
+        Ok(store) => {
+            match store.get::<bool>(StoreKey::LocationBasedEnabled) {
+                Ok(value) => Ok(value.unwrap_or(false)),
+                Err(e) => {
+                    tracing::error!("Failed to read location-based enabled setting: {}", e);
+                    Ok(false) // Return default on error
+                }
+            }
+        }
+        Err(e) => {
+            tracing::error!("Failed to access store: {}", e);
+            Ok(false) // Return default on error
+        }
+    }
 }

Likely an incorrect or invalid review comment.


48-70: 🛠️ Refactor suggestion

⚠️ Potential issue

Remove unnecessary async from synchronous functions.

The functions add_trusted_ssid and remove_trusted_ssid are marked as async but don't perform any asynchronous operations. Additionally, they lack error handling.

-pub async fn add_trusted_ssid<R: tauri::Runtime>(
+pub fn add_trusted_ssid<R: tauri::Runtime>(
     app: tauri::AppHandle<R>,
     ssid: String,
 ) -> Result<(), LocationConnectivityError> {
-    let mut ssids = get_trusted_ssids(app.clone())?;
+    let mut ssids = match get_trusted_ssids(app.clone()) {
+        Ok(ssids) => ssids,
+        Err(e) => {
+            tracing::error!("Failed to get trusted SSIDs: {}", e);
+            return Err(e);
+        }
+    };
     
     if !ssids.contains(&ssid) {
         ssids.push(ssid);
-        set_trusted_ssids(app, ssids)?;
+        if let Err(e) = set_trusted_ssids(app, ssids) {
+            tracing::error!("Failed to save trusted SSIDs: {}", e);
+            return Err(e);
+        }
     }
     
     Ok(())
 }

-pub async fn remove_trusted_ssid<R: tauri::Runtime>(
+pub fn remove_trusted_ssid<R: tauri::Runtime>(
     app: tauri::AppHandle<R>,
     ssid: String,
 ) -> Result<(), LocationConnectivityError> {
-    let mut ssids = get_trusted_ssids(app.clone())?;
+    let mut ssids = match get_trusted_ssids(app.clone()) {
+        Ok(ssids) => ssids,
+        Err(e) => {
+            tracing::error!("Failed to get trusted SSIDs: {}", e);
+            return Err(e);
+        }
+    };
     ssids.retain(|s| s != &ssid);
-    set_trusted_ssids(app, ssids)?;
+    if let Err(e) = set_trusted_ssids(app, ssids) {
+        tracing::error!("Failed to save trusted SSIDs: {}", e);
+        return Err(e);
+    }
     Ok(())
 }

Likely an incorrect or invalid review comment.

plugins/location-connectivity/src/ext.rs (4)

8-14: Platform support implementation looks good.

The conditional compilation for platform-specific SSID detection is well-structured with appropriate error for unsupported platforms.


63-105: ⚠️ Potential issue

Missing error handling in status update logic.

The function only propagates errors without handling them, violating the error handling guideline.

Consider adding error handling for store operations:

 pub async fn update_location_status(&self) -> Result<(), LocationConnectivityError> {
     let current_ssid = self.get_current_ssid().await?;
     
-    let is_enabled = crate::store::get_location_based_enabled(self.app_handle.clone())?;
-    let trusted_ssids = crate::store::get_trusted_ssids(self.app_handle.clone())?;
+    let is_enabled = match crate::store::get_location_based_enabled(self.app_handle.clone()) {
+        Ok(enabled) => enabled,
+        Err(e) => {
+            tracing::error!("Failed to get location-based enabled setting: {}", e);
+            false // Default to disabled on error
+        }
+    };
+    
+    let trusted_ssids = match crate::store::get_trusted_ssids(self.app_handle.clone()) {
+        Ok(ssids) => ssids,
+        Err(e) => {
+            tracing::error!("Failed to get trusted SSIDs: {}", e);
+            Vec::new() // Default to empty list on error
+        }
+    };

Likely an incorrect or invalid review comment.


42-46: ⚠️ Potential issue

Add error handling for initialization failure.

The spawned task only logs a warning when initialization fails but doesn't handle the error.

Consider implementing retry logic or updating the state to reflect the initialization failure:

 tokio::spawn(async move {
-    if let Err(e) = state_clone.update_location_status().await {
-        tracing::warn!("Failed to initialize location status: {}", e);
-    }
+    match state_clone.update_location_status().await {
+        Ok(_) => tracing::info!("Location status initialized successfully"),
+        Err(e) => {
+            tracing::error!("Failed to initialize location status: {}", e);
+            // Consider retry logic or setting an error state
+            // For example: mark the monitoring as failed in the state
+        }
+    }
 });

Likely an incorrect or invalid review comment.


145-148: ⚠️ Potential issue

Add error handling for monitoring failures.

Update failures in the monitoring loop are only logged as warnings.

Consider implementing exponential backoff or stopping monitoring after repeated failures:

+let mut consecutive_failures = 0;
+const MAX_CONSECUTIVE_FAILURES: u32 = 5;

 loop {
     interval.tick().await;
     
     if let Some(state) = app_handle.try_state::<LocationConnectivityState<R>>() {
-        if let Err(e) = state.update_location_status().await {
-            tracing::warn!("Failed to update location status: {}", e);
-        }
+        match state.update_location_status().await {
+            Ok(_) => consecutive_failures = 0,
+            Err(e) => {
+                consecutive_failures += 1;
+                tracing::error!("Failed to update location status (attempt {}/{}): {}", 
+                    consecutive_failures, MAX_CONSECUTIVE_FAILURES, e);
+                
+                if consecutive_failures >= MAX_CONSECUTIVE_FAILURES {
+                    tracing::error!("Too many consecutive failures, stopping monitoring");
+                    break;
+                }
+            }
+        }
     } else {

Likely an incorrect or invalid review comment.

plugins/location-connectivity/permissions/schemas/schema.json (1)

1-402: LGTM - Well-structured JSON schema for plugin permissions.

The schema properly defines the permission structure for the location-connectivity plugin with comprehensive type definitions and command-specific permissions. The structure follows JSON Schema Draft 07 standards and correctly maps to the Tauri plugin permission system.

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

♻️ Duplicate comments (1)
plugins/location-connectivity/src/ext.rs (1)

118-141: Retry mechanism addresses previous concerns but final error still unhandled.

The retry logic improves reliability compared to the previous implementation, but the final failure after all retries is still only logged.

🧹 Nitpick comments (4)
plugins/location-connectivity/src/ext.rs (4)

40-40: Remove "what" comments in favor of "why" explanations.

These comments explain what the code does rather than why it's needed.

-        // Initialize the status immediately
+        // Ensure initial state is available before commands are called
-        // Start background monitoring
+        // Keep location status current for real-time connectivity decisions

Also applies to: 48-48


97-97: Remove unnecessary explicit drop.

The current_status variable will be automatically dropped at the end of its scope.

         *current_status = new_status.clone();
-        drop(current_status);

91-94: Consider simplifying status change detection.

The current implementation compares fields individually, which could be simplified using PartialEq.

If LocationStatus implements PartialEq, this could be:

-        let status_changed = new_status.current_ssid != current_status.current_ssid 
-            || new_status.is_in_trusted_location != current_status.is_in_trusted_location
-            || new_status.should_use_cloud != current_status.should_use_cloud
-            || new_status.is_enabled != current_status.is_enabled;
+        let status_changed = new_status != *current_status;

159-162: Environment variable parsing could be more robust.

The current parsing silently falls back to default on any parsing error.

             let check_interval = std::env::var("LOCATION_CHECK_INTERVAL")
                 .ok()
-                .and_then(|s| s.parse::<u64>().ok())
+                .and_then(|s| s.parse::<u64>().map_err(|e| {
+                    tracing::warn!("Invalid LOCATION_CHECK_INTERVAL '{}': {}, using default", s, e);
+                    e
+                }).ok())
                 .unwrap_or(5);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae54093 and 5c8a7e0.

📒 Files selected for processing (3)
  • plugins/location-connectivity/package.json (1 hunks)
  • plugins/location-connectivity/src/ext.rs (1 hunks)
  • plugins/location-connectivity/src/wifi_macos.rs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/location-connectivity/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/location-connectivity/src/wifi_macos.rs
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{js,ts,tsx,rs}`: 1. No error handling. 2. No unused imports, variables, or functions. 3. For comments, keep it minimal. It should be about "Why", not "What".

**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

  • plugins/location-connectivity/src/ext.rs
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (1)
plugins/location-connectivity/src/ext.rs (1)

147-154: 🛠️ Refactor suggestion

Potential race condition in monitoring activation check.

Multiple threads could potentially pass the if *is_active check before any of them sets it to true, leading to multiple monitoring tasks.

         tokio::spawn(async move {
-            {
-                let mut is_active = monitoring_active.write().await;
-                if *is_active {
-                    return; // Already monitoring
-                }
-                *is_active = true;
-            }
+            let mut is_active = monitoring_active.write().await;
+            if *is_active {
+                return; // Already monitoring
+            }
+            *is_active = true;
+            drop(is_active); // Release lock before long-running loop

Likely an incorrect or invalid review comment.

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

🧹 Nitpick comments (2)
plugins/location-connectivity/js/bindings.gen.ts (2)

1-1: Consider removing @ts-nocheck directive.

The @ts-nocheck directive disables TypeScript checking entirely. While this might be necessary for auto-generated code, it's worth verifying if this is still needed and whether the generated code can be made TypeScript-compliant.


82-82: Remove unused import.

The TAURI_CHANNEL import appears to be unused throughout the file.

  import {
    invoke as TAURI_INVOKE,
-   Channel as TAURI_CHANNEL,
  } from "@tauri-apps/api/core";
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4a3af5 and fb2d20e.

📒 Files selected for processing (4)
  • plugins/location-connectivity/js/bindings.gen.ts (1 hunks)
  • plugins/location-connectivity/js/index.ts (1 hunks)
  • plugins/location-connectivity/src/lib.rs (1 hunks)
  • plugins/location-connectivity/src/types.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • plugins/location-connectivity/js/index.ts
  • plugins/location-connectivity/src/lib.rs
  • plugins/location-connectivity/src/types.rs
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{js,ts,tsx,rs}`: 1. No error handling. 2. No unused imports, variables, or functions. 3. For comments, keep it minimal. It should be about "Why", not "What".

**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

  • plugins/location-connectivity/js/bindings.gen.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-latest)
🔇 Additional comments (3)
plugins/location-connectivity/js/bindings.gen.ts (3)

7-46: LGTM! Well-structured command bindings.

The command functions are properly structured with appropriate async/await patterns, correct parameter passing, and sensible return types for a Tauri plugin interface.


60-76: LGTM! Clean type definitions.

The type definitions are well-structured with appropriate union types and comprehensive field coverage for the location-based functionality.


103-136: LGTM! Sophisticated event system implementation.

The proxy-based event system provides a flexible interface for both global and window-specific event handling, which is appropriate for a Tauri plugin.

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

🧹 Nitpick comments (2)
plugins/location-connectivity/src/wifi_macos.rs (2)

138-148: Consider refining the error detection logic.

The check for "airport" in error messages might be too broad and could potentially match legitimate SSIDs containing that word.

Consider this more specific approach:

     fn is_error_message(text: &str) -> bool {
         let text_lower = text.to_lowercase();
         // Common error indicators that appear in various languages
         text_lower.contains("not associated") 
             || text_lower.contains("not connected")
             || text_lower.contains("no network")
-            || text_lower.contains("airport")  // Often indicates error messages from airport utility
+            || text_lower.contains("airport network")  // More specific to error messages
             || text_lower.contains("error")
             || text_lower.starts_with("unable")
             || text_lower.starts_with("failed")
     }

162-183: Complex nested JSON parsing could benefit from error handling.

The deeply nested JSON parsing lacks error handling for malformed JSON structures and could be made more robust.

Consider adding intermediate error checks:

     fn parse_system_profiler_json(json: &serde_json::Value) -> Option<String> {
-        if let Some(airport_data) = json.get("SPAirPortDataType") {
-            if let Some(interfaces) = airport_data.as_array() {
+        let airport_data = json.get("SPAirPortDataType")?;
+        let interfaces = airport_data.as_array()?;
+        
                 for interface in interfaces {
                     if let Some(networks) = interface.get("spairport_airport_other") {
                         if let Some(networks_array) = networks.as_array() {
                             for network in networks_array {
                                 if let Some(current) = network.get("_name") {
                                     if let Some(ssid_str) = current.as_str() {
                                         if network.get("spairport_network_cc").is_some() {
                                             return Some(ssid_str.to_string());
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
-            }
-        }
         None
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb2d20e and 9cd46a3.

📒 Files selected for processing (14)
  • apps/desktop/src/components/settings/views/lab.tsx (2 hunks)
  • plugins/connector/src/ext.rs (4 hunks)
  • plugins/location-connectivity/Cargo.toml (1 hunks)
  • plugins/location-connectivity/build.rs (1 hunks)
  • plugins/location-connectivity/js/index.ts (1 hunks)
  • plugins/location-connectivity/package.json (1 hunks)
  • plugins/location-connectivity/src/commands.rs (1 hunks)
  • plugins/location-connectivity/src/error.rs (1 hunks)
  • plugins/location-connectivity/src/ext.rs (1 hunks)
  • plugins/location-connectivity/src/lib.rs (1 hunks)
  • plugins/location-connectivity/src/store.rs (1 hunks)
  • plugins/location-connectivity/src/types.rs (1 hunks)
  • plugins/location-connectivity/src/wifi_macos.rs (1 hunks)
  • plugins/location-connectivity/tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • plugins/location-connectivity/build.rs
  • plugins/location-connectivity/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (11)
  • plugins/location-connectivity/package.json
  • plugins/location-connectivity/js/index.ts
  • plugins/location-connectivity/tsconfig.json
  • plugins/location-connectivity/Cargo.toml
  • plugins/location-connectivity/src/error.rs
  • plugins/connector/src/ext.rs
  • plugins/location-connectivity/src/types.rs
  • apps/desktop/src/components/settings/views/lab.tsx
  • plugins/location-connectivity/src/store.rs
  • plugins/location-connectivity/src/ext.rs
  • plugins/location-connectivity/src/commands.rs
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{js,ts,tsx,rs}`: 1. No error handling. 2. No unused imports, variables, or functions. 3. For comments, keep it minimal. It should be about "Why", not "What".

**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

  • plugins/location-connectivity/src/wifi_macos.rs
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-latest)
🔇 Additional comments (4)
plugins/location-connectivity/src/wifi_macos.rs (4)

1-5: LGTM! Clean module structure and imports.

The conditional compilation and imports are appropriate for the macOS-specific functionality.


7-39: Excellent fallback strategy with comprehensive logging.

The main function implements a robust approach with multiple detection methods and clear debug logging at each step.


186-187: LGTM! Proper conditional re-export.

The public re-export correctly makes the function available only on macOS.


76-92: 🛠️ Refactor suggestion

Inconsistent error handling compared to other methods.

Unlike get_ssid_via_networksetup and get_ssid_via_system_profiler, this method only logs debug messages for command execution failures instead of properly handling them.

Apply this diff to maintain consistency:

         for airport_path in &airport_paths {
-            let output = Command::new(airport_path).arg("-I").output();
-
-            if let Ok(output) = output {
+            let output = Command::new(airport_path)
+                .arg("-I")
+                .output()
+                .map_err(|e| {
+                    LocationConnectivityError::WifiDetection(format!(
+                        "Failed to execute airport command at {}: {}",
+                        airport_path, e
+                    ))
+                });
+
+            match output {
+                Ok(output) => {
                 if output.status.success() {
                     let output_str = String::from_utf8_lossy(&output.stdout);
 
                     if let Some(ssid) = parse_airport_output(&output_str) {
                         return Ok(Some(ssid));
                     }
                 }
-            } else {
-                tracing::debug!("Failed to execute airport command at {}", airport_path);
+                }
+                Err(e) => {
+                    tracing::debug!("airport command failed at {}: {}", airport_path, e);
+                }
             }
         }

Likely an incorrect or invalid review comment.

@yujonglee yujonglee closed this Jun 9, 2025
@coderabbitai coderabbitai bot mentioned this pull request Jul 26, 2025
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.

location based connectivity

2 participants