Skip to content

fix: stack impersonation banner with customer alerts#3006

Merged
HarshMN2345 merged 2 commits intomainfrom
fix-impersonation-banner-stacking
Apr 27, 2026
Merged

fix: stack impersonation banner with customer alerts#3006
HarshMN2345 merged 2 commits intomainfrom
fix-impersonation-banner-stacking

Conversation

@HarshMN2345
Copy link
Copy Markdown
Member

@HarshMN2345 HarshMN2345 commented Apr 27, 2026

The header-alert system previously rendered only the highest-importance banner. Since the impersonation banner has importance 100, it always suppressed payment-failed and other billing alerts (importance 1), making them invisible to operators during impersonation sessions.

Now the impersonation banner renders in a separate fixed-position stack alongside the highest-priority customer alert, so operators can see exactly what the customer sees while impersonating.

What does this PR do?

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)

Related PRs and Issues

(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)

Have you read the Contributing Guidelines on issues?

(Write your answer here.)

The header-alert system previously rendered only the highest-importance
banner. Since the impersonation banner has importance 100, it always
suppressed payment-failed and other billing alerts (importance 1),
making them invisible to operators during impersonation sessions.

Now the impersonation banner renders in a separate fixed-position stack
alongside the highest-priority customer alert, so operators can see
exactly what the customer sees while impersonating.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR fixes the impersonation-banner-suppressing-billing-alerts problem by introducing an AlertStack wrapper that renders both banners in a single fixed-position container, with each HeaderAlert child delegating layout management to the parent stack via Svelte context. The headerAlert store's get() is refactored to use getStore (removing the spurious-subscriber anti-pattern) and gains getExcluding() to skip the importance-100 impersonation entry.

One cleanup gap remains: src/routes/+layout.svelte (outside the diff) still registers the impersonation banner in the store and reactively updates its show flag — code that is now dead because every consumer uses getExcluding('impersonation'). The getExcluding calls and the store registration are coupled; removing both together would simplify the design.

Confidence Score: 5/5

Safe to merge; the fix is correct and well-scoped, with only a minor cleanup gap remaining.

All findings are P2. The core logic — AlertStack layout management, isInStack context delegation, getExcluding exclusion — is sound. The only issue is leftover dead code in routes/+layout.svelte that is outside the diff and doesn't affect correctness.

src/routes/+layout.svelte (not in diff) — contains now-redundant headerAlert.add/updateShow calls for the impersonation entry.

Important Files Changed

Filename Overview
src/lib/layout/alertStack.svelte New fixed-position wrapper that manages layout height via ResizeObserver for stacked banners; duplicates setNavigationHeight logic from headerAlert.svelte, but cleanly delegates via isInStack context.
src/lib/layout/headerAlert.svelte Correctly opts out of self-managed layout/observers when isInStack context is true; fixes bannerSpacing.set(null) type mismatch.
src/lib/stores/headerAlert.ts Replaces update()-for-read anti-pattern with getStore(); adds getExcluding() to allow billing alerts to bypass the importance-100 impersonation entry; removes unused set() method.
src/lib/layout/shell.svelte Wraps ImpersonationBanner and activeHeaderAlert in AlertStack; derives hasAnyAlert to gate the stack; impersonation visibility is derived independently of the headerAlert store.
src/lib/stores/billing.ts Swaps headerAlert.get() for getExcluding('impersonation') so billing alerts are no longer shadowed by the importance-100 impersonation entry.
src/routes/(console)/+layout.svelte Replaces get() with getExcluding('impersonation') in checkForUsageLimits and afterUpdate; the registration of the impersonation entry in headerAlert (in routes/+layout.svelte) was not removed, leaving that code as dead weight.
src/lib/layout/index.ts Adds AlertStack to the layout barrel export.

Reviews (2): Last reviewed commit: "fix: address code review findings" | Re-trigger Greptile

Comment thread src/lib/stores/headerAlert.ts Outdated
Comment thread src/lib/layout/alertStack.svelte Outdated
Comment thread src/lib/layout/shell.svelte Outdated
- Use svelte/store get() for read-only access in headerAlert.get() and
  getExcluding() to avoid spurious subscriber notifications on every call
- Fix bannerSpacing.set(undefined) → set(null) to match the store's
  declared string | null type (alertStack and headerAlert)
- Remove redundant isImpersonating guard around ImpersonationBanner;
  the component self-manages visibility, eliminating the transient
  empty-stack layout edge case
@HarshMN2345 HarshMN2345 merged commit c1b0353 into main Apr 27, 2026
4 checks passed
@HarshMN2345 HarshMN2345 deleted the fix-impersonation-banner-stacking branch April 27, 2026 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants