Skip to content

feat(ota): add update drawer for updates#2318

Closed
ComputelessComputer wants to merge 2 commits intomainfrom
feat/add-update-drawer
Closed

feat(ota): add update drawer for updates#2318
ComputelessComputer wants to merge 2 commits intomainfrom
feat/add-update-drawer

Conversation

@ComputelessComputer
Copy link
Collaborator

Overview

  • Added an update drawer for OTA (Over-the-Air) updates
  • Provides a new UI component for managing software updates

Changes

  • Implemented update drawer functionality
  • Enhanced user experience for update management

@netlify
Copy link

netlify bot commented Dec 15, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit bb20768
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/693fe52b2d78450008cfdf23
😎 Deploy Preview https://deploy-preview-2318--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 Dec 15, 2025

Warning

Rate limit exceeded

@ComputelessComputer has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 22 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ccf13fe and bb20768.

📒 Files selected for processing (5)
  • apps/desktop/src/components/main/sidebar/index.tsx (2 hunks)
  • apps/desktop/src/components/main/sidebar/profile/index.tsx (3 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (1 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/store.ts (6 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/task.ts (1 hunks)
📝 Walkthrough

Walkthrough

Adds an OTA update drawer UI and integrates it into the left sidebar, extends the OTA state machine with a showDrawer flag, and exposes a drawer-close callback from the OTA hook; the sidebar layout and avatar rendering are adjusted to show download progress.

Changes

Cohort / File(s) Summary
Sidebar Integration
apps/desktop/src/components/main/sidebar/index.tsx
Inserts UpdateDrawer as a sibling to existing sidebar content, wraps returned JSX in a fragment, and adjusts header button handlers to call toggleExpanded.
OTA Drawer Component
apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx
New UpdateDrawer component that reads OTA state via useOTA, renders a BottomSheet when an update is ready, shows status (downloading/ready), and provides actions (Later / Restart now) wired to close and install handlers.
OTA State Machine
apps/desktop/src/components/main/sidebar/profile/ota/store.ts
Adds showDrawer: boolean to context and initial state; sets showDrawer on startDownload/downloadFinished; hides it on cancelDownload/closeDrawer/reset; adds closeDrawer event.
OTA Hook / Task API
apps/desktop/src/components/main/sidebar/profile/ota/task.ts
Exposes handleCloseDrawer() on the useOTA return value which triggers the store's closeDrawer event.
Profile Avatar UI
apps/desktop/src/components/main/sidebar/profile/index.tsx
Wraps avatar in a relative container and overlays a circular progress indicator when OTA downloading state is active; preserves existing avatar rendering.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review state transitions in ota/store.ts to ensure showDrawer is set/cleared on all relevant paths.
  • Verify UpdateDrawer visibility conditions (uses showDrawer && state === "ready") and action handlers (handleCloseDrawer, install).
  • Confirm useOTA surface change (handleCloseDrawer) is correctly typed and consumed where used.
  • Check sidebar button handler changes for unintended UX regressions and accessibility.

Possibly related PRs

  • OTA UI final #1584 — Extends/integrates OTA flow and modifies the same OTA modules (UpdateDrawer, showDrawer, handleCloseDrawer), likely a direct follow-up or predecessor.

Suggested reviewers

  • yujonglee

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 'feat(ota): add update drawer for updates' clearly describes the main change: adding an update drawer component for OTA updates, which aligns with the changeset modifications across multiple files.
Description check ✅ Passed The description is related to the changeset, mentioning the addition of an update drawer for OTA updates and enhanced user experience for update management, which corresponds to the changes made.

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

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

@netlify
Copy link

netlify bot commented Dec 15, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit bb20768
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/693fe52be831550008ba8d2a
😎 Deploy Preview https://deploy-preview-2318--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.

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)
apps/desktop/src/components/main/sidebar/profile/ota/task.ts (1)

30-40: handleCloseDrawer wiring looks correct; confirm UX for closing mid-download

Exposing handleCloseDrawer and routing it to updateStore.trigger.closeDrawer() is consistent with the other handlers and keeps the hook API clean.

One behavior to be aware of: if the user closes the drawer while state === "downloading", showDrawer stays false even after downloadFinished sets the state to "ready", so the ready state drawer will not auto-reopen for that update. If the intended UX is to always surface the “ready to restart” prompt, you may want a follow-up event (e.g., in downloadFinished) to re-show the drawer or otherwise notify the user.

apps/desktop/src/components/main/sidebar/index.tsx (1)

26-80: Consider nesting UpdateDrawer inside the sidebar container to avoid layout surprises

By changing LeftSidebar to return a fragment and placing <UpdateDrawer /> as a sibling before the main <div>, callers now see two DOM children where previously there was a single sidebar element. If BottomSheet doesn’t fully portal out of the normal flow, this can subtly affect flex layout or sizing of the main content.

A safer pattern is to keep LeftSidebar’s root as a single <div> and render <UpdateDrawer /> inside it (e.g., as the first child). That preserves the external layout contract while still letting the bottom sheet overlay the UI via its own positioning.

📜 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 fa4f763 and 680da42.

📒 Files selected for processing (4)
  • apps/desktop/src/components/main/sidebar/index.tsx (2 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (1 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/store.ts (5 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/task.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{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:

  • apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx
  • apps/desktop/src/components/main/sidebar/index.tsx
  • apps/desktop/src/components/main/sidebar/profile/ota/store.ts
  • apps/desktop/src/components/main/sidebar/profile/ota/task.ts
**/*.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:

  • apps/desktop/src/components/main/sidebar/profile/ota/store.ts
  • apps/desktop/src/components/main/sidebar/profile/ota/task.ts
🧬 Code graph analysis (2)
apps/desktop/src/components/main/sidebar/index.tsx (3)
apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (1)
  • UpdateDrawer (12-125)
apps/desktop/src/components/main/sidebar/banner/index.tsx (1)
  • BannerArea (13-128)
apps/desktop/src/components/main/sidebar/profile/index.tsx (1)
  • ProfileSection (38-247)
apps/desktop/src/components/main/sidebar/profile/ota/task.ts (1)
apps/desktop/src/components/main/sidebar/profile/ota/store.ts (1)
  • updateStore (27-130)
⏰ 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). (6)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
🔇 Additional comments (2)
apps/desktop/src/components/main/sidebar/profile/ota/store.ts (1)

24-128: showDrawer state and transitions are coherent with the new drawer

The new showDrawer flag is consistently managed: it is initialized to false, turned on in startDownload, and cleared in cancelDownload, closeDrawer, and reset. This aligns with UpdateDrawer’s shouldShow logic and keeps the drawer visibility decoupled from the underlying OTA state machine, which is a clean separation.

apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (1)

12-124: UpdateDrawer cleanly reflects OTA state and actions

The component cleanly maps OTA state to UI: shouldShow correctly gates visibility, the progress indicator and “ready” visuals reflect downloadProgress and update.version, and the close/install/cancel actions are wired through the hook as expected. cn usage and conditional rendering patterns are consistent with local conventions.

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 (2)
apps/desktop/src/components/main/sidebar/profile/index.tsx (1)

284-312: Consider adding accessibility attributes to the progress indicator.

The circular progress SVG implementation is correct and visually clear. However, for better accessibility, consider adding ARIA attributes to communicate download progress to screen reader users.

Apply this diff to enhance accessibility:

-        {isDownloading && (
-          <svg className="absolute -inset-1 size-10" viewBox="0 0 40 40">
+        {isDownloading && (
+          <svg 
+            className="absolute -inset-1 size-10" 
+            viewBox="0 0 40 40"
+            role="progressbar"
+            aria-label="Download progress"
+            aria-valuenow={downloadProgress.percentage}
+            aria-valuemin={0}
+            aria-valuemax={100}
+          >
apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (1)

36-46: Consider using the Button component for the close button.

For consistency, consider using the Button component with an icon-only variant instead of a custom button element. This ensures uniform styling and behavior across all interactive elements.

If the Button component supports icon-only or ghost variants, apply this diff:

-          <button
-            onClick={handleCloseDrawer}
-            className={cn([
-              "flex h-8 w-8 items-center justify-center",
-              "rounded-full",
-              "hover:bg-neutral-100",
-              "transition-colors",
-            ])}
-          >
+          <Button
+            variant="ghost"
+            size="icon"
+            onClick={handleCloseDrawer}
+            className="h-8 w-8 rounded-full"
+          >
             <X className="h-4 w-4 text-neutral-500" />
-          </button>
+          </Button>
📜 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 680da42 and ccf13fe.

📒 Files selected for processing (3)
  • apps/desktop/src/components/main/sidebar/profile/index.tsx (3 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (1 hunks)
  • apps/desktop/src/components/main/sidebar/profile/ota/store.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{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:

  • apps/desktop/src/components/main/sidebar/profile/index.tsx
  • apps/desktop/src/components/main/sidebar/profile/ota/store.ts
  • apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx
**/*.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:

  • apps/desktop/src/components/main/sidebar/profile/ota/store.ts
🧬 Code graph analysis (2)
apps/desktop/src/components/main/sidebar/profile/index.tsx (2)
apps/desktop/src/components/main/sidebar/profile/ota/task.ts (1)
  • useOTA (30-41)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (3)
apps/desktop/src/components/main/sidebar/profile/ota/task.ts (1)
  • useOTA (30-41)
extensions/shared/types/hypr-extension.d.ts (3)
  • BottomSheet (139-139)
  • BottomSheetContent (140-140)
  • Button (159-159)
packages/utils/src/cn.ts (1)
  • cn (20-22)
⏰ 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). (6)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
🔇 Additional comments (8)
apps/desktop/src/components/main/sidebar/profile/index.tsx (3)

30-30: LGTM!

Clean import of the OTA hook for integration with the profile UI.


259-261: LGTM!

Clean destructuring of OTA state and derived boolean. The downloadProgress object is guaranteed to exist with a percentage property based on the store initialization.


313-331: LGTM!

The avatar rendering maintains the existing logic while properly accommodating the progress overlay. Good use of cn with array syntax for className management.

apps/desktop/src/components/main/sidebar/profile/ota/store.ts (2)

24-24: LGTM!

Clean addition of the showDrawer boolean flag to the OTA context with appropriate initialization.

Also applies to: 38-38


69-69: LGTM!

The state transitions for showDrawer are logically sound:

  • Shows drawer when download finishes (ready state)
  • Hides drawer on start, cancel, close, and reset

The dedicated closeDrawer event provides a clean API for dismissing the drawer.

Also applies to: 97-97, 108-113, 128-128

apps/desktop/src/components/main/sidebar/profile/ota/drawer.tsx (3)

1-10: LGTM!

Clean import structure with all necessary dependencies for the UpdateDrawer component.


12-18: LGTM!

Clean component setup with appropriate derived state. The double-check (showDrawer && isReady) ensures the drawer only appears when both conditions are met.


19-64: LGTM!

Well-structured drawer implementation with:

  • Clear visual hierarchy (icon + version + description)
  • Defensive programming with optional chaining on update?.version
  • User-friendly action choices (Later vs Restart now)
  • Proper semantic HTML and styling

The overall implementation provides a clean UX for OTA update notifications.

@yujonglee yujonglee closed this Dec 15, 2025
@yujonglee yujonglee deleted the feat/add-update-drawer branch December 15, 2025 10:58
@yujonglee yujonglee restored the feat/add-update-drawer branch December 15, 2025 10:59
@yujonglee yujonglee deleted the feat/add-update-drawer branch December 15, 2025 11:04
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.

2 participants