Stop Sentry on logout; fix E2E + Dockerfile for merged consolidation
- sentry.client.ts: add stopSentryClient() that awaits Sentry.close() so the SDK tears down when a user logs out. Hub methods become no-ops until initSentryClient() is called again on next login. - root.tsx: call stopSentryClient() from the user-effect when user === null. - Add sentry-config to journal + planner Dockerfiles (was missing after #237 introduced the new workspace package, breaking the Dockerfile package check). - Footer: replace inner <nav> with <div> — nested nav landmarks broke the journal "nav bar shows on all pages" e2e test (two navigation roles on the page). - e2e auth: tick the required ToS checkbox in the shared registerUser helper so passkey registration tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
adbf507101
commit
01f002cc46
6 changed files with 21 additions and 3 deletions
|
|
@ -11,6 +11,7 @@ COPY packages/ui/package.json packages/ui/
|
||||||
COPY packages/map/package.json packages/map/
|
COPY packages/map/package.json packages/map/
|
||||||
COPY packages/gpx/package.json packages/gpx/
|
COPY packages/gpx/package.json packages/gpx/
|
||||||
COPY packages/i18n/package.json packages/i18n/
|
COPY packages/i18n/package.json packages/i18n/
|
||||||
|
COPY packages/sentry-config/package.json packages/sentry-config/
|
||||||
COPY packages/api/package.json packages/api/
|
COPY packages/api/package.json packages/api/
|
||||||
COPY packages/map-core/package.json packages/map-core/
|
COPY packages/map-core/package.json packages/map-core/
|
||||||
COPY packages/db/package.json packages/db/
|
COPY packages/db/package.json packages/db/
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export function Footer() {
|
||||||
return (
|
return (
|
||||||
<footer className="mt-16 border-t border-gray-200 bg-white">
|
<footer className="mt-16 border-t border-gray-200 bg-white">
|
||||||
<div className="mx-auto max-w-7xl px-4 py-6 text-sm text-gray-500">
|
<div className="mx-auto max-w-7xl px-4 py-6 text-sm text-gray-500">
|
||||||
<nav className="flex flex-wrap items-center gap-x-6 gap-y-2">
|
<div className="flex flex-wrap items-center gap-x-6 gap-y-2">
|
||||||
<a href="/legal/imprint" className="hover:text-gray-700">
|
<a href="/legal/imprint" className="hover:text-gray-700">
|
||||||
{t("footer.imprint")}
|
{t("footer.imprint")}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -26,7 +26,7 @@ export function Footer() {
|
||||||
<span className="ml-auto text-xs text-gray-400">
|
<span className="ml-auto text-xs text-gray-400">
|
||||||
{t("footer.alpha")}
|
{t("footer.alpha")}
|
||||||
</span>
|
</span>
|
||||||
</nav>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,16 @@ export function initSentryClient() {
|
||||||
...browserSentryConfig("journal client", import.meta.env),
|
...browserSentryConfig("journal client", import.meta.env),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tear down the Sentry client on logout. After this call, `Sentry.captureException`
|
||||||
|
* and other hub methods become no-ops until `initSentryClient` is called again.
|
||||||
|
*
|
||||||
|
* Fire-and-forget: the close flush happens async, but we don't want to block the
|
||||||
|
* logout UI on it.
|
||||||
|
*/
|
||||||
|
export function stopSentryClient() {
|
||||||
|
if (!initialized) return;
|
||||||
|
initialized = false;
|
||||||
|
void Sentry.close();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { getSessionUser } from "~/lib/auth.server";
|
||||||
import { LocaleProvider } from "~/components/LocaleContext";
|
import { LocaleProvider } from "~/components/LocaleContext";
|
||||||
import { AlphaBanner } from "~/components/AlphaBanner";
|
import { AlphaBanner } from "~/components/AlphaBanner";
|
||||||
import { Footer } from "~/components/Footer";
|
import { Footer } from "~/components/Footer";
|
||||||
import { initSentryClient } from "~/lib/sentry.client";
|
import { initSentryClient, stopSentryClient } from "~/lib/sentry.client";
|
||||||
import stylesheet from "@trails-cool/ui/styles.css?url";
|
import stylesheet from "@trails-cool/ui/styles.css?url";
|
||||||
|
|
||||||
export const links: LinksFunction = () => [{ rel: "stylesheet", href: stylesheet }];
|
export const links: LinksFunction = () => [{ rel: "stylesheet", href: stylesheet }];
|
||||||
|
|
@ -123,6 +123,7 @@ export default function App({ loaderData }: Route.ComponentProps) {
|
||||||
Sentry.setUser({ id: user.id });
|
Sentry.setUser({ id: user.id });
|
||||||
} else {
|
} else {
|
||||||
Sentry.setUser(null);
|
Sentry.setUser(null);
|
||||||
|
stopSentryClient();
|
||||||
}
|
}
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ COPY packages/ui/package.json packages/ui/
|
||||||
COPY packages/map/package.json packages/map/
|
COPY packages/map/package.json packages/map/
|
||||||
COPY packages/gpx/package.json packages/gpx/
|
COPY packages/gpx/package.json packages/gpx/
|
||||||
COPY packages/i18n/package.json packages/i18n/
|
COPY packages/i18n/package.json packages/i18n/
|
||||||
|
COPY packages/sentry-config/package.json packages/sentry-config/
|
||||||
COPY packages/api/package.json packages/api/
|
COPY packages/api/package.json packages/api/
|
||||||
COPY packages/map-core/package.json packages/map-core/
|
COPY packages/map-core/package.json packages/map-core/
|
||||||
COPY packages/db/package.json packages/db/
|
COPY packages/db/package.json packages/db/
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ async function registerUser(page: Page, email: string, username: string) {
|
||||||
// Verify both fields retained values before submitting
|
// Verify both fields retained values before submitting
|
||||||
await expect(page.getByLabel("Email")).toHaveValue(email);
|
await expect(page.getByLabel("Email")).toHaveValue(email);
|
||||||
await expect(page.getByLabel("Username")).toHaveValue(username);
|
await expect(page.getByLabel("Username")).toHaveValue(username);
|
||||||
|
// Accept the Terms of Service (required)
|
||||||
|
await page.getByRole("checkbox").check();
|
||||||
await page.getByRole("button", { name: /Register with Passkey/ }).click();
|
await page.getByRole("button", { name: /Register with Passkey/ }).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue