Skip to content

feat: add side panel view for the extension#2185

Merged
Nick-1979 merged 10 commits into
mainfrom
sidePanel
Jul 16, 2026
Merged

feat: add side panel view for the extension#2185
Nick-1979 merged 10 commits into
mainfrom
sidePanel

Conversation

@Nick-1979

@Nick-1979 Nick-1979 commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added a browser side panel experience with a one-click open button and side-panel support across key wallet screens.
    • Multiple popups and panels now use a compact side-panel layout with side-panel-aware sizing and smoother scroll fitting (including fade overlays).
    • Biometric settings now block enabling in the side panel and provide guidance to complete setup from popup/fullscreen.
  • Bug Fixes

    • Improved side panel vs popup detection using safer browser API access, with better handling of side-panel layouts for connected dapps/accounts and history/details.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Nick-1979, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ffdbbd70-107e-4374-8a39-0e11c7f3cc80

📥 Commits

Reviewing files that changed from the base of the PR and between 9eb5d38 and fe9f254.

📒 Files selected for processing (3)
  • packages/extension-polkagate/src/hooks/index.ts
  • packages/extension-polkagate/src/popup/staking/stakingInfo/index.tsx
  • packages/extension/public/locales/en/translation.json
📝 Walkthrough

Walkthrough

This PR adds side-panel support across the extension: new hooks and manifest entries register the side panel, a new button opens it, and many popup and staking screens now switch layout and sizing when rendered in side-panel mode.

Changes

Side Panel Mode

Layer / File(s) Summary
Hooks, manifest, and assets
packages/extension-polkagate/src/hooks/useIsSidePanel.ts, useUiMode.ts, useViewportHeight.ts, useIsExtensionPopup.ts, hooks/index.ts, packages/extension/manifest*.json, packages/extension/public/sidepanel.html, packages/extension/public/locales/en/translation.json
Adds side-panel and viewport hooks, hardens popup detection with typed chrome access, registers sidePanel permission/default_path in manifests, adds sidepanel.html, and adds related translation strings.
Compact popup mode and consumers
packages/extension-polkagate/src/components/ExtensionPopup.tsx, fullscreen/components/GovernanceModal.tsx, partials/RemoveAccount.tsx, partials/RenameAccount.tsx, partials/SignUsingProxy.tsx, popup/tokens/partial/TokenHistory.tsx, partials/BiometricUnlockSetting.tsx
Adds compactInSidePanel to ExtensionPopup, wires it into popup consumers, and adds side-panel-specific biometric blocking and tooltip behavior.
Side panel open button and header wiring
partials/SidePanelModeButton.tsx, partials/UserDashboardHeader.tsx
Adds a button that opens the browser side panel and closes the current window, rendered in the dashboard header.
Connected accounts, dapp, and website access layouts
partials/ConnectedAccounts.tsx, partials/ConnectedDapp.tsx, partials/WebsitesAccess.tsx
Makes these panels side-panel responsive and hardens tab detection via a typed chrome.tabs accessor.
Accounts list management side-panel layout
popup/accountsLists/*
Adapts body, edit/new profile, and list management layouts to side-panel sizing, adding scroll-fade overlays and reworking async profile-update flows.
Transaction history side-panel layout
popup/history/newDesign/*
Adjusts loading placeholders, replaces Dialog/DraggableModal with SharePopup in HistoryDetail, and adapts history index layout.
Home dashboard and related popups side-panel layout
popup/home/*, popup/nft/index.tsx, popup/notification/*, popup/receive/Receive.tsx, partials/SelectLanguage.tsx, popup/tokens/index.tsx
Adjusts layouts/scrolling/popup sizing for changelog, home, assets, currency, language, nft, notification, receive, and tokens screens.
Settings side-panel layout and theme toggle style prop
popup/settings/extensionSettings/*, popup/settings/partials/ActionRow.tsx, popup/settings/partials/actions/ThemeChange.tsx
Adds side-panel scroll-fade overlays to settings screens and passes a shared style prop into ThemeChange.
Staking pages side-panel layout
popup/staking/*, fullscreen/stake/new-solo/pendingReward/RewardsTable.tsx
Adapts staking and pending-reward screens to side-panel layout, plus minor PoolDetail and StakingInfoTile tweaks.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SidePanelModeButton
  participant chrome.sidePanel.open
  participant CurrentWindow
  User->>SidePanelModeButton: click
  SidePanelModeButton->>chrome.sidePanel.open: open({ windowId })
  chrome.sidePanel.open-->>SidePanelModeButton: success
  SidePanelModeButton->>CurrentWindow: window.close()
Loading

Possibly related PRs

Suggested labels: new design

Suggested reviewers: AMIRKHANEF

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a side panel view for the extension.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sidePanel

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.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add Chrome side panel mode for extension UI

✨ Enhancement 🐞 Bug fix ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add Chrome side panel entrypoint and an in-UI button to open it.
• Detect side panel mode and adapt popups/pages for constrained viewport heights.
• Block biometric enrollment from side panel; fix minor skeleton/layout inconsistencies.
Diagram

graph TD
  A[("Extension manifest") ] --> B["sidepanel.html"] --> C["Extension UI bundle"]
  C --> D["UI mode hooks"] --> E["Popup/pages"] --> F["ExtensionPopup"]
  E --> G["Side panel button"] --> H{{"Chrome Side Panel API"}}

  subgraph Legend
    direction LR
    _cfg[("Config")] ~~~ _ui["UI component"] ~~~ _ext{{"Browser API"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Centralize side panel layout in a shared page wrapper
  • ➕ Reduces scattered calc(100vh - …) constants across many screens
  • ➕ Makes future UI additions automatically side-panel-safe
  • ➕ Enables consistent scroll + fade behaviors in one place
  • ➖ Requires refactoring common page scaffolding and retesting multiple flows
  • ➖ May be harder to land incrementally if pages diverge structurally
2. Use CSS variables for header/footer heights + a single `--content-height`
  • ➕ Keeps math out of component code; easy to tune per mode
  • ➕ Improves maintainability and consistency across pages
  • ➖ Requires careful integration with MUI sx usage and existing layout containers
  • ➖ Still needs a migration across many screens
3. Feature-flag side panel for fewer routes initially
  • ➕ Lower initial risk; narrower surface area for layout regressions
  • ➕ Faster to validate with users before expanding
  • ➖ Partial experience may feel inconsistent
  • ➖ Still need to do the broad layout work later

Recommendation: Current approach is reasonable to ship side panel support quickly by adjusting the most impacted screens and adding mode hooks. As follow-up, consider centralizing side-panel sizing/scroll behavior (wrapper or CSS variables) to eliminate repeated calc(100vh - …) values and reduce future maintenance/regression risk.

Files changed (54) +696 / -340

Enhancement (40) +475 / -204
ExtensionPopup.tsxAdd compact side-panel sheet mode to ExtensionPopup +7/-4

Add compact side-panel sheet mode to ExtensionPopup

• Introduces 'compactInSidePanel' and uses 'useIsSidePanel()' to switch the popup container into a bottom-aligned, auto-height sheet with a capped maxHeight. This prevents full-screen popup layouts from breaking inside the side panel viewport.

packages/extension-polkagate/src/components/ExtensionPopup.tsx

GovernanceModal.tsxEnable compact popup layout for governance modal in side panel +1/-0

Enable compact popup layout for governance modal in side panel

• Passes 'compactInSidePanel: true' into popupProps so governance modal renders as a compact sheet when used inside the side panel.

packages/extension-polkagate/src/fullscreen/components/GovernanceModal.tsx

index.tsExport side panel + UI mode utility hooks +3/-0

Export side panel + UI mode utility hooks

• Adds exports for 'useIsSidePanel', 'useUiMode', and 'useViewportHeight' so screens can consistently detect side panel mode and respond to viewport changes.

packages/extension-polkagate/src/hooks/index.ts

useIsSidePanel.tsAdd hook to detect side panel document +6/-0

Add hook to detect side panel document

• New hook returning true when 'window.location.pathname' ends with '/sidepanel.html'. Used broadly for side-panel-specific layout decisions.

packages/extension-polkagate/src/hooks/useIsSidePanel.ts

useUiMode.tsAdd unified UI mode hook (extension vs side panel vs fullscreen) +28/-0

Add unified UI mode hook (extension vs side panel vs fullscreen)

• New helper combining 'useIsExtensionPopup' and 'useIsSidePanel' to derive 'isFullscreen' and other mode flags for layout decisions.

packages/extension-polkagate/src/hooks/useUiMode.ts

useViewportHeight.tsAdd viewport height hook for dynamic table sizing +18/-0

Add viewport height hook for dynamic table sizing

• New hook that tracks 'window.innerHeight' via resize listener and returns the current height; used to size side-panel tables more reliably.

packages/extension-polkagate/src/hooks/useViewportHeight.ts

ConnectedAccounts.tsxMake connected-accounts list scrollable and side-panel friendly +64/-50

Make connected-accounts list scrollable and side-panel friendly

• Adds side-panel-aware flex/height constraints and introduces a bottom 'FadeOnScroll' overlay with a translucent gradient for long lists. Uses a list ref to drive the fade behavior.

packages/extension-polkagate/src/partials/ConnectedAccounts.tsx

RemoveAccount.tsxRender remove-account popup as compact sheet in side panel +1/-1

Render remove-account popup as compact sheet in side panel

• Sets 'compactInSidePanel: true' in popupProps so remove account modal adapts to side panel constraints.

packages/extension-polkagate/src/partials/RemoveAccount.tsx

RenameAccount.tsxEnable compact side-panel layout for rename popup +1/-0

Enable compact side-panel layout for rename popup

• Adds 'compactInSidePanel' to the rename account 'ExtensionPopup' invocation for better fit in side panel.

packages/extension-polkagate/src/partials/RenameAccount.tsx

SelectLanguage.tsxAdjust language list sizing/padding for side panel +3/-2

Adjust language list sizing/padding for side panel

• Uses 'useIsSidePanel()' to switch the language list maxHeight to a viewport-based value and adds extra bottom padding for side panel scrolling.

packages/extension-polkagate/src/partials/SelectLanguage.tsx

SidePanelModeButton.tsxAdd header button to open Chrome side panel +94/-0

Add header button to open Chrome side panel

• New component that detects 'chrome.sidePanel.open' support and opens the side panel for the current window, then closes the popup. Includes hover styling and tooltip text.

packages/extension-polkagate/src/partials/SidePanelModeButton.tsx

UserDashboardHeader.tsxExpose side panel entry button in dashboard header +2/-0

Expose side panel entry button in dashboard header

• Adds 'SidePanelModeButton' next to notifications and fullscreen mode buttons so users can open the side panel from the popup UI.

packages/extension-polkagate/src/partials/UserDashboardHeader.tsx

WebsitesAccess.tsxMake website-access screen and popup height side-panel aware +20/-16

Make website-access screen and popup height side-panel aware

• Uses 'useIsSidePanel()' to scale list/popup heights based on viewport, ensuring the access list remains usable within side panel constraints.

packages/extension-polkagate/src/partials/WebsitesAccess.tsx

BodySection.tsxMake account list management scroll container side-panel friendly +4/-3

Make account list management scroll container side-panel friendly

• Adds 'useIsSidePanel()' and swaps fixed maxHeights/minHeights with side-panel-aware flex and viewport-based maxHeight values to avoid overflow issues.

packages/extension-polkagate/src/popup/accountsLists/BodySection.tsx

EditProfile.tsxImprove edit-profile scrolling and side-panel sizing +13/-10

Improve edit-profile scrolling and side-panel sizing

• Adds side-panel mode sizing, introduces a scroll ref, and adds 'FadeOnScroll' for the accounts selection step. Also adjusts popup maxHeight for side panel.

packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx

NewProfile.tsxImprove new-profile flow scrolling and side-panel sizing +13/-10

Improve new-profile flow scrolling and side-panel sizing

• Adds side-panel sizing and a 'FadeOnScroll' overlay for the account selection list. Also tweaks translation replacement arg ordering for consistency.

packages/extension-polkagate/src/popup/accountsLists/NewProfile.tsx

index.tsxAdapt accounts list pages to side panel layout +7/-4

Adapt accounts list pages to side panel layout

• Adds 'useIsSidePanel()' and updates the main container/Motion wrapper styles to support column layout and avoid overflow clipping in side panel mode.

packages/extension-polkagate/src/popup/accountsLists/index.tsx

index.tsxMake history page layout side-panel friendly +5/-4

Make history page layout side-panel friendly

• Adds 'useIsSidePanel()' and switches the page to a flex column layout with controlled overflow and viewport-based scroll areas in side panel mode.

packages/extension-polkagate/src/popup/history/newDesign/index.tsx

ChangeLog.tsxUse UiMode and resize changelog popup for side panel +6/-5

Use UiMode and resize changelog popup for side panel

• Uses 'useUiMode()' to detect side panel and increases changelog popup/list maxHeight to use available side panel viewport space.

packages/extension-polkagate/src/popup/home/ChangeLog.tsx

index.tsxRestructure home page scrolling and WhatsNew placement for side panel +22/-14

Restructure home page scrolling and WhatsNew placement for side panel

• Adjusts the home page to use a fixed header/footer layout in side panel, moving WhatsNew outside the primary scroll region and disabling the fade overlay in side panel mode.

packages/extension-polkagate/src/popup/home/index.tsx

AssetsBox.tsxMake assets box scroll and sizing side-panel aware +4/-3

Make assets box scroll and sizing side-panel aware

• Adds 'useIsSidePanel()' and updates layout to avoid fixed minHeights and to allow the assets list to scroll properly inside the side panel.

packages/extension-polkagate/src/popup/home/partial/AssetsBox.tsx

SelectCurrency.tsxAdjust currency selector list height for side panel +5/-2

Adjust currency selector list height for side panel

• Adds 'useIsSidePanel()' and updates list and popup maxHeights to rely on viewport math, improving usability in side panel.

packages/extension-polkagate/src/popup/home/partial/SelectCurrency.tsx

index.tsxAdapt NFT page container and scroll behavior for side panel +4/-3

Adapt NFT page container and scroll behavior for side panel

• Adds side-panel-aware flex layout and switches content overflow to scroll within the side panel viewport.

packages/extension-polkagate/src/popup/nft/index.tsx

index.tsxMake notifications page layout side-panel compatible +5/-4

Make notifications page layout side-panel compatible

• Adds 'useIsSidePanel()' and changes Motion/container sizing to avoid overflow issues and allow proper scrolling in side panel mode.

packages/extension-polkagate/src/popup/notification/index.tsx

SelectChain.tsxAdd FadeOnScroll and side-panel sizing to chain selection modal +8/-5

Add FadeOnScroll and side-panel sizing to chain selection modal

• Adds 'useIsSidePanel()' and a scroll ref to support side-panel-friendly list height and a 'FadeOnScroll' overlay for long lists.

packages/extension-polkagate/src/popup/notification/partials/SelectChain.tsx

SelectNotificationAccountsBody.tsxAdd FadeOnScroll and side-panel sizing for notification accounts list +8/-5

Add FadeOnScroll and side-panel sizing for notification accounts list

• Introduces 'useIsSidePanel()' and scroll ref to keep the account selection list usable in side panel and adds a fade overlay at the bottom.

packages/extension-polkagate/src/popup/notification/partials/SelectNotificationAccountsBody.tsx

Receive.tsxAdd FadeOnScroll and side-panel sizing for network selection list +7/-4

Add FadeOnScroll and side-panel sizing for network selection list

• Adds 'useIsSidePanel()' and a ref-driven FadeOnScroll to the network selector so large network lists remain navigable inside the side panel.

packages/extension-polkagate/src/popup/receive/Receive.tsx

Chains.tsxMake extension settings chains view layout work in side panel +4/-2

Make extension settings chains view layout work in side panel

• Adds 'useIsSidePanel()' and applies a flex column layout to Motion/Grid wrappers so the chains list fills side panel height correctly.

packages/extension-polkagate/src/popup/settings/extensionSettings/Chains.tsx

Endpoints.tsxSide-panel layout and fade overlay for endpoints settings +24/-6

Side-panel layout and fade overlay for endpoints settings

• Adds 'useIsSidePanel()' and restructures containers to avoid overflow clipping in side panel. Adds a 'FadeOnScroll' gradient overlay at the bottom of the endpoints list.

packages/extension-polkagate/src/popup/settings/extensionSettings/Endpoints.tsx

index.tsxSide-panel layout for extension settings shell + FadeOnScroll +27/-8

Side-panel layout for extension settings shell + FadeOnScroll

• Adds side-panel flex layout handling for the settings container and introduces a bottom FadeOnScroll overlay tied to a scroll ref for better UX.

packages/extension-polkagate/src/popup/settings/extensionSettings/index.tsx

EarningOptions.tsxAdapt staking options page layout for side panel +7/-6

Adapt staking options page layout for side panel

• Adds 'useIsSidePanel()' and updates Motion/VelvetBox sizing and overflow to work in a constrained side panel viewport.

packages/extension-polkagate/src/popup/staking/EarningOptions.tsx

Reward.tsxAdapt staking rewards page for side panel and improve scroll sizing +6/-5

Adapt staking rewards page for side panel and improve scroll sizing

• Adds 'useIsSidePanel()' and changes main container to a flex column layout with proper scroll behavior for side panel mode.

packages/extension-polkagate/src/popup/staking/Reward.tsx

StakingPositions.tsxAdapt staking positions page layout for side panel +5/-4

Adapt staking positions page layout for side panel

• Adds 'useIsSidePanel()' and updates Motion/VelvetBox sizing to avoid fixed maxHeight constraints and allow side panel scrolling.

packages/extension-polkagate/src/popup/staking/StakingPositions.tsx

SelectPool.tsxMake easy-stake pool selection scroll correctly in side panel +4/-3

Make easy-stake pool selection scroll correctly in side panel

• Adds 'useIsSidePanel()' and updates Motion/Stack sizing so the pool list fills available height and scrolls properly in side panel mode.

packages/extension-polkagate/src/popup/staking/easyStake/SelectPool.tsx

SelectValidator.tsxDynamic validator table height in side panel using viewport hook +6/-4

Dynamic validator table height in side panel using viewport hook

• Adds 'useIsSidePanel()' and 'useViewportHeight()' to size the nominators table based on current viewport height, preventing cramped/overflowed tables in the side panel.

packages/extension-polkagate/src/popup/staking/easyStake/SelectValidator.tsx

ChoosePool.tsxMake pool chooser list side-panel scrollable +3/-2

Make pool chooser list side-panel scrollable

• Adds 'useIsSidePanel()' and updates stack sizing to avoid fixed maxHeight constraints in side panel mode.

packages/extension-polkagate/src/popup/staking/pool-new/joinPool/ChoosePool.tsx

NominationsSetting.tsxDynamic nominations table height for side panel +9/-5

Dynamic nominations table height for side panel

• Adds 'useIsSidePanel()' and 'useViewportHeight()' and computes a minimum table height for side panel to keep nominations selection usable.

packages/extension-polkagate/src/popup/staking/solo-new/nominations/NominationsSetting.tsx

ChooseAccount.tsxSide-panel sizing and FadeOnScroll for account chooser modal +10/-6

Side-panel sizing and FadeOnScroll for account chooser modal

• Adds 'useIsSidePanel()' and a scroll ref to the account selection modal, enabling a fade overlay and viewport-based height values for side panel mode.

packages/extension-polkagate/src/popup/staking/solo-new/settings/ChooseAccount.tsx

index.tsxAdapt token details page container sizing for side panel +4/-3

Adapt token details page container sizing for side panel

• Adds 'useIsSidePanel()' and updates the main content container to use flex sizing and avoid fixed maxHeight in side panel mode.

packages/extension-polkagate/src/popup/tokens/index.tsx

TokenHistory.tsxRender token history filter popup as compact sheet in side panel +7/-1

Render token history filter popup as compact sheet in side panel

• Adds 'compactInSidePanel: true' to the filters SharePopup so it fits within side panel constraints.

packages/extension-polkagate/src/popup/tokens/partial/TokenHistory.tsx

Bug fix (6) +100 / -36
useIsExtensionPopup.tsTreat sidepanel.html as extension popup context and harden chrome access +18/-2

Treat sidepanel.html as extension popup context and harden chrome access

• Detects side panel documents and returns true for extension-mode behavior. Also wraps 'chrome' access through a typed 'getChrome()' helper to avoid runtime reference issues.

packages/extension-polkagate/src/hooks/useIsExtensionPopup.ts

BiometricUnlockSetting.tsxDisable biometric enrollment from side panel and adjust enrollment popup sizing +37/-16

Disable biometric enrollment from side panel and adjust enrollment popup sizing

• Blocks enabling biometrics from side panel when not already enabled and shows a tooltip/snackbar explaining where to enable. Also adjusts the enrollment SharePopup maxHeight and compact behavior for side panel.

packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx

ConnectedDapp.tsxHarden chrome.tabs usage and add side-panel layout constraints +32/-10

Harden chrome.tabs usage and add side-panel layout constraints

• Replaces direct 'chrome.tabs.query' with a safe wrapper that resolves empty tabs when unavailable. Updates layout and connected-accounts popup sizing for side panel mode.

packages/extension-polkagate/src/partials/ConnectedDapp.tsx

HistoryBox.tsxTune history loading count for side panel and simplify history entries iteration +9/-4

Tune history loading count for side panel and simplify history entries iteration

• Computes entries once and sets skeleton item count higher for side panel in short mode. This improves perceived loading and avoids repeated Object.entries work.

packages/extension-polkagate/src/popup/history/newDesign/HistoryBox.tsx

ActionRow.tsxTweak action row spacing and align ThemeChange styling +3/-3

Tweak action row spacing and align ThemeChange styling

• Adjusts margin-top and forwards a common 'style' into ThemeChange for consistent sizing alongside other action buttons.

packages/extension-polkagate/src/popup/settings/partials/ActionRow.tsx

StakingInfoTile.tsxFix staking rewards skeleton alignment +1/-1

Fix staking rewards skeleton alignment

• Adjusts 'skeletonAlignment' to depend on row vs column layout, aligning placeholder content with displayed amount position.

packages/extension-polkagate/src/popup/staking/partial/StakingInfoTile.tsx

Refactor (3) +63 / -88
HistoryDetail.tsxRefactor history detail modal to SharePopup and add side-panel sizing +54/-77

Refactor history detail modal to SharePopup and add side-panel sizing

• Replaces the conditional Dialog/DraggableModal implementation with a unified SharePopup-based approach. Adds side-panel-aware maxHeight for detail content scrolling.

packages/extension-polkagate/src/popup/history/newDesign/HistoryDetail.tsx

ThemeChange.tsxAllow ThemeChange to accept external sizing styles +3/-3

Allow ThemeChange to accept external sizing styles

• Updates ThemeChange to accept an 'SxProps<Theme>' style prop so the parent can control sizing/spacing consistently.

packages/extension-polkagate/src/popup/settings/partials/actions/ThemeChange.tsx

PoolDetail.tsxMinor PoolDetail rendering cleanup +6/-8

Minor PoolDetail rendering cleanup

• Simplifies conditional rendering around loading vs content to reduce nested blocks and improve readability without changing behavior.

packages/extension-polkagate/src/popup/staking/partial/PoolDetail.tsx

Documentation (1) +3 / -1
translation.jsonAdd side panel and biometric messaging strings +3/-1

Add side panel and biometric messaging strings

• Adds new translation keys for the side panel tooltip and the side-panel biometric enablement restriction message.

packages/extension/public/locales/en/translation.json

Other (4) +55 / -11
manifest.dev.jsonEnable side panel permission and side_panel entrypoint (dev) +6/-2

Enable side panel permission and side_panel entrypoint (dev)

• Adds the 'sidePanel' permission and registers 'side_panel.default_path' pointing to 'sidepanel.html' for development builds.

packages/extension/manifest.dev.json

manifest.jsonEnable side panel permission/entrypoint and update extension icons +11/-7

Enable side panel permission/entrypoint and update extension icons

• Adds 'sidePanel' permission and the 'side_panel' block with default_path. Also switches icon assets to the '*b.png' variants.

packages/extension/manifest.json

manifest.prod.jsonEnable side panel permission and side_panel entrypoint (prod) +6/-2

Enable side panel permission and side_panel entrypoint (prod)

• Adds the 'sidePanel' permission and registers 'side_panel.default_path' pointing to 'sidepanel.html' for production builds.

packages/extension/manifest.prod.json

sidepanel.htmlAdd side panel HTML entrypoint +32/-0

Add side panel HTML entrypoint

• Introduces a new HTML document that mounts the React app for Chrome side panel usage, matching the extension bundle loading pattern.

packages/extension/public/sidepanel.html

@qodo-code-review

qodo-code-review Bot commented Jul 1, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 14 rules

Grey Divider


Remediation recommended

1. Misindented useUiMode return ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new useUiMode hook has an inconsistently indented final return block, diverging from the
surrounding formatting and making the code harder to read/maintain. This can also create formatter
churn and potential lint failures.
Code

packages/extension-polkagate/src/hooks/useUiMode.ts[R23-28]

+ return {
+      isExtension,
+      isFullscreen: true,
+      isSidePanel
+    };
+}
Evidence
PR Compliance ID 660843 requires new/modified code to match existing local code style. In
useUiMode, the final return block is visibly misindented relative to the earlier return block
and surrounding statements.

Rule 660843: Match existing local code style in new or modified code
packages/extension-polkagate/src/hooks/useUiMode.ts[23-28]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The final `return` block in `useUiMode` is misindented compared to the rest of the file.

## Issue Context
This PR adds new UI-mode hooks; new/modified code should match the local style to avoid readability issues and formatting churn.

## Fix Focus Areas
- packages/extension-polkagate/src/hooks/useUiMode.ts[23-28]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. BiometricUnlockSetting uses async() 📘 Rule violation ⚙ Maintainability
Description
The updated callbacks in BiometricUnlockSetting use async() without a space, which is
inconsistent with the prevailing async () style used elsewhere in the package. This introduces
inconsistent formatting in changed code.
Code

packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx[R49-50]

+  const refreshStatus = useCallback(async() => {
    try {
Evidence
PR Compliance ID 660843 requires changed code to match the existing local style in the
module/package. The changed callbacks in BiometricUnlockSetting are formatted as async() while
other nearby package code uses async () (example cited), demonstrating inconsistent formatting
introduced by this PR.

Rule 660843: Match existing local code style in new or modified code
packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx[49-50]
packages/extension-polkagate/src/components/SignUsingPassword.tsx[85-85]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Several changed callbacks use `async()` (no space) which diverges from the package’s predominant `async ()` formatting.

## Issue Context
This is a style consistency issue in newly modified code; keeping consistent formatting reduces review noise and prevents formatter/lint churn.

## Fix Focus Areas
- packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx[49-50]
- packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx[79-80]
- packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx[120-120]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unchecked tab.url access ✓ Resolved 🐞 Bug ☼ Reliability
Description
ConnectedDapp / ConnectedDappContents destructure the first result from getActiveTabs() and
read tab.url without a null-check, which can throw when no tab is returned. This aborts the
dapp-connection check and can incorrectly mark the dapp as disconnected (or log an error) in such
cases.
Code

packages/extension-polkagate/src/partials/ConnectedDapp.tsx[R73-76]

+        const [tab] = await getActiveTabs();

        authDappUrl = tab.url;
      }
Evidence
The helper explicitly resolves an empty array when chrome.tabs.query is missing, making [tab]
potentially undefined; both call sites then dereference tab.url without a guard, which can
throw.

packages/extension-polkagate/src/partials/ConnectedDapp.tsx[32-43]
packages/extension-polkagate/src/partials/ConnectedDapp.tsx[62-76]
packages/extension-polkagate/src/partials/ConnectedDapp.tsx[167-181]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getActiveTabs()` can resolve to `[]` (e.g., when `chrome.tabs.query` is unavailable or returns no active tab). Both `ConnectedDappContents.checkTab` and `ConnectedDapp.checkTab` destructure `[tab]` and immediately access `tab.url`, which can throw at runtime.

### Issue Context
This breaks the “check current connection” logic and can prevent the UI from correctly determining whether the current site is connected.

### Fix Focus Areas
- packages/extension-polkagate/src/partials/ConnectedDapp.tsx[32-43]
- packages/extension-polkagate/src/partials/ConnectedDapp.tsx[62-82]
- packages/extension-polkagate/src/partials/ConnectedDapp.tsx[167-187]

### Suggested change
- Change the call sites to safely read the url:
 - `const tab = (await getActiveTabs())[0];`
 - `authDappUrl = tab?.url;`
- Optionally enhance `getActiveTabs()` to resolve `[]` when `chrome.runtime.lastError` is set, and/or return `Promise<Tab | undefined>` to enforce checking at compile time.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread packages/extension-polkagate/src/hooks/useUiMode.ts Outdated
Comment thread packages/extension-polkagate/src/partials/ConnectedDapp.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (5)
packages/extension-polkagate/src/popup/staking/pool-new/joinPool/ChoosePool.tsx (1)

105-135: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a flex-column wrapper for ChoosePool The current Motion wrapper is a plain motion.div, so flex: '1 1 auto'/minHeight: 0 on the inner Stack won’t take effect unless an ancestor sets display: flex; flexDirection: column.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/extension-polkagate/src/popup/staking/pool-new/joinPool/ChoosePool.tsx`
around lines 105 - 135, The inner Stack in ChoosePool relies on flex sizing, but
its current Motion wrapper is a plain motion.div so the column flex rules do not
apply. Update the ChoosePool wrapper around the Stack to be a flex column
container (or ensure the Motion component applies display flex with column
direction) so the Stack’s flex: '1 1 auto' and minHeight: 0 behavior works as
intended.
packages/extension-polkagate/src/popup/accountsLists/NewProfile.tsx (1)

50-73: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Same missing-.catch pattern as EditProfile.onEdit.

Promise.all(...).finally(...) here has no .catch, so a rejected updateMeta call surfaces as an unhandled promise rejection while the popup still closes via .finally as though the add succeeded.

🔧 Proposed fix
     }) || []).finally(() => {
+    }) || []).catch(console.error).finally(() => {
       setIsBusy(false);
       handleClose();
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/accountsLists/NewProfile.tsx` around
lines 50 - 73, The onAdd flow in NewProfile is missing the same rejection
handling used in EditProfile.onEdit: Promise.all(...).finally(...) will still
close the popup even if updateMeta fails, and the rejection becomes unhandled.
Update onAdd to explicitly catch errors around the Promise.all/updateMeta work,
keep setIsBusy(false) in a shared cleanup path, and only call handleClose after
a successful add so failures are surfaced instead of looking successful.
packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx (2)

47-83: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Missing error handling on the second persistence phase.

The first Promise.all (Lines 52-63) has .catch(console.error), but the second Promise.all (Lines 65-82) only has .finally, no .catch. If any updateMeta call in phase 2 rejects, it becomes an unhandled promise rejection — silently swallowed while the popup still closes as if the update succeeded (via .finally), giving the user no signal of a partial failure.

🔧 Proposed fix
     }) || []).finally(() => {
+    }) || []).catch(console.error).finally(() => {
       setIsBusy(false);
       handleClose();
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx` around
lines 47 - 83, The second persistence phase in onEdit is missing error handling,
so failures from updateMeta in the allAccounts Promise.all can become unhandled
while the popup still closes. Add a .catch handler to that Promise.all
(alongside the existing .finally) and surface/log the rejection before closing,
so the EditProfile flow only completes cleanly when all metadata updates
succeed. Keep the cleanup in .finally, but ensure any phase-2 failure is
observed and reported.

47-63: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Skip the cleanup pass for retained accounts. In this editable-profile path, useProfileAccounts(allAccounts, profileLabel) falls through to tag-based filtering, so account.profile?.includes(profileLabel) doesn’t narrow the loop. As a result, accounts that stay selected get stripped in phase 1 and written again in phase 2, adding an unnecessary update and briefly clearing the tag. Gate the first pass on !selectedAddresses.has(account.address) instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx` around
lines 47 - 63, The first cleanup pass in onEdit is affecting retained accounts
because the current account.profile?.includes(profileLabel) check does not
exclude still-selected accounts from useProfileAccounts(allAccounts,
profileLabel). Update the Promise.all loop in EditProfile.tsx to skip any
account whose address is in selectedAddresses by gating the cleanup on
!selectedAddresses.has(account.address), so retained accounts are not stripped
and rewritten during phase 1.
packages/extension-polkagate/src/popup/notification/partials/SelectChain.tsx (1)

61-74: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

ExtensionPopup needs a side-panel height override here. In side-panel mode the content grows to calc(100vh - 250px), but the popup shell still falls back to its 440px default because neither maxHeight nor compactInSidePanel is passed. That can leave this screen with extra scrolling or clipped content.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/notification/partials/SelectChain.tsx`
around lines 61 - 74, The SelectChain popup is not applying the side-panel
height override to ExtensionPopup, so the shell still uses its default 440px
sizing in side-panel mode. Update the ExtensionPopup usage in SelectChain to
pass the side-panel-specific height behavior, using the existing isSidePanel
check and the relevant props such as maxHeight and/or compactInSidePanel so the
shell matches the inner content sizing.
🧹 Nitpick comments (12)
packages/extension-polkagate/src/partials/ConnectedAccounts.tsx (1)

32-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stale comment now describes the wrong variable.

// Sort only on the first render, store result in a ref was moved above listRef but actually documents sortedAccountsRef (declared on the next line). Consider moving the comment back next to sortedAccountsRef.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/partials/ConnectedAccounts.tsx` around lines
32 - 40, The inline comment is attached to the wrong variable and now describes
`sortedAccountsRef` instead of `listRef`. Move or reattach the “Sort only on the
first render, store result in a ref” comment so it sits directly above
`sortedAccountsRef` in `ConnectedAccounts`, keeping `listRef` documented
separately and ensuring the comment matches the symbol it describes.
packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx (1)

41-49: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unreachable side-panel branch in the enable-password SharePopup.

isEnableBlockedInSidePanel (isSidePanel && !status.enabled) blocks the switch and onToggle whenever the user tries to enable biometrics from the side panel, and setShowPasswordForm(true) is only reached after that check passes. That means showPasswordForm can never be true while isSidePanel is true, so the isSidePanel branches in popupProps (Line 204 compactInSidePanel: isSidePanel, Line 205 maxHeight: isSidePanel ? 'calc(100vh - 190px)' : ...) never actually execute for this popup.

Consider simplifying to reflect that this modal only ever opens outside the side panel, or reconsider if the enable-block gate was meant to be narrower (e.g., only block after the password form step) so this branch becomes reachable.

♻️ Possible simplification if the enable-blocked gate is intentional as-is
         popupProps={{
-          compactInSidePanel: isSidePanel,
-          maxHeight: isSidePanel ? 'calc(100vh - 190px)' : isExtension ? '100%' : '360px',
+          maxHeight: isExtension ? '100%' : '360px',
           pt: 90,
           withGradientBorder: true
         }}

As per coding guidelines, "Write minimum code that solves the problem without speculative features" — this branch is speculative/unreachable given the current gating logic.

Also applies to: 107-120, 204-211

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx` around
lines 41 - 49, The `BiometricUnlockSetting` flow has an unreachable side-panel
path because `isEnableBlockedInSidePanel` prevents entering
`setShowPasswordForm(true)` when `isSidePanel` is true. Update the gating around
`onToggle`/password-form entry so the `popupProps` side-panel branches
(`compactInSidePanel`, `maxHeight`) are either removed as dead code or made
reachable by narrowing the block to the intended step in
`BiometricUnlockSetting`/`SharePopup` rather than blocking the entire enable
flow.

Source: Coding guidelines

packages/extension-polkagate/src/hooks/useUiMode.ts (1)

12-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify the redundant branches.

Both branches return the same isExtension/isSidePanel fields and only differ in isFullscreen, which is simply the negation of the if condition. This can be collapsed into a single return.

♻️ Proposed simplification
 export default function useUiMode(): {
   isExtension: boolean,
   isSidePanel: boolean,
   isFullscreen: boolean
 } {
   const isExtension = useIsExtensionPopup();
   const isSidePanel = useIsSidePanel();

-  if (isExtension || isSidePanel) {
-    return {
-      isExtension,
-      isFullscreen: false,
-      isSidePanel
-    };
-  }
-
- return {
-      isExtension,
-      isFullscreen: true,
-      isSidePanel
-    };
+  return {
+    isExtension,
+    isFullscreen: !(isExtension || isSidePanel),
+    isSidePanel
+  };
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/hooks/useUiMode.ts` around lines 12 - 28,
Simplify the redundant branching in useUiMode by collapsing the two return paths
into a single return statement. The function useUiMode currently returns the
same isExtension and isSidePanel values in both branches, so replace the if/else
structure with one object that sets isFullscreen based on the negation of the
existing extension/side-panel condition. Keep the useIsExtensionPopup and
useIsSidePanel calls unchanged.
packages/extension-polkagate/src/hooks/useIsExtensionPopup.ts (2)

12-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse useIsSidePanel instead of re-deriving the pathname check.

This inlines the same /sidepanel.html pathname check already implemented in useIsSidePanel.ts. Reusing the hook avoids duplicated logic that could drift if the detection rule changes.

♻️ Proposed fix
+import useIsSidePanel from './useIsSidePanel';
+
 export default function useIsExtensionPopup(): boolean {
-  const isSidePanel = window.location.pathname.endsWith('/sidepanel.html');
+  const isSidePanel = useIsSidePanel();

   if (isSidePanel) {
     return true;
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/hooks/useIsExtensionPopup.ts` around lines
12 - 17, The pathname check for detecting the extension popup is duplicated in
useIsExtensionPopup and should reuse the existing useIsSidePanel hook instead of
re-deriving /sidepanel.html logic. Update useIsExtensionPopup to call
useIsSidePanel and base its return value on that shared hook so the detection
logic stays centralized and consistent.

4-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate chrome-access boilerplate across files.

ChromeWithExtensionViews/getChrome here mirrors the near-identical ChromeWithSidePanel/getChrome pattern in SidePanelModeButton.tsx. Consider extracting a shared typed chrome accessor (or a single unified interface) to avoid maintaining duplicate globalThis.chrome typings in multiple places.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/hooks/useIsExtensionPopup.ts` around lines 4
- 10, The chrome access typing is duplicated here and in the SidePanelModeButton
code path, so extract a shared typed chrome accessor or unified chrome interface
instead of keeping separate ChromeWithExtensionViews/getChrome boilerplate in
useIsExtensionPopup. Move the reusable chrome typing/access helper to a common
module, then update both useIsExtensionPopup and SidePanelModeButton to consume
that shared symbol so globalThis.chrome is defined in one place.
packages/extension-polkagate/src/partials/SidePanelModeButton.tsx (2)

74-89: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Clickable Box lacks keyboard accessibility.

No role, tabIndex, or onKeyDown handler, so keyboard-only users can't activate this button. If this matches an existing pattern (e.g. FullscreenModeButton), consider addressing both together.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/partials/SidePanelModeButton.tsx` around
lines 74 - 89, The clickable Box in SidePanelModeButton is mouse-only and lacks
keyboard access. Update the Box used as the button container to match the
existing accessible button pattern (for example, the one in
FullscreenModeButton) by adding the appropriate role, tabIndex, and an onKeyDown
handler that activates on keyboard input. Keep the existing onClick behavior and
ensure the interactive semantics are applied to the same buttonContainer
element.

11-20: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Centralize the typed chrome accessor Consider sharing the chrome wrapper/type instead of duplicating ChromeWith* + getChrome in useIsExtensionPopup.ts, ConnectedDapp.tsx, and this file; keeping them local makes the chrome shape easy to drift over time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/partials/SidePanelModeButton.tsx` around
lines 11 - 20, Centralize the typed chrome accessor instead of keeping separate
ChromeWith* interfaces and getChrome helpers in SidePanelModeButton,
useIsExtensionPopup, and ConnectedDapp. Move the shared chrome shape/wrapper
into a common utility or type definition, then update SidePanelModeButton to
import and use that shared accessor so the chrome API contract stays consistent
across all call sites.
packages/extension-polkagate/src/popup/staking/easyStake/SelectPool.tsx (1)

118-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stack sx layout object is duplicated in ChoosePool.tsx.

The exact same object (flex/height/maxHeight/minHeight/overflowY) is repeated in packages/extension-polkagate/src/popup/staking/pool-new/joinPool/ChoosePool.tsx (line 105). Given both components already share nearly identical pool-filtering logic, consider extracting a shared usePoolListStackStyle() helper (or a small shared style constant) to avoid the two copies drifting apart.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/staking/easyStake/SelectPool.tsx` at
line 118, The Stack sx layout object used in SelectPool and ChoosePool is
duplicated and should be centralized. Extract the shared
flex/height/maxHeight/minHeight/overflowY/px/width styling into a common helper
or shared constant such as a usePoolListStackStyle() hook, then use it from both
SelectPool and ChoosePool to keep the pool list container styling in sync.
packages/extension-polkagate/src/popup/staking/EarningOptions.tsx (1)

74-87: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extract the repeated side-panel layout styles into a shared helper.

The Grid sx (flexDirection/flexWrap/height/overflow/pb) and the Motion style object are duplicated verbatim in Reward.tsx (lines 207, 209) and StakingPositions.tsx (lines 183, 191). A shared hook/constant (e.g. useSidePanelPageStyle() returning { gridSx, motionStyle }) would remove this triplication and prevent future drift when one page's layout needs tweaking but the others are missed.

♻️ Example extraction
// hooks/useSidePanelPageStyle.ts
export default function useSidePanelPageStyle(bottomPad = '86px') {
  const isSidePanel = useIsSidePanel();

  return {
    isSidePanel,
    gridSx: {
      flexDirection: isSidePanel ? 'column' : undefined,
      flexWrap: isSidePanel ? 'nowrap' : undefined,
      height: isSidePanel ? '100vh' : undefined,
      overflow: isSidePanel ? 'hidden' : undefined,
      pb: isSidePanel ? bottomPad : undefined,
      position: 'relative'
    },
    motionStyle: isSidePanel
      ? { display: 'flex', flex: '1 1 auto', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }
      : undefined
  } as const;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/staking/EarningOptions.tsx` around
lines 74 - 87, The side-panel layout styles in the EarningOptions page are
duplicated in other staking pages, so extract them into a shared helper to keep
them consistent. Move the repeated Grid sx values and Motion style object into a
reusable hook/constant such as useSidePanelPageStyle, and use that shared source
from EarningOptions, Reward, and StakingPositions. Keep the helper centered
around the existing isSidePanel logic so the page components only consume gridSx
and motionStyle instead of redefining the same objects.
packages/extension-polkagate/src/popup/staking/solo-new/nominations/NominationsSetting.tsx (1)

91-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate side-panel height formula across files.

Math.max(viewportHeight - 165, 300) is repeated verbatim in SelectValidator.tsx (line 140). Consider extracting a shared hook (e.g., useSidePanelTableHeight) to avoid the magic numbers drifting out of sync.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/extension-polkagate/src/popup/staking/solo-new/nominations/NominationsSetting.tsx`
around lines 91 - 93, The side-panel table height calculation is duplicated with
the same magic numbers, so extract it into a shared helper/hook such as
useSidePanelTableHeight and use that from NominationsSetting and
SelectValidator. Keep the shared logic in one place using the
viewportHeight-based Math.max(...) formula so both components stay in sync and
the constants are defined only once.
packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx (1)

99-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared viewport offsets These side-panel calc(100vh - …) values are duplicated across packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx, packages/extension-polkagate/src/popup/accountsLists/NewProfile.tsx, and packages/extension-polkagate/src/popup/accountsLists/BodySection.tsx. Pull them into a shared constant/helper so the layout spacing stays consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx` around
lines 99 - 106, The side-panel viewport offset values are duplicated across
EditProfile, NewProfile, and BodySection, so extract the repeated `calc(100vh -
…)` spacing into a shared constant or helper and use it from the relevant layout
styles. Update the `EditProfile` layout block (and the matching side-panel
sizing in `NewProfile` and `BodySection`) to reference the shared symbol so the
spacing stays consistent in one place.
packages/extension-polkagate/src/popup/nft/index.tsx (1)

74-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate sx object shared verbatim with notification/index.tsx.

The outer Grid sx here (flexDirection, flexWrap, height: '100vh', overflow: 'hidden', pb: '86px', position: 'relative', all gated on isSidePanel) is byte-for-byte identical to the one in packages/extension-polkagate/src/popup/notification/index.tsx (line 43), and per the PR description this "page shell" pattern likely repeats across several more files in this cohort (home, tokens, etc.). Consider extracting a shared hook/helper (e.g. useSidePanelPageSx()) returning this sx object to avoid maintaining N copies of the same conditional styling.

♻️ Example extraction
// hooks/useSidePanelPageSx.ts
export default function useSidePanelPageSx() {
  const isSidePanel = useIsSidePanel();

  return {
    flexDirection: isSidePanel ? 'column' : undefined,
    flexWrap: isSidePanel ? 'nowrap' : undefined,
    height: isSidePanel ? '100vh' : undefined,
    overflow: isSidePanel ? 'hidden' : undefined,
    pb: isSidePanel ? '86px' : undefined,
    position: 'relative'
  } as const;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/extension-polkagate/src/popup/nft/index.tsx` around lines 74 - 80,
The outer Grid styling in this NFT popup is duplicated verbatim across the
side-panel page shell, so extract the shared conditional sx into a reusable
helper or hook (for example, a page-shell sx builder) and use it here and in the
matching notification/page components. Update the Grid in nft/index.tsx to
consume that shared source of truth so the same isSidePanel-dependent layout is
maintained in one place instead of repeating the object in multiple files.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/extension-polkagate/src/partials/SidePanelModeButton.tsx`:
- Line 30: The SidePanelModeButton component is duplicating the side panel URL
check instead of using the shared hook. Update SidePanelModeButton to import and
use useIsSidePanel from the hooks barrel, and replace the inline useMemo
pathname comparison with that hook so the logic stays centralized and
consistent.

In `@packages/extension-polkagate/src/popup/settings/extensionSettings/index.tsx`:
- Line 27: The `location` variable in `ExtensionSettings` is being cast to the
DOM `Location` type, which hides the router-specific shape returned by
`useLocation()`. Update the typing in `index.tsx` to use the router location
type (or narrow only `state` on the `useLocation` result) so `location`
correctly reflects the values from React Router without pretending to be a DOM
`Location`.

---

Outside diff comments:
In `@packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx`:
- Around line 47-83: The second persistence phase in onEdit is missing error
handling, so failures from updateMeta in the allAccounts Promise.all can become
unhandled while the popup still closes. Add a .catch handler to that Promise.all
(alongside the existing .finally) and surface/log the rejection before closing,
so the EditProfile flow only completes cleanly when all metadata updates
succeed. Keep the cleanup in .finally, but ensure any phase-2 failure is
observed and reported.
- Around line 47-63: The first cleanup pass in onEdit is affecting retained
accounts because the current account.profile?.includes(profileLabel) check does
not exclude still-selected accounts from useProfileAccounts(allAccounts,
profileLabel). Update the Promise.all loop in EditProfile.tsx to skip any
account whose address is in selectedAddresses by gating the cleanup on
!selectedAddresses.has(account.address), so retained accounts are not stripped
and rewritten during phase 1.

In `@packages/extension-polkagate/src/popup/accountsLists/NewProfile.tsx`:
- Around line 50-73: The onAdd flow in NewProfile is missing the same rejection
handling used in EditProfile.onEdit: Promise.all(...).finally(...) will still
close the popup even if updateMeta fails, and the rejection becomes unhandled.
Update onAdd to explicitly catch errors around the Promise.all/updateMeta work,
keep setIsBusy(false) in a shared cleanup path, and only call handleClose after
a successful add so failures are surfaced instead of looking successful.

In
`@packages/extension-polkagate/src/popup/notification/partials/SelectChain.tsx`:
- Around line 61-74: The SelectChain popup is not applying the side-panel height
override to ExtensionPopup, so the shell still uses its default 440px sizing in
side-panel mode. Update the ExtensionPopup usage in SelectChain to pass the
side-panel-specific height behavior, using the existing isSidePanel check and
the relevant props such as maxHeight and/or compactInSidePanel so the shell
matches the inner content sizing.

In
`@packages/extension-polkagate/src/popup/staking/pool-new/joinPool/ChoosePool.tsx`:
- Around line 105-135: The inner Stack in ChoosePool relies on flex sizing, but
its current Motion wrapper is a plain motion.div so the column flex rules do not
apply. Update the ChoosePool wrapper around the Stack to be a flex column
container (or ensure the Motion component applies display flex with column
direction) so the Stack’s flex: '1 1 auto' and minHeight: 0 behavior works as
intended.

---

Nitpick comments:
In `@packages/extension-polkagate/src/hooks/useIsExtensionPopup.ts`:
- Around line 12-17: The pathname check for detecting the extension popup is
duplicated in useIsExtensionPopup and should reuse the existing useIsSidePanel
hook instead of re-deriving /sidepanel.html logic. Update useIsExtensionPopup to
call useIsSidePanel and base its return value on that shared hook so the
detection logic stays centralized and consistent.
- Around line 4-10: The chrome access typing is duplicated here and in the
SidePanelModeButton code path, so extract a shared typed chrome accessor or
unified chrome interface instead of keeping separate
ChromeWithExtensionViews/getChrome boilerplate in useIsExtensionPopup. Move the
reusable chrome typing/access helper to a common module, then update both
useIsExtensionPopup and SidePanelModeButton to consume that shared symbol so
globalThis.chrome is defined in one place.

In `@packages/extension-polkagate/src/hooks/useUiMode.ts`:
- Around line 12-28: Simplify the redundant branching in useUiMode by collapsing
the two return paths into a single return statement. The function useUiMode
currently returns the same isExtension and isSidePanel values in both branches,
so replace the if/else structure with one object that sets isFullscreen based on
the negation of the existing extension/side-panel condition. Keep the
useIsExtensionPopup and useIsSidePanel calls unchanged.

In `@packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx`:
- Around line 41-49: The `BiometricUnlockSetting` flow has an unreachable
side-panel path because `isEnableBlockedInSidePanel` prevents entering
`setShowPasswordForm(true)` when `isSidePanel` is true. Update the gating around
`onToggle`/password-form entry so the `popupProps` side-panel branches
(`compactInSidePanel`, `maxHeight`) are either removed as dead code or made
reachable by narrowing the block to the intended step in
`BiometricUnlockSetting`/`SharePopup` rather than blocking the entire enable
flow.

In `@packages/extension-polkagate/src/partials/ConnectedAccounts.tsx`:
- Around line 32-40: The inline comment is attached to the wrong variable and
now describes `sortedAccountsRef` instead of `listRef`. Move or reattach the
“Sort only on the first render, store result in a ref” comment so it sits
directly above `sortedAccountsRef` in `ConnectedAccounts`, keeping `listRef`
documented separately and ensuring the comment matches the symbol it describes.

In `@packages/extension-polkagate/src/partials/SidePanelModeButton.tsx`:
- Around line 74-89: The clickable Box in SidePanelModeButton is mouse-only and
lacks keyboard access. Update the Box used as the button container to match the
existing accessible button pattern (for example, the one in
FullscreenModeButton) by adding the appropriate role, tabIndex, and an onKeyDown
handler that activates on keyboard input. Keep the existing onClick behavior and
ensure the interactive semantics are applied to the same buttonContainer
element.
- Around line 11-20: Centralize the typed chrome accessor instead of keeping
separate ChromeWith* interfaces and getChrome helpers in SidePanelModeButton,
useIsExtensionPopup, and ConnectedDapp. Move the shared chrome shape/wrapper
into a common utility or type definition, then update SidePanelModeButton to
import and use that shared accessor so the chrome API contract stays consistent
across all call sites.

In `@packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx`:
- Around line 99-106: The side-panel viewport offset values are duplicated
across EditProfile, NewProfile, and BodySection, so extract the repeated
`calc(100vh - …)` spacing into a shared constant or helper and use it from the
relevant layout styles. Update the `EditProfile` layout block (and the matching
side-panel sizing in `NewProfile` and `BodySection`) to reference the shared
symbol so the spacing stays consistent in one place.

In `@packages/extension-polkagate/src/popup/nft/index.tsx`:
- Around line 74-80: The outer Grid styling in this NFT popup is duplicated
verbatim across the side-panel page shell, so extract the shared conditional sx
into a reusable helper or hook (for example, a page-shell sx builder) and use it
here and in the matching notification/page components. Update the Grid in
nft/index.tsx to consume that shared source of truth so the same
isSidePanel-dependent layout is maintained in one place instead of repeating the
object in multiple files.

In `@packages/extension-polkagate/src/popup/staking/EarningOptions.tsx`:
- Around line 74-87: The side-panel layout styles in the EarningOptions page are
duplicated in other staking pages, so extract them into a shared helper to keep
them consistent. Move the repeated Grid sx values and Motion style object into a
reusable hook/constant such as useSidePanelPageStyle, and use that shared source
from EarningOptions, Reward, and StakingPositions. Keep the helper centered
around the existing isSidePanel logic so the page components only consume gridSx
and motionStyle instead of redefining the same objects.

In `@packages/extension-polkagate/src/popup/staking/easyStake/SelectPool.tsx`:
- Line 118: The Stack sx layout object used in SelectPool and ChoosePool is
duplicated and should be centralized. Extract the shared
flex/height/maxHeight/minHeight/overflowY/px/width styling into a common helper
or shared constant such as a usePoolListStackStyle() hook, then use it from both
SelectPool and ChoosePool to keep the pool list container styling in sync.

In
`@packages/extension-polkagate/src/popup/staking/solo-new/nominations/NominationsSetting.tsx`:
- Around line 91-93: The side-panel table height calculation is duplicated with
the same magic numbers, so extract it into a shared helper/hook such as
useSidePanelTableHeight and use that from NominationsSetting and
SelectValidator. Keep the shared logic in one place using the
viewportHeight-based Math.max(...) formula so both components stay in sync and
the constants are defined only once.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bd9bfc52-21cf-486e-b7fb-9f2d6c666feb

📥 Commits

Reviewing files that changed from the base of the PR and between be049be and dd03d0b.

📒 Files selected for processing (54)
  • packages/extension-polkagate/src/components/ExtensionPopup.tsx
  • packages/extension-polkagate/src/fullscreen/components/GovernanceModal.tsx
  • packages/extension-polkagate/src/hooks/index.ts
  • packages/extension-polkagate/src/hooks/useIsExtensionPopup.ts
  • packages/extension-polkagate/src/hooks/useIsSidePanel.ts
  • packages/extension-polkagate/src/hooks/useUiMode.ts
  • packages/extension-polkagate/src/hooks/useViewportHeight.ts
  • packages/extension-polkagate/src/partials/BiometricUnlockSetting.tsx
  • packages/extension-polkagate/src/partials/ConnectedAccounts.tsx
  • packages/extension-polkagate/src/partials/ConnectedDapp.tsx
  • packages/extension-polkagate/src/partials/RemoveAccount.tsx
  • packages/extension-polkagate/src/partials/RenameAccount.tsx
  • packages/extension-polkagate/src/partials/SelectLanguage.tsx
  • packages/extension-polkagate/src/partials/SidePanelModeButton.tsx
  • packages/extension-polkagate/src/partials/UserDashboardHeader.tsx
  • packages/extension-polkagate/src/partials/WebsitesAccess.tsx
  • packages/extension-polkagate/src/popup/accountsLists/BodySection.tsx
  • packages/extension-polkagate/src/popup/accountsLists/EditProfile.tsx
  • packages/extension-polkagate/src/popup/accountsLists/NewProfile.tsx
  • packages/extension-polkagate/src/popup/accountsLists/index.tsx
  • packages/extension-polkagate/src/popup/history/newDesign/HistoryBox.tsx
  • packages/extension-polkagate/src/popup/history/newDesign/HistoryDetail.tsx
  • packages/extension-polkagate/src/popup/history/newDesign/index.tsx
  • packages/extension-polkagate/src/popup/home/ChangeLog.tsx
  • packages/extension-polkagate/src/popup/home/index.tsx
  • packages/extension-polkagate/src/popup/home/partial/AssetsBox.tsx
  • packages/extension-polkagate/src/popup/home/partial/SelectCurrency.tsx
  • packages/extension-polkagate/src/popup/nft/index.tsx
  • packages/extension-polkagate/src/popup/notification/index.tsx
  • packages/extension-polkagate/src/popup/notification/partials/SelectChain.tsx
  • packages/extension-polkagate/src/popup/notification/partials/SelectNotificationAccountsBody.tsx
  • packages/extension-polkagate/src/popup/receive/Receive.tsx
  • packages/extension-polkagate/src/popup/settings/extensionSettings/Chains.tsx
  • packages/extension-polkagate/src/popup/settings/extensionSettings/Endpoints.tsx
  • packages/extension-polkagate/src/popup/settings/extensionSettings/index.tsx
  • packages/extension-polkagate/src/popup/settings/partials/ActionRow.tsx
  • packages/extension-polkagate/src/popup/settings/partials/actions/ThemeChange.tsx
  • packages/extension-polkagate/src/popup/staking/EarningOptions.tsx
  • packages/extension-polkagate/src/popup/staking/Reward.tsx
  • packages/extension-polkagate/src/popup/staking/StakingPositions.tsx
  • packages/extension-polkagate/src/popup/staking/easyStake/SelectPool.tsx
  • packages/extension-polkagate/src/popup/staking/easyStake/SelectValidator.tsx
  • packages/extension-polkagate/src/popup/staking/partial/PoolDetail.tsx
  • packages/extension-polkagate/src/popup/staking/partial/StakingInfoTile.tsx
  • packages/extension-polkagate/src/popup/staking/pool-new/joinPool/ChoosePool.tsx
  • packages/extension-polkagate/src/popup/staking/solo-new/nominations/NominationsSetting.tsx
  • packages/extension-polkagate/src/popup/staking/solo-new/settings/ChooseAccount.tsx
  • packages/extension-polkagate/src/popup/tokens/index.tsx
  • packages/extension-polkagate/src/popup/tokens/partial/TokenHistory.tsx
  • packages/extension/manifest.dev.json
  • packages/extension/manifest.json
  • packages/extension/manifest.prod.json
  • packages/extension/public/locales/en/translation.json
  • packages/extension/public/sidepanel.html

Comment thread packages/extension-polkagate/src/partials/SidePanelModeButton.tsx Outdated
@Nick-1979
Nick-1979 merged commit 1b32f33 into main Jul 16, 2026
7 checks passed
@Nick-1979
Nick-1979 deleted the sidePanel branch July 16, 2026 09:14
github-actions Bot pushed a commit that referenced this pull request Jul 16, 2026
# [2.14.0](v2.13.0...v2.14.0) (2026-07-16)

### Features

* add side panel view for the extension ([#2185](#2185)) ([1b32f33](1b32f33))
@Nick-1979
Nick-1979 restored the sidePanel branch July 16, 2026 09:27
@Nick-1979
Nick-1979 deleted the sidePanel branch July 16, 2026 09:27
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