Skip to content

fix(fe): Prompts for disabled email#2124

Merged
evanhutnik merged 7 commits intomainfrom
evan/connect-email-perms
Mar 23, 2026
Merged

fix(fe): Prompts for disabled email#2124
evanhutnik merged 7 commits intomainfrom
evan/connect-email-perms

Conversation

@evanhutnik
Copy link
Copy Markdown
Contributor

Summary

  • When a user has not granted email permissions during Google OAuth sign-in, show an informative banner in the Soup mail view and the email Compose view explaining they need to re-authenticate with email permissions enabled, with a Logout button
  • Update the Settings Account page to show Disabled with a (?) tooltip explaining the missing permissions, instead of the old Enable button that triggered a separate OAuth flow
  • Replace DeprecatedTextButton with the Button component from @ui/components/Button in the new banners

evanhutnik and others added 2 commits March 23, 2026 13:44
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@evanhutnik evanhutnik requested a review from a team as a code owner March 23, 2026 17:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

EmailAuth: failure toast changed from `toast.failure` to `toast.alert` and message updated to instruct selecting email permissions on sign‑in; control flow still navigates to success and `AlreadyInitialized` remains treated as success. Soup-view: added `isMailView` memo, `useEmailLinksQuery` plus `hasLinkError` logic, conditional rendering of <EmailPermissionsBanner /> and UI dimming (`pointer-events-none`, `opacity-10`) when errors exist. Account: removed `connect`, moved disabled-email tooltip to a QuestionCircle button with Popover placed top and updated copy about Google email permissions. Compose: replaced inline link-error UI with <EmailPermissionsBanner /> and removed connect/warning SVG. Added exported `EmailPermissionsBanner` component that displays a message and a Logout button.

Poem

🐰 I hopped through branches, banner bright,
A question circle blinked in light,
“Select email perms on sign‑in,” it sings,
A Logout button tied with strings,
I thump and skip — the code takes flight ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(fe): Prompts for disabled email' is directly related to the main change—adding prompts/banners to inform users about disabled email due to missing permissions.
Description check ✅ Passed The description accurately summarizes the three main changes: informative banners in mail and compose views, updated Settings Account page UI, and component replacement.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch evan/connect-email-perms

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 23, 2026

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/app/packages/app/component/next-soup/soup-view/soup-view.tsx`:
- Around line 288-307: The permissions banner UI duplicated in soup-view.tsx
(Show block using hasLinkError(), Caution, UIButton, logoutHandler) should be
extracted into a shared component (e.g., EmailPermissionsBanner) and reused from
both js/app/packages/app/component/next-soup/soup-view/soup-view.tsx and
js/app/packages/block-email/component/Compose.tsx; create EmailPermissionsBanner
that accepts props for the logout handler and any class/variant overrides, move
the markup (Caution icon, text, Logout UIButton) into that component, replace
the inline Show blocks in both files with <EmailPermissionsBanner
onLogout={logoutHandler} /> (or equivalent) while preserving the conditional
rendering via hasLinkError() in the caller or by accepting a visible prop.

In `@js/app/packages/app/component/settings/Account.tsx`:
- Around line 229-233: QuestionCircle is currently only mouse-interactive and
not keyboard-accessible; make it focusable and announce the tooltip by adding a
tabIndex={0} (or ensuring it's a focusable element), wire keyboard handlers
(onFocus -> setShowTooltip(true), onBlur -> setShowTooltip(false)), and also
handle activation keys (onKeyDown to open/close on Enter/Space) so keyboard
users can discover the tooltip; additionally add appropriate ARIA attributes
(e.g., aria-describedby pointing to the tooltip id and role="button" if it's
interactive) to the QuestionCircle component and ensure the tooltip content is
linked to that id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7070447a-6d3d-4594-885d-a9f686d79a4e

📥 Commits

Reviewing files that changed from the base of the PR and between 457ebcd and 6a9a8fe.

📒 Files selected for processing (4)
  • js/app/packages/app/component/EmailAuth.tsx
  • js/app/packages/app/component/next-soup/soup-view/soup-view.tsx
  • js/app/packages/app/component/settings/Account.tsx
  • js/app/packages/block-email/component/Compose.tsx

Copy link
Copy Markdown
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

Caution

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

⚠️ Outside diff range comments (1)
js/app/packages/block-email/component/Compose.tsx (1)

852-871: 🧹 Nitpick | 🔵 Trivial

Extract the email permissions banner into a shared component.

This banner markup and copy is duplicated with soup-view.tsx (lines 288-307). Consider extracting an EmailPermissionsBanner component that accepts onLogout as a prop to keep messaging and styling consistent across the application.

♻️ Suggested shared component

Create a new file js/app/packages/core/component/EmailPermissionsBanner.tsx:

import Caution from '@icon/regular/warning.svg';
import { Button } from '@ui/components/Button';

interface EmailPermissionsBannerProps {
  onLogout: () => void;
}

export function EmailPermissionsBanner(props: EmailPermissionsBannerProps) {
  return (
    <div class="w-full bg-alert-bg border-b border-t border-alert/20 text-alert-ink p-2">
      <div class="flex items-center justify-between gap-2">
        <Caution class="size-4" />
        <span class="text-sm">
          Email requires additional Google permissions. Select the
          permissions on sign-in to enable.
        </span>
        <span class="grow" />
        <Button
          variant="secondary"
          size="sm"
          class="px-2"
          onClick={props.onLogout}
        >
          Logout
        </Button>
      </div>
    </div>
  );
}

Then use it in both files:

-<Show when={hasLinkError()}>
-  <div class="w-full bg-alert-bg border-b border-t border-alert/20 text-alert-ink p-2">
-    <div class="flex items-center justify-between gap-2">
-      <Caution class="size-4" />
-      <span class="text-sm">
-        Email requires additional Google permissions. Select the
-        permissions on sign-in to enable.
-      </span>
-      <span class="grow" />
-      <Button
-        variant="secondary"
-        size="sm"
-        class="px-2"
-        onClick={logoutHandler}
-      >
-        Logout
-      </Button>
-    </div>
-  </div>
-</Show>
+<Show when={hasLinkError()}>
+  <EmailPermissionsBanner onLogout={logoutHandler} />
+</Show>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/app/packages/block-email/component/Compose.tsx` around lines 852 - 871,
Extract the duplicated banner markup into a shared React component named
EmailPermissionsBanner that accepts a prop onLogout: () => void; implement the
component to render the same markup, icon (Caution), Button and copy used
currently, then replace the duplicated blocks in Compose.tsx (the Show
when={hasLinkError()} block) and in soup-view.tsx with <EmailPermissionsBanner
onLogout={logoutHandler} /> (or appropriate handler), ensuring you import
EmailPermissionsBanner and the same Caution and Button symbols in the new
component so styling and behavior remain identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/app/packages/app/component/next-soup/soup-view/soup-view.tsx`:
- Around line 47-50: The file mixes a renamed import `UIButton` (from
`@ui/components/Button`) and a local `Button` (from `./filters-bar/button`),
causing inconsistent component naming; rename the local `Button` export/import
to a clearer name (e.g., `FilterButton`) at its source and update all usages in
this file (references to `Button` in `soup-view.tsx`) to `FilterButton` so you
can import the shared UI Button as `Button` (or vice versa) consistently across
the codebase; update the export in `./filters-bar/button` (component name and/or
default export) and adjust the import in `soup-view.tsx` accordingly to
eliminate the `UIButton` alias and standardize names.

---

Outside diff comments:
In `@js/app/packages/block-email/component/Compose.tsx`:
- Around line 852-871: Extract the duplicated banner markup into a shared React
component named EmailPermissionsBanner that accepts a prop onLogout: () => void;
implement the component to render the same markup, icon (Caution), Button and
copy used currently, then replace the duplicated blocks in Compose.tsx (the Show
when={hasLinkError()} block) and in soup-view.tsx with <EmailPermissionsBanner
onLogout={logoutHandler} /> (or appropriate handler), ensuring you import
EmailPermissionsBanner and the same Caution and Button symbols in the new
component so styling and behavior remain identical.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c0baae16-cb0b-429b-b97e-d5f688d44d0e

📥 Commits

Reviewing files that changed from the base of the PR and between 6a9a8fe and 81df579.

📒 Files selected for processing (2)
  • js/app/packages/app/component/next-soup/soup-view/soup-view.tsx
  • js/app/packages/block-email/component/Compose.tsx

Comment on lines +47 to +50
import { useEmailLinksQuery } from '@queries/email/link';
import { useLogout } from '@core/auth/logout';
import Caution from '@icon/regular/warning.svg';
import { Button as UIButton } from '@ui/components/Button';
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.

🧹 Nitpick | 🔵 Trivial

Consider using a consistent import alias for the Button component.

The file imports Button from @ui/components/Button as UIButton (line 50), while there's already a local Button import from ./filters-bar/button (line 103). This naming distinction is necessary to avoid conflicts, but consider whether the local Button component should be renamed (e.g., FilterButton) at its source to allow consistent naming across the codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/app/packages/app/component/next-soup/soup-view/soup-view.tsx` around lines
47 - 50, The file mixes a renamed import `UIButton` (from
`@ui/components/Button`) and a local `Button` (from `./filters-bar/button`),
causing inconsistent component naming; rename the local `Button` export/import
to a clearer name (e.g., `FilterButton`) at its source and update all usages in
this file (references to `Button` in `soup-view.tsx`) to `FilterButton` so you
can import the shared UI Button as `Button` (or vice versa) consistently across
the codebase; update the export in `./filters-bar/button` (component name and/or
default export) and adjust the import in `soup-view.tsx` accordingly to
eliminate the `UIButton` alias and standardize names.

evanhutnik and others added 2 commits March 23, 2026 14:10
…oltip

- Extract duplicated banner markup into shared EmailPermissionsBanner component
- Wrap QuestionCircle icon in a button with focus/blur handlers for keyboard accessibility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/app/packages/core/component/EmailPermissionsBanner.tsx`:
- Line 17: The onClick handler on the Button in EmailPermissionsBanner.tsx
invokes the async logout() without awaiting or handling errors; change the
onClick for the Button (the handler that currently calls logout()) to an async
function that awaits logout() and catches/reports errors (e.g., call
toast.failure or otherwise log/display the failure) so rejections are not
unhandled and the user gets feedback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 598ab2b5-ee36-4679-be96-1e83bed99a25

📥 Commits

Reviewing files that changed from the base of the PR and between 81df579 and 8e7c541.

📒 Files selected for processing (4)
  • js/app/packages/app/component/next-soup/soup-view/soup-view.tsx
  • js/app/packages/app/component/settings/Account.tsx
  • js/app/packages/block-email/component/Compose.tsx
  • js/app/packages/core/component/EmailPermissionsBanner.tsx

sign-in to enable.
</span>
<span class="grow" />
<Button variant="secondary" size="sm" class="px-2" onClick={() => logout()}>
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.

⚠️ Potential issue | 🟡 Minor

Handle or explicitly discard the async logout() promise.

logout() is async (returns a Promise). Invoking it without await or .catch() means any rejection is unhandled and the user receives no feedback if logout fails.

Consider adding minimal error handling:

Suggested fix
-        <Button variant="secondary" size="sm" class="px-2" onClick={() => logout()}>
+        <Button variant="secondary" size="sm" class="px-2" onClick={() => void logout()}>

Or, for user feedback on failure:

onClick={async () => {
  try {
    await logout();
  } catch {
    toast.failure('Logout failed');
  }
}}
📝 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
<Button variant="secondary" size="sm" class="px-2" onClick={() => logout()}>
<Button variant="secondary" size="sm" class="px-2" onClick={() => void logout()}>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/app/packages/core/component/EmailPermissionsBanner.tsx` at line 17, The
onClick handler on the Button in EmailPermissionsBanner.tsx invokes the async
logout() without awaiting or handling errors; change the onClick for the Button
(the handler that currently calls logout()) to an async function that awaits
logout() and catches/reports errors (e.g., call toast.failure or otherwise
log/display the failure) so rejections are not unhandled and the user gets
feedback.

Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/app/packages/app/component/next-soup/soup-view/soup-view.tsx`:
- Around line 198-206: The email links query runs unconditionally; change
useEmailLinksQuery to accept an options param with enabled: Accessor<boolean>
and wire that into the query's enabled flag (e.g., enabled: options?.enabled?.()
?? true) so it only runs when desired, then update the call in soup-view.tsx to
call useEmailLinksQuery({ enabled: isMailView }) instead of the unconditional
call; reference useEmailLinksQuery and isMailView when making the changes.

In `@js/app/packages/app/component/settings/Account.tsx`:
- Around line 209-210: The current element uses boolean interpolation in the
class string which can emit a literal "false" token; replace the dynamic class
construction with Solid's classList by keeping the static classes ("flex
items-center justify-between") on class and moving the conditional "mb-[18px]"
into classList keyed by the boolean expression using showEmailModal() (i.e.,
classList should apply "mb-[18px]" when !showEmailModal()). Locate the JSX
element that references showEmailModal() and update its class handling
accordingly so no boolean values are interpolated into the class string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ff996c81-8806-4948-9bb3-9e126cd11173

📥 Commits

Reviewing files that changed from the base of the PR and between 8e7c541 and 6eb321b.

📒 Files selected for processing (2)
  • js/app/packages/app/component/next-soup/soup-view/soup-view.tsx
  • js/app/packages/app/component/settings/Account.tsx

Comment on lines +198 to +206
const emailLinksQuery = useEmailLinksQuery();
const hasLinkError = createMemo(() => {
if (!isMailView()) return false;
if (emailLinksQuery.isPending) return false;
return (
emailLinksQuery.isError ||
(emailLinksQuery.data && emailLinksQuery.data.links.length === 0)
);
});
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if useEmailLinksQuery supports an enabled option
ast-grep --pattern $'export function useEmailLinksQuery($$$) {
  $$$
}'

# Also check the query definition for createQuery options
rg -n -A 20 'useEmailLinksQuery' --type ts -g '*/queries/**'

Repository: macro-inc/macro

Length of output: 813


🏁 Script executed:

#!/bin/bash
# Check TanStack Query documentation and verify if useQuery supports enabled option
# Also search for examples of enabled option usage in the codebase
rg -n "enabled:" --type ts | head -20

Repository: macro-inc/macro

Length of output: 2001


🏁 Script executed:

#!/bin/bash
# Look at the full soup-view.tsx file around the query usage
cat -n js/app/packages/app/component/next-soup/soup-view/soup-view.tsx | sed -n '190,210p'

Repository: macro-inc/macro

Length of output: 809


🏁 Script executed:

#!/bin/bash
# Check if there are other conditional query examples in the codebase
rg -n "enabled:\s*(true|false|\$)" --type ts | head -30

Repository: macro-inc/macro

Length of output: 2200


🏁 Script executed:

#!/bin/bash
# Get full definition of useEmailLinksQuery
cat -n js/app/packages/queries/email/link.ts

Repository: macro-inc/macro

Length of output: 954


🏁 Script executed:

#!/bin/bash
# Check how other query hooks accept options (e.g., useEntitiesForProperty)
cat -n js/app/packages/app/component/property-edit-modal/hooks/useEntitiesForProperty.ts | sed -n '75,95p'

Repository: macro-inc/macro

Length of output: 815


🏁 Script executed:

#!/bin/bash
# Check a query hook that accepts enabled parameter
cat -n js/app/packages/queries/preview/preview.ts | sed -n '1,50p'

Repository: macro-inc/macro

Length of output: 2278


Modify useEmailLinksQuery() to conditionally enable based on view context.

Currently, useEmailLinksQuery() runs unconditionally on every soup view render, but the data is only used when isMailView() is true. Following the pattern used by other query hooks in the codebase (e.g., useEntitiesForProperty, useItemPreview), update useEmailLinksQuery() to accept an enabled options parameter:

export function useEmailLinksQuery(options?: { enabled: Accessor<boolean> }) {
  return useQuery(() => ({
    queryKey: emailKeys.links.queryKey,
    queryFn: async () => throwOnErr(async () => await emailClient.getLinks()),
    staleTime: LINK_STALE_TIME,
    refetchOnWindowFocus: 'always',
    enabled: options?.enabled?.() ?? true,
  }));
}

Then pass enabled: isMailView when calling it in soup-view.tsx.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/app/packages/app/component/next-soup/soup-view/soup-view.tsx` around lines
198 - 206, The email links query runs unconditionally; change useEmailLinksQuery
to accept an options param with enabled: Accessor<boolean> and wire that into
the query's enabled flag (e.g., enabled: options?.enabled?.() ?? true) so it
only runs when desired, then update the call in soup-view.tsx to call
useEmailLinksQuery({ enabled: isMailView }) instead of the unconditional call;
reference useEmailLinksQuery and isMailView when making the changes.

Comment on lines +209 to +210
class={`flex items-center justify-between ${!showEmailModal() && 'mb-[18px]'}`}
>
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.

🧹 Nitpick | 🔵 Trivial

Avoid boolean interpolation in class strings.

Line 209 can produce a literal false class token. Prefer classList for conditional classes.

Proposed cleanup
-              <div
-                class={`flex items-center justify-between ${!showEmailModal() && 'mb-[18px]'}`}
-              >
+              <div
+                class="flex items-center justify-between"
+                classList={{ 'mb-[18px]': !showEmailModal() }}
+              >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/app/packages/app/component/settings/Account.tsx` around lines 209 - 210,
The current element uses boolean interpolation in the class string which can
emit a literal "false" token; replace the dynamic class construction with
Solid's classList by keeping the static classes ("flex items-center
justify-between") on class and moving the conditional "mb-[18px]" into classList
keyed by the boolean expression using showEmailModal() (i.e., classList should
apply "mb-[18px]" when !showEmailModal()). Locate the JSX element that
references showEmailModal() and update its class handling accordingly so no
boolean values are interpolated into the class string.

Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
js/app/packages/core/component/EmailPermissionsBanner.tsx (1)

21-21: ⚠️ Potential issue | 🟡 Minor

Handle logout() failures in the click handler.

At Line 21, logout() is async and currently called without rejection handling; a failure can become an unhandled promise rejection and gives no user feedback.

Suggested fix
-          onClick={() => logout()}
+          onClick={() => {
+            void logout().catch((error) => {
+              console.error('Logout failed', error);
+            });
+          }}
#!/bin/bash
set -euo pipefail

echo "== useLogout implementation (verify async callback) =="
nl -ba js/app/packages/core/auth/logout.ts | sed -n '1,80p'

echo
echo "== EmailPermissionsBanner onClick handler =="
nl -ba js/app/packages/core/component/EmailPermissionsBanner.tsx | sed -n '15,30p'

Expected result: useLogout wraps an async function, and this handler currently invokes logout() without local .catch(...) handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/app/packages/core/component/EmailPermissionsBanner.tsx` at line 21, The
onClick handler in EmailPermissionsBanner currently calls the async logout()
(from useLogout) without handling rejections; wrap the call so failures are
caught and surfaced (e.g., call logout().catch(...) or make the onClick an async
function and use try/catch) and ensure you surface an error to the user or UI
(toast/error state) when logout() fails; update the onClick in
EmailPermissionsBanner to call the safe wrapper and reference logout/useLogout
so the promise rejection is handled locally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@js/app/packages/core/component/EmailPermissionsBanner.tsx`:
- Line 21: The onClick handler in EmailPermissionsBanner currently calls the
async logout() (from useLogout) without handling rejections; wrap the call so
failures are caught and surfaced (e.g., call logout().catch(...) or make the
onClick an async function and use try/catch) and ensure you surface an error to
the user or UI (toast/error state) when logout() fails; update the onClick in
EmailPermissionsBanner to call the safe wrapper and reference logout/useLogout
so the promise rejection is handled locally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ce92f991-ed63-4f0e-8240-405554d965f9

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb321b and c48936f.

📒 Files selected for processing (1)
  • js/app/packages/core/component/EmailPermissionsBanner.tsx

@evanhutnik evanhutnik merged commit afb7143 into main Mar 23, 2026
24 checks passed
@evanhutnik evanhutnik deleted the evan/connect-email-perms branch March 23, 2026 18:38
@coderabbitai coderabbitai bot mentioned this pull request Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant