feat: add NetworkContext powered by plugins/network event#2076
feat: add NetworkContext powered by plugins/network event#2076
Conversation
- 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 EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Deploy Preview for hyprnote ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for hyprnote-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThis 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
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
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes
Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (6)
plugins/network/.gitignore (1)
1-1: Local node_modules ignore is fine (optional duplication).Ignoring
node_moduleslocally 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-networkwithmain: "./js/index.ts", thecodegenscript, and@tauri-apps/apiat^2.9.0all look aligned with the Tauri 2.9 stack. If other plugin packages define extra fields liketypesorexports, 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 replaceauthors = ["You"]and the emptydescriptionwith real metadata, but that’s non-blocking.plugins/network/src/handler.rs (1)
17-22: Skip the redundant first interval tick.
tokio::time::intervalcompletes its first tick immediately, causing an unnecessary network check right after line 13 already fetchedinitial_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 withisOnline: falseor a loading state.The initial state assumes the user is online (
true), which may briefly display incorrect status until the check completes. Starting withfalseor adding a separate loading state would prevent showing potentially misleading information.
22-32: Treating all errors as offline status may be misleading.Setting
isOnlinetofalseon 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
⛔ Files ignored due to path filters (7)
Cargo.lockis excluded by!**/*.lockplugins/network/js/bindings.gen.tsis excluded by!**/*.gen.tsplugins/network/permissions/autogenerated/commands/is_online.tomlis excluded by!plugins/**/permissions/**plugins/network/permissions/autogenerated/reference.mdis excluded by!plugins/**/permissions/**plugins/network/permissions/default.tomlis excluded by!plugins/**/permissions/**plugins/network/permissions/schemas/schema.jsonis excluded by!plugins/**/permissions/**pnpm-lock.yamlis 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, usecn(import from@hypr/utils). It is similar toclsx. Always pass an array and split by logical grouping.
Usemotion/reactinstead offramer-motion.
Files:
plugins/network/js/index.tsapps/desktop/src/contexts/network.tsx
plugins/*/src/lib.rs
📄 CodeRabbit inference engine (plugins/AGENTS.md)
After updating commands in
plugins/<NAME>/src/lib.rs, runcodegen, updateplugins/<NAME>/permissions/default.toml, andapps/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.rsplugins/network/build.rsapps/desktop/src-tauri/src/lib.rsplugins/network/src/lib.rsplugins/network/Cargo.tomlapps/desktop/src-tauri/Cargo.tomlCargo.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-networkentry 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 thatplugins/network/permissions/default.tomldefines a matchingnetwork:defaultcapability 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.
COMMANDSwith"is_online"andtauri_plugin::Builder::new(COMMANDS).build();is the expected setup for plugin codegen. Just ensure this list stays in lockstep with the actual commands registered inplugins/network/src/lib.rs/src/commands.rs, and rerun thecodegenscript 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.jsonkeeps 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, updatedplugins/network/permissions/default.toml, andapps/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
NetworkEventenum with its serde tagging and thecommon_event_derivesmacro 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
Errortype is not used internally within the plugin (commands returnResult<bool, String>and handlers useStringerrors), it IS publicly exported fromlib.rsas 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.
| 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(), | ||
| }, | ||
| ); | ||
| } |
There was a problem hiding this comment.
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.
| 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.
feat: add NetworkContext powered by plugins/network event
Summary
Adds a new
tauri-plugin-networkplugin that monitors network connectivity and a correspondingNetworkContextReact provider in the desktop app.The plugin uses the existing
hypr-networkcrate (ICMP ping to 8.8.8.8) to detect connectivity, polls every 5 seconds, and emitsstatusChangedevents when the network status changes. The React context provides aNetworkProvidercomponent anduseNetworkhook for consuming network status.Review & Testing Checklist for Human
NetworkProvideris 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.handler.rs:17)Test Plan
<NetworkProvider>to your app's component treeuseNetwork()hook in a component to display statusNotes