fix(web): make the re-auth banner a centered popup, not a full-width top bar
Unrelated to #2108's diagnostics work, folded in at the maintainer's request rather than tracked separately. The sticky full-bleed bar cost the whole view a band of vertical space for what is a notification about one server, and it pushed down the monitoring sidebar that an OAuth failure now opens. Every corner is spoken for — the toast stack owns bottom-right, the right edge is the sidebar whose toolbar an anchored card covers, top-left is the Servers header — so it is centered instead, which is the one placement that reads as addressed to the window rather than attached to the wrong panel. Deliberately WITHOUT an overlay. This is a notification, not a decision that must be made now, and blocking the page would force a choice between reading the requests that explain the failure and keeping the affordance — dismissing is not free, since "Authorize again" also clears the stale OAuth state, which a plain reconnect does not do. Kept as the existing declarative component rather than routed through Mantine's `notifications`: that module is mocked in App.test.tsx, so switching would have broken the ten tests asserting on this banner's text and its action button, including the lost-authorization-state coverage. The message now stacks above a right-aligned action, which a ~420px card needs. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
f0720e4ed6
commit
d6250d6b05
2 changed files with 48 additions and 20 deletions
|
|
@ -422,20 +422,41 @@ const ToastLinkButton = Anchor.withProps({
|
|||
size: "sm",
|
||||
});
|
||||
|
||||
// Sticky re-auth banner bar. A `Paper` so every static style is a prop: `shadow`
|
||||
// emits `var(--mantine-shadow-sm)` (identical to the old CSS), and the stacking
|
||||
// The re-auth popup. A `Paper` so every static style is a prop; the stacking
|
||||
// order goes through `styles.root` since Mantine has no `z` prop.
|
||||
//
|
||||
// Floats top-right rather than spanning the top as a sticky full-bleed bar.
|
||||
// The bar cost the whole view a band of vertical space for what is a
|
||||
// notification about one server, and it sat directly above the monitoring
|
||||
// sidebar that an OAuth failure now opens (#2108) — the two things a user needs
|
||||
// at once here are this affordance and those requests, so it must not push them
|
||||
// around. `fixed`, not `sticky`, so scrolling the server list leaves it put.
|
||||
//
|
||||
// Centered, and deliberately WITHOUT an overlay. Every corner is spoken for —
|
||||
// the toast stack owns bottom-right (see `main.tsx`), the right edge is the
|
||||
// monitoring sidebar whose toolbar this would cover, and top-left is the
|
||||
// Servers header — so anchoring it anywhere hides something. Centering is the
|
||||
// one placement that reads as addressed to the whole window rather than
|
||||
// attached to the wrong panel.
|
||||
//
|
||||
// The missing overlay is the point, not an omission: this is a notification,
|
||||
// not a decision that must be made now. An OAuth failure opens the monitoring
|
||||
// sidebar (#2108), and blocking the page would force a choice between reading
|
||||
// those requests and keeping the affordance — dismissing is not free, since
|
||||
// "Authorize again" also clears the stale OAuth state, which a plain reconnect
|
||||
// does not do. So it floats above the page and leaves it usable.
|
||||
//
|
||||
// `transform` goes through `styles.root` for the same reason `zIndex` does:
|
||||
// Mantine exposes neither as a style prop.
|
||||
const ReAuthBannerBar = Paper.withProps({
|
||||
px: "md",
|
||||
pt: "xs",
|
||||
pos: "sticky",
|
||||
top: 60,
|
||||
pos: "fixed",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
w: 420,
|
||||
bg: "var(--mantine-color-body)",
|
||||
shadow: "sm",
|
||||
styles: { root: { zIndex: 200 } },
|
||||
// Paper's default `radius: "md"` would round this full-bleed sticky bar's
|
||||
// corners; the bar it replaced (a Box) had none.
|
||||
radius: 0,
|
||||
shadow: "xl",
|
||||
radius: "md",
|
||||
styles: { root: { transform: "translate(-50%, -50%)", zIndex: 200 } },
|
||||
});
|
||||
|
||||
// Body of the "response body dropped" warning toast: a one-line summary of what
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Alert, Button, Group, Text } from "@mantine/core";
|
||||
import { Alert, Button, Group, Stack, Text } from "@mantine/core";
|
||||
|
||||
export const DEFAULT_REAUTH_BANNER_TITLE = "Re-authentication required";
|
||||
export const DEFAULT_REAUTH_BANNER_ACTION_LABEL = "Re-authenticate";
|
||||
|
|
@ -24,11 +24,16 @@ const ReAuthAlert = Alert.withProps({
|
|||
closeButtonLabel: "Dismiss",
|
||||
});
|
||||
|
||||
const BannerRow = Group.withProps({
|
||||
justify: "space-between",
|
||||
align: "center",
|
||||
wrap: "nowrap",
|
||||
gap: "md",
|
||||
// Message above the action rather than beside it: this renders in a ~420px
|
||||
// popup, where a side-by-side row squeezes the message into a few words per
|
||||
// line while the button keeps its full width.
|
||||
const BannerBody = Stack.withProps({
|
||||
gap: "xs",
|
||||
});
|
||||
|
||||
const BannerActions = Group.withProps({
|
||||
justify: "flex-end",
|
||||
gap: "xs",
|
||||
});
|
||||
|
||||
const MessageText = Text.withProps({
|
||||
|
|
@ -50,10 +55,12 @@ export function ReAuthBanner({
|
|||
}: ReAuthBannerProps) {
|
||||
return (
|
||||
<ReAuthAlert title={title} onClose={onDismiss}>
|
||||
<BannerRow>
|
||||
<BannerBody>
|
||||
<MessageText>{message}</MessageText>
|
||||
<ReAuthButton onClick={onReauthenticate}>{actionLabel}</ReAuthButton>
|
||||
</BannerRow>
|
||||
<BannerActions>
|
||||
<ReAuthButton onClick={onReauthenticate}>{actionLabel}</ReAuthButton>
|
||||
</BannerActions>
|
||||
</BannerBody>
|
||||
</ReAuthAlert>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue