Skip to content

feat: add NetworkContext powered by plugins/network event#2076

Closed
yujonglee wants to merge 1 commit intomainfrom
devin/1764683914-network-context
Closed

feat: add NetworkContext powered by plugins/network event#2076
yujonglee wants to merge 1 commit intomainfrom
devin/1764683914-network-context

Conversation

@yujonglee
Copy link
Contributor

@yujonglee yujonglee commented Dec 2, 2025

feat: add NetworkContext powered by plugins/network event

Summary

Adds a new tauri-plugin-network plugin that monitors network connectivity and a corresponding NetworkContext React provider in the desktop app.

The plugin uses the existing hypr-network crate (ICMP ping to 8.8.8.8) to detect connectivity, polls every 5 seconds, and emits statusChanged events when the network status changes. The React context provides a NetworkProvider component and useNetwork hook for consuming network status.

Review & Testing Checklist for Human

  • The NetworkProvider is NOT integrated into the app's component tree yet - this context exists but won't do anything until you wrap your app with <NetworkProvider>. You'll need to add it to the appropriate layout/root component.
  • Test network detection by toggling WiFi/ethernet on and off - verify events are emitted and state updates correctly
  • Verify the 5-second polling interval is appropriate for your use case (hardcoded in handler.rs:17)
  • Test on networks that might block ICMP (corporate networks, VPNs) - the ping to 8.8.8.8 may give false negatives

Test Plan

  1. Add <NetworkProvider> to your app's component tree
  2. Use useNetwork() hook in a component to display status
  3. Toggle network connectivity and verify the UI updates within ~5 seconds

Notes

- Create tauri-plugin-network with network status monitoring
- Add NetworkEvent that emits statusChanged events when connectivity changes
- Add is_online command to check current network status
- Create NetworkContext React provider in apps/desktop
- Add useNetwork hook for consuming network status in components
- Properly handle errors in network status checks

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Dec 2, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit c4e2a62
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/692ef4c87bd60a0007fd2f5c
😎 Deploy Preview https://deploy-preview-2076--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.

@netlify
Copy link

netlify bot commented Dec 2, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit c4e2a62
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/692ef4c88697d00008313c43
😎 Deploy Preview https://deploy-preview-2076--hyprnote-storybook.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 Dec 2, 2025

📝 Walkthrough

Walkthrough

This PR introduces a new Tauri network plugin to the workspace with backend network status detection and frontend React integration. The plugin monitors online connectivity via a background task that checks every 5 seconds, emits events on status changes, and exposes an async command for synchronous checks. A React context and hook enable frontend components to access the current online state.

Changes

Cohort / File(s) Summary
Workspace and app dependency declarations
Cargo.toml, apps/desktop/src-tauri/Cargo.toml
Added tauri-plugin-network as workspace-managed dependency in two locations for use across the project.
Tauri app configuration
apps/desktop/src-tauri/src/lib.rs, apps/desktop/src-tauri/capabilities/default.json
Registered network plugin initialization in app bootstrap and added "network:default" capability permission.
Network plugin implementation
plugins/network/Cargo.toml, plugins/network/src/lib.rs, plugins/network/src/commands.rs, plugins/network/src/events.rs, plugins/network/src/error.rs, plugins/network/src/handler.rs, plugins/network/build.rs
Created complete Tauri network plugin with async is_online command, background monitoring task emitting NetworkEvent on status changes, error types, and specta type-safe bindings.
Plugin configuration and setup
plugins/network/package.json, plugins/network/tsconfig.json, plugins/network/js/index.ts, plugins/network/.gitignore
Added standard plugin package configuration, TypeScript settings, and JavaScript bindings re-export.
Frontend integration
apps/desktop/src/contexts/network.tsx
Introduced NetworkProvider context and useNetwork hook to expose online status to React components with event subscription and error handling.

Sequence Diagram(s)

sequenceDiagram
    participant App as App Init
    participant Plugin as Network Plugin
    participant Task as Background Task
    participant Net as hypr_network
    participant Event as Event System
    participant Context as React Context
    participant Hook as Component

    App->>Plugin: init()
    activate Plugin
    Note over Plugin: Setup invocation handler<br/>Mount specta events
    Plugin->>Task: spawn async setup task
    activate Task
    Task->>Net: is_online() (initial)
    Net-->>Task: status
    Task->>Task: store initial status
    Note over Task: Loop every 5 seconds
    Task->>Net: is_online()
    Net-->>Task: new status
    alt Status Changed
        Task->>Event: emit NetworkEvent::StatusChanged
        Event->>Context: networkEvent listener
        Context->>Context: update isOnline state
        Context-->>Hook: notify subscribers
        Hook->>Hook: re-render with new status
    end
    deactivate Task
    deactivate Plugin
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Plugin implementation (plugins/network/src/*.rs): Straightforward pattern of event-based status polling with no complex logic; verify event emission timing and error handling propagation.
  • Frontend context (apps/desktop/src/contexts/network.tsx): Validate event listener cleanup on unmount and context hook error boundary for missing provider.
  • Dependency and capability wiring: Confirm plugin init is correctly chained and capability entry is properly positioned.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a NetworkContext powered by a network plugin event system.
Description check ✅ Passed The description provides relevant context about the changes, including the plugin functionality, polling behavior, and integration requirements for the NetworkContext.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1764683914-network-context

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

🧹 Nitpick comments (6)
plugins/network/.gitignore (1)

1-1: Local node_modules ignore is fine (optional duplication).

Ignoring node_modules locally is fine; if the repo root already does this, it’s redundant but harmless. You can keep it for clarity or drop it to reduce duplication.

plugins/network/package.json (1)

1-11: Package metadata and codegen script look consistent with other plugins.

@hypr/plugin-network with main: "./js/index.ts", the codegen script, and @tauri-apps/api at ^2.9.0 all look aligned with the Tauri 2.9 stack. If other plugin packages define extra fields like types or exports, consider mirroring those here for consistency, but this is optional.

plugins/network/Cargo.toml (1)

1-29: Cargo manifest wiring looks good; metadata could be refined later.

The dependency setup (workspace tauri, tauri-plugin-windows, hypr-network, tokio, tauri-specta, etc.) looks consistent with other plugins and should support specta/TS bindings and async network checks. At some point you may want to replace authors = ["You"] and the empty description with real metadata, but that’s non-blocking.

plugins/network/src/handler.rs (1)

17-22: Skip the redundant first interval tick.

tokio::time::interval completes its first tick immediately, causing an unnecessary network check right after line 13 already fetched initial_status.

Apply this diff to skip the first tick:

     tokio::spawn(async move {
         let mut interval = tokio::time::interval(Duration::from_secs(5));
+        interval.tick().await; // Skip first immediate tick
 
         loop {
             interval.tick().await;
apps/desktop/src/contexts/network.tsx (2)

16-16: Consider starting with isOnline: false or a loading state.

The initial state assumes the user is online (true), which may briefly display incorrect status until the check completes. Starting with false or adding a separate loading state would prevent showing potentially misleading information.


22-32: Treating all errors as offline status may be misleading.

Setting isOnline to false on any error (lines 26, 31) assumes network failure, but errors could stem from other issues (permissions, plugin initialization, etc.). Consider maintaining the current state or using a separate error state to distinguish between "offline" and "status unknown."

Example approach:

const [networkState, setNetworkState] = useState<{
  isOnline: boolean;
  status: 'checking' | 'ready' | 'error';
}>({ isOnline: false, status: 'checking' });
📜 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 93d9166 and c4e2a62.

⛔ Files ignored due to path filters (7)
  • Cargo.lock is excluded by !**/*.lock
  • plugins/network/js/bindings.gen.ts is excluded by !**/*.gen.ts
  • plugins/network/permissions/autogenerated/commands/is_online.toml is excluded by !plugins/**/permissions/**
  • plugins/network/permissions/autogenerated/reference.md is excluded by !plugins/**/permissions/**
  • plugins/network/permissions/default.toml is excluded by !plugins/**/permissions/**
  • plugins/network/permissions/schemas/schema.json is excluded by !plugins/**/permissions/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • Cargo.toml (1 hunks)
  • apps/desktop/src-tauri/Cargo.toml (1 hunks)
  • apps/desktop/src-tauri/capabilities/default.json (1 hunks)
  • apps/desktop/src-tauri/src/lib.rs (1 hunks)
  • apps/desktop/src/contexts/network.tsx (1 hunks)
  • plugins/network/.gitignore (1 hunks)
  • plugins/network/Cargo.toml (1 hunks)
  • plugins/network/build.rs (1 hunks)
  • plugins/network/js/index.ts (1 hunks)
  • plugins/network/package.json (1 hunks)
  • plugins/network/src/commands.rs (1 hunks)
  • plugins/network/src/error.rs (1 hunks)
  • plugins/network/src/events.rs (1 hunks)
  • plugins/network/src/handler.rs (1 hunks)
  • plugins/network/src/lib.rs (1 hunks)
  • plugins/network/tsconfig.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • plugins/network/js/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • plugins/network/js/index.ts
  • apps/desktop/src/contexts/network.tsx
plugins/*/src/lib.rs

📄 CodeRabbit inference engine (plugins/AGENTS.md)

After updating commands in plugins/<NAME>/src/lib.rs, run codegen, update plugins/<NAME>/permissions/default.toml, and apps/desktop/src-tauri/capabilities/default.json

Files:

  • plugins/network/src/lib.rs
🧠 Learnings (3)
📚 Learning: 2025-11-27T11:40:22.782Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: plugins/AGENTS.md:0-0
Timestamp: 2025-11-27T11:40:22.782Z
Learning: Applies to plugins/*/src/lib.rs : After updating commands in `plugins/<NAME>/src/lib.rs`, run `codegen`, update `plugins/<NAME>/permissions/default.toml`, and `apps/desktop/src-tauri/capabilities/default.json`

Applied to files:

  • plugins/network/src/commands.rs
  • plugins/network/build.rs
  • apps/desktop/src-tauri/src/lib.rs
  • plugins/network/src/lib.rs
  • plugins/network/Cargo.toml
  • apps/desktop/src-tauri/Cargo.toml
  • Cargo.toml
📚 Learning: 2025-11-24T16:32:01.459Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:32:01.459Z
Learning: Applies to **/*.ts : Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework

Applied to files:

  • plugins/network/tsconfig.json
📚 Learning: 2025-11-24T16:32:13.593Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: packages/nango/.cursor/rules/nango.mdc:0-0
Timestamp: 2025-11-24T16:32:13.593Z
Learning: Applies to packages/nango/**/models.ts : Do NOT edit the models.ts file - it is automatically generated at compilation time

Applied to files:

  • plugins/network/tsconfig.json
🧬 Code graph analysis (4)
plugins/network/build.rs (1)
apps/desktop/src-tauri/src/lib.rs (1)
  • main (12-190)
apps/desktop/src-tauri/src/lib.rs (1)
plugins/network/src/lib.rs (1)
  • init (23-41)
plugins/network/src/events.rs (2)
packages/store/src/schema-external.ts (1)
  • Event (150-150)
plugins/network/src/commands.rs (1)
  • is_online (5-7)
plugins/network/src/handler.rs (1)
plugins/network/src/commands.rs (1)
  • is_online (5-7)
⏰ 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). (4)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: Devin
🔇 Additional comments (11)
Cargo.toml (1)

129-129: Workspace wiring for tauri-plugin-network looks consistent.

The new tauri-plugin-network entry matches the existing tauri plugin pattern and makes it available as a shared workspace dependency.

apps/desktop/src-tauri/capabilities/default.json (1)

108-108: Network capability entry looks correct; ensure permission id matches.

Adding "network:default" here is the right hook so the main window can use the network plugin. Please double‑check that plugins/network/permissions/default.toml defines a matching network:default capability so permissions and capabilities stay in sync. Based on learnings, this sync is required after adding new plugin commands.

plugins/network/build.rs (1)

1-5: Build script matches tauri plugin pattern; keep COMMANDS in sync.

COMMANDS with "is_online" and tauri_plugin::Builder::new(COMMANDS).build(); is the expected setup for plugin codegen. Just ensure this list stays in lockstep with the actual commands registered in plugins/network/src/lib.rs / src/commands.rs, and rerun the codegen script when commands change. Based on learnings, this plus permissions/capabilities updates keeps the plugin wiring consistent.

plugins/network/tsconfig.json (1)

1-3: TS config correctly reuses the shared base.

Extending ../tsconfig.base.json keeps this plugin aligned with the workspace TypeScript settings; nothing else needed here.

plugins/network/js/index.ts (1)

1-1: Re-exporting generated bindings is appropriate.

export * from "./bindings.gen"; is a clean way to expose the generated bindings as the plugin’s JS/TS surface; this matches the usual pattern.

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

1-7: LGTM! Clean command wrapper.

The command correctly wraps the network check and follows the plugin command pattern.

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

45-45: LGTM! Dependency addition follows workspace pattern.

The network plugin dependency is correctly added using workspace versioning.

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

74-74: Plugin initialization looks correct. Verify codegen has been run.

The network plugin is properly initialized in the plugin chain. As per coding guidelines, ensure that after updating commands in the plugin, you have run codegen, updated plugins/network/permissions/default.toml, and apps/desktop/src-tauri/capabilities/default.json.

Based on learnings, after updating plugin commands, codegen and permission files need to be updated.

plugins/network/src/events.rs (1)

1-15: LGTM! Event structure is well-defined.

The NetworkEvent enum with its serde tagging and the common_event_derives macro properly set up type-safe event emission and TypeScript bindings generation.

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

23-41: LGTM! Plugin initialization follows Tauri best practices.

The plugin correctly sets up the specta builder, mounts events, and spawns the network monitoring handler with appropriate error logging.

plugins/network/src/error.rs (1)

1-14: The Error type is part of the public API and should not be removed without deprecation.

While the Error type is not used internally within the plugin (commands return Result<bool, String> and handlers use String errors), it IS publicly exported from lib.rs as part of the plugin's public API. Removing it could break external code that depends on it. If it's no longer needed, consider adding a deprecation notice rather than removing it outright.

Comment on lines +25 to +33
if is_online != previous {
let event = NetworkEvent::StatusChanged { is_online };
let _ = event.emit_to(
&app_handle,
EventTarget::AnyLabel {
label: tauri_plugin_windows::AppWindow::Main.label(),
},
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Log event emission failures instead of silently ignoring them.

Silently ignoring errors from emit_to with let _ could hide issues with event delivery to the frontend, making debugging difficult.

Apply this diff to log failures:

             if is_online != previous {
                 let event = NetworkEvent::StatusChanged { is_online };
-                let _ = event.emit_to(
+                if let Err(e) = event.emit_to(
                     &app_handle,
                     EventTarget::AnyLabel {
                         label: tauri_plugin_windows::AppWindow::Main.label(),
                     },
-                );
+                ) {
+                    tracing::warn!("Failed to emit network status change event: {}", e);
+                }
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if is_online != previous {
let event = NetworkEvent::StatusChanged { is_online };
let _ = event.emit_to(
&app_handle,
EventTarget::AnyLabel {
label: tauri_plugin_windows::AppWindow::Main.label(),
},
);
}
if is_online != previous {
let event = NetworkEvent::StatusChanged { is_online };
if let Err(e) = event.emit_to(
&app_handle,
EventTarget::AnyLabel {
label: tauri_plugin_windows::AppWindow::Main.label(),
},
) {
tracing::warn!("Failed to emit network status change event: {}", e);
}
}
🤖 Prompt for AI Agents
In plugins/network/src/handler.rs around lines 25 to 33, the call to
event.emit_to is currently ignored with let _ = ..., so failures are silently
dropped; change this to capture the Result and log errors on Err(e) (e.g., using
the crate's logger/tracing macro) with context including the event type and the
is_online value so emission failures are visible for debugging.

@yujonglee yujonglee closed this Dec 2, 2025
@yujonglee yujonglee deleted the devin/1764683914-network-context branch December 2, 2025 23:18
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

Comments