Skip to content

Conversation

@kvhnuke
Copy link
Contributor

@kvhnuke kvhnuke commented Aug 17, 2022

Summary by CodeRabbit

  • New Features

    • Safari support: buildable Safari extension and a macOS app with Safari-integrated UI.
    • New Safari build option for the extension.
  • Bug Fixes

    • Hide unsupported features on Safari (DApps link, Buy/Sell, Swap) for a smoother experience.
    • Hardware wallet options now only appear in supported browsers.
    • Onboarding now reliably closes the active tab; Safari action window kept alive as needed.
  • Chores

    • CI/CD enhancements: macOS build/deploy workflow, unified build/test/release jobs, artifact uploads, caching, and automated file scanning with PR summary.

✏️ Tip: You can customize this high-level summary in your review settings.

Copy link

@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 (1)
packages/extension/src/ui/action/views/asset-detail-view/components/asset-detail-action.vue (1)

47-47: Global Safari detection flag implemented.

The code now assigns the global __IS_SAFARI__ flag to a local variable. This implementation correctly supports the conditional rendering of UI elements based on browser detection.

For consistency with the rest of the codebase, consider using camelCase for variable naming (isSafari instead of is_safari). Also, ensure that __IS_SAFARI__ is properly defined in your build configuration.

-const is_safari = __IS_SAFARI__;
+const isSafari = __IS_SAFARI__;

And update the conditionals accordingly:

-v-if="!is_safari"
+v-if="!isSafari"
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between b3b34ac and 4c181a6.

📒 Files selected for processing (1)
  • packages/extension/src/ui/action/views/asset-detail-view/components/asset-detail-action.vue (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: build all
  • GitHub Check: safari build
  • GitHub Check: test
  • GitHub Check: test all
🔇 Additional comments (2)
packages/extension/src/ui/action/views/asset-detail-view/components/asset-detail-action.vue (2)

5-5: Conditional rendering for Buy/Sell button in Safari.

The code now hides the Buy/Sell button when running in Safari browsers. This aligns with the PR objective to add Safari support, presumably because this functionality is not supported or behaves differently in Safari.

Can you confirm why the Buy/Sell functionality needs to be disabled specifically for Safari? Adding a code comment would help future developers understand this limitation.


25-25: Conditional rendering for Swap link in Safari.

Similar to the Buy/Sell button, the Swap functionality is now hidden when running in Safari browsers.

Is there a specific Safari limitation that prevents the Swap functionality from working properly? Consider documenting this constraint for maintainability.

Copy link

@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)
packages/extension/src/ui/action/App.vue (2)

246-250: Safari keepalive interval works but could guard against unhandled promise rejections

The Safari-specific keepalive via setInterval(isKeyRingLocked, 5000) is a pragmatic way to keep the action window alive. However, because isKeyRingLocked is async, any thrown error or rejected promise will be unhandled here.

Low risk, but you might want to explicitly “fire and forget” with error handling, and optionally keep an interval id to clear on unmount:

-import { computed, onMounted, ref } from 'vue';
+import { computed, onMounted, onBeforeUnmount, ref } from 'vue';

 let keepaliveIntervalId: number | undefined;

 onMounted(async () => {
   // ...
   if (isInitialized) {
     const _isLocked = await isKeyRingLocked();
     if (__IS_SAFARI__) {
-      setInterval(() => {
-        isKeyRingLocked(); // keepalive safari action window
-      }, 1000 * 5);
+      keepaliveIntervalId = window.setInterval(() => {
+        void isKeyRingLocked().catch(console.error); // keepalive safari action window
+      }, 1000 * 5);
     }
     // ...
   }
 });

+onBeforeUnmount(() => {
+  if (keepaliveIntervalId !== undefined) {
+    clearInterval(keepaliveIntervalId);
+  }
+});

Not strictly required for correctness in a short-lived popup, but it tightens things up.


486-493: External Google Fonts import: consider bundling font locally

Importing Roboto from Google Fonts will work, but it adds an external network dependency and potential privacy/performance considerations in an extension context.

If store policies or your own privacy posture are strict, consider bundling the font with the extension and referencing it locally instead of via fonts.googleapis.com. Otherwise, this change is fine as-is.

📜 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 f23d558 and bedab7d.

📒 Files selected for processing (2)
  • packages/extension/package.json (1 hunks)
  • packages/extension/src/ui/action/App.vue (7 hunks)
⏰ 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: build all
  • GitHub Check: test all
  • GitHub Check: safari build
  • GitHub Check: test
🔇 Additional comments (4)
packages/extension/package.json (1)

19-19: Verify if Safari build should include system info generation step.

The new build:safari script follows the established pattern for browser-specific builds and is consistent with build:chrome and build:opera. However, the build:firefox script (Line 17) includes an additional step && node configs/get-system-info.js that build:safari does not.

Verify whether this system info generation step should also be applied to Safari builds, or if it's Firefox-specific and intentionally omitted for Safari.

Additionally, ensure that the build infrastructure (particularly vite.config.ts) properly recognizes and handles BROWSER='safari' as a valid environment value, and that manifest.safari.ts is properly integrated into the build pipeline.

packages/extension/src/ui/action/App.vue (3)

12-18: Main app template refactor looks clean and preserves behavior

The restructuring of the main app template (loading block, app-menu, accounts-header, routed view, and modals) is readable and keeps the existing behavior intact. Prop wiring and event handlers (setNetwork, toggleDepositWindow, lock action, updates/settings/addNetwork modals) still line up with the script logic.

No issues here from a functional standpoint.

Also applies to: 21-27, 30-32, 36-37, 39-40, 42-45


190-191: Multi-line buy URL template remains correct

The reflowed default buyLink template string still produces the same URL: the newline is inside the ${ ... } expression and doesn’t introduce whitespace into the actual URL. Interpolation of network, crypto, and platform remains intact.

Looks good.


530-533: Gradient/background tweak is cosmetic and safe

The updated radial-gradient plus @primary background on .app__loading is syntactically valid and only affects visuals. No behavioral impact on layout or logic.

Looks good.

Comment on lines 3 to 8
<div :class="['app', 'restricted-container', 'expanded']" v-if="foundRestrictedAddress || geoRestricted">
<swap-looking-animation />
<div v-if="popupClosed" class="app__loading__text">
<h2>Close this window</h2>
<p>Continue to onboard on the background page</p>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

popupClosed banner is effectively unreachable with current state gating

popupClosed is only set to true in the openOnboard().then(...) branch when the keyring is not initialized and geoRestricted is false. In that scenario, foundRestrictedAddress is still false and geoRestricted is false, so the restricted container (v-if="foundRestrictedAddress || geoRestricted") never renders, and the “Close this window / Continue to onboard…” block is never shown.

If the goal is to show this Safari fallback message when window.close() fails after onboarding starts, it probably needs to live in the main app branch (or some global overlay) rather than inside the restricted container, or the condition for the outer v-if needs to consider popupClosed as well.

I’d recommend revisiting the placement/conditions so the new banner actually appears in the intended Safari onboarding scenario.

Also applies to: 124-124, 281-283

🤖 Prompt for AI Agents
In packages/extension/src/ui/action/App.vue around lines 3 to 8 (also check
lines ~124 and 281-283), the "popupClosed" banner is unreachable because the
outer v-if only checks foundRestrictedAddress || geoRestricted, so when
popupClosed is set the restricted container may not render; update the rendering
logic to include popupClosed in the outer condition or move the banner into the
main app branch/global overlay so it can render independently (e.g., change the
outer v-if to (foundRestrictedAddress || geoRestricted || popupClosed) or
relocate the banner component to a top-level area that always mounts and
conditionally shows when popupClosed is true), and ensure any related
styles/structure still apply.

Copy link

@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

📜 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 bedab7d and 7e71891.

📒 Files selected for processing (2)
  • packages/extension/package.json (1 hunks)
  • packages/extension/src/ui/action/App.vue (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/extension/package.json
⏰ 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: build all
  • GitHub Check: test
  • GitHub Check: safari build
  • GitHub Check: test all

Comment on lines +287 to +291
if (__IS_SAFARI__) {
setInterval(() => {
isKeyRingLocked(); // keepalive safari action window
}, 1000 * 5);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory leak: Safari keepalive interval is never cleaned up.

The setInterval runs indefinitely without cleanup. Once the interval starts, it continues making background calls every 5 seconds even after the component unmounts, wasting resources and potentially impacting extension performance.

Store the interval ID and clear it in the onUnmounted lifecycle hook.

🔎 Proposed fix

Add an import for onUnmounted at the top (line 118):

-import { computed, onMounted, ref } from 'vue';
+import { computed, onMounted, onUnmounted, ref } from 'vue';

Then update the Safari keepalive logic to store and clean up the interval:

+let safariKeepaliveInterval: ReturnType<typeof setInterval> | null = null;
+
 onMounted(async () => {
   geoRestricted.value = await isGeoRestricted();
   const isInitialized = await kr.isInitialized();
   isWalletInitialized.value = isInitialized;
   if (geoRestricted.value) return;
   if (isInitialized) {
     const _isLocked = await isKeyRingLocked();
     if (__IS_SAFARI__) {
-      setInterval(() => {
+      safariKeepaliveInterval = setInterval(() => {
         isKeyRingLocked(); // keepalive safari action window
       }, 1000 * 5);
     }
     // ... rest of the code
   }
 });
+
+onUnmounted(() => {
+  if (safariKeepaliveInterval) {
+    clearInterval(safariKeepaliveInterval);
+  }
+});
📝 Committable suggestion

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

Suggested change
if (__IS_SAFARI__) {
setInterval(() => {
isKeyRingLocked(); // keepalive safari action window
}, 1000 * 5);
}
import { computed, onMounted, onUnmounted, ref } from 'vue';
// ... other code ...
let safariKeepaliveInterval: ReturnType<typeof setInterval> | null = null;
onMounted(async () => {
geoRestricted.value = await isGeoRestricted();
const isInitialized = await kr.isInitialized();
isWalletInitialized.value = isInitialized;
if (geoRestricted.value) return;
if (isInitialized) {
const _isLocked = await isKeyRingLocked();
if (__IS_SAFARI__) {
safariKeepaliveInterval = setInterval(() => {
isKeyRingLocked(); // keepalive safari action window
}, 1000 * 5);
}
// ... rest of the code
}
});
onUnmounted(() => {
if (safariKeepaliveInterval) {
clearInterval(safariKeepaliveInterval);
}
});
🤖 Prompt for AI Agents
In packages/extension/src/ui/action/App.vue around lines 287 to 291, the Safari
keepalive setInterval is started but never cleared, causing a memory leak;
update the component to import and use Vue's onUnmounted, store the interval ID
returned by setInterval in a variable, and call clearInterval(intervalId) inside
an onUnmounted hook so the timer is cleaned up when the component unmounts.

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.

5 participants