From a1a30e75632c56d5e3b5e33f7ed361e23b2f6664 Mon Sep 17 00:00:00 2001 From: SvenVw <37927107+SvenVw@users.noreply.github.com> Date: Tue, 3 Mar 2026 09:51:16 +0100 Subject: [PATCH 1/5] refactor: Suppress logging `BodyStreambuffer was aborted` to Sentry as this is caused by users navigating to another page while the page is still loading --- .changeset/wide-animals-tan.md | 5 +++++ fdm-app/app/entry.client.tsx | 1 + fdm-app/instrument.server.mjs | 1 + 3 files changed, 7 insertions(+) create mode 100644 .changeset/wide-animals-tan.md diff --git a/.changeset/wide-animals-tan.md b/.changeset/wide-animals-tan.md new file mode 100644 index 000000000..0a6cf85f1 --- /dev/null +++ b/.changeset/wide-animals-tan.md @@ -0,0 +1,5 @@ +--- +"@nmi-agro/fdm-app": patch +--- + +Suppress logging `BodyStreambuffer was aborted` to Sentry as this is caused by users navigating to another page while the page is still loading diff --git a/fdm-app/app/entry.client.tsx b/fdm-app/app/entry.client.tsx index 5974074eb..c96658955 100644 --- a/fdm-app/app/entry.client.tsx +++ b/fdm-app/app/entry.client.tsx @@ -18,6 +18,7 @@ if (clientConfig.analytics.sentry) { dsn: sentryConfig.dsn, release: import.meta.env.PUBLIC_APP_VERSION, environment: import.meta.env.NODE_ENV, + ignoreErrors: [/BodyStreamBuffer was aborted/], integrations: [ Sentry.reactRouterTracingIntegration(), Sentry.replayIntegration(), diff --git a/fdm-app/instrument.server.mjs b/fdm-app/instrument.server.mjs index 8febe8f08..715d468bf 100644 --- a/fdm-app/instrument.server.mjs +++ b/fdm-app/instrument.server.mjs @@ -18,6 +18,7 @@ Sentry.init({ integrations: [nodeProfilingIntegration()], tracesSampleRate: Number(process.env.VITE_SENTRY_TRACE_SAMPLE_RATE), profilesSampleRate: Number(process.env.VITE_SENTRY_PROFILE_SAMPLE_RATE), + ignoreErrors: [/BodyStreamBuffer was aborted/], environment: process.env.NODE_ENV ?? "development", release: process.env.npm_package_version, }) From fbbc0a31f31bcbabb6c311a163e18100df67fd33 Mon Sep 17 00:00:00 2001 From: SvenVw <37927107+SvenVw@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:37:49 +0100 Subject: [PATCH 2/5] feat: show loading state in the page load takes longer than 300ms and log it to Sentry --- .changeset/heavy-steaks-mix.md | 5 ++ .changeset/shy-times-fly.md | 5 ++ .../components/custom/navigation-progress.tsx | 77 +++++++++++++++++++ fdm-app/app/root.tsx | 2 + 4 files changed, 89 insertions(+) create mode 100644 .changeset/heavy-steaks-mix.md create mode 100644 .changeset/shy-times-fly.md create mode 100644 fdm-app/app/components/custom/navigation-progress.tsx diff --git a/.changeset/heavy-steaks-mix.md b/.changeset/heavy-steaks-mix.md new file mode 100644 index 000000000..42bfdff88 --- /dev/null +++ b/.changeset/heavy-steaks-mix.md @@ -0,0 +1,5 @@ +--- +"@nmi-agro/fdm-app": patch +--- + +In case the page load takes longer than 300ms log this to Sentry including the total duration to identify potential slow pages diff --git a/.changeset/shy-times-fly.md b/.changeset/shy-times-fly.md new file mode 100644 index 000000000..34a8129da --- /dev/null +++ b/.changeset/shy-times-fly.md @@ -0,0 +1,5 @@ +--- +"@nmi-agro/fdm-app": minor +--- + +In case a page load takes longer than 300ms show a loading spinner and blur the page to prevent double clicking the navigation action diff --git a/fdm-app/app/components/custom/navigation-progress.tsx b/fdm-app/app/components/custom/navigation-progress.tsx new file mode 100644 index 000000000..9e005abdb --- /dev/null +++ b/fdm-app/app/components/custom/navigation-progress.tsx @@ -0,0 +1,77 @@ +import * as Sentry from "@sentry/react-router" +import { AnimatePresence, motion } from "framer-motion" +import { Loader2 } from "lucide-react" +import { useEffect, useRef, useState } from "react" +import { useNavigation } from "react-router" +import { clientConfig } from "~/lib/config" + +/** + * Shows a blurred overlay with a loading card when navigation takes longer than 300ms. + * Fast navigations never trigger the indicator. + * Tracks show frequency and duration as Sentry metrics. + */ +export function NavigationProgress() { + const { state } = useNavigation() + const [show, setShow] = useState(false) + const startTimeRef = useRef(null) + + // Show after 300ms — emit a count metric when it appears + useEffect(() => { + if (state !== "idle") { + const timer = setTimeout(() => { + setShow(true) + startTimeRef.current = Date.now() + if (clientConfig.analytics.sentry) { + Sentry.metrics.count("navigation_progress.shown", 1) + } + }, 300) + return () => clearTimeout(timer) + } + + // Navigation finished — emit duration metric and hide + if (show && startTimeRef.current !== null) { + const duration = Date.now() - startTimeRef.current + if (clientConfig.analytics.sentry) { + Sentry.metrics.distribution( + "navigation_progress.duration_ms", + duration, + ) + } + startTimeRef.current = null + } + setShow(false) + }, [state, show]) + + return ( + + {show && ( + <> + {/* Backdrop blur */} + + + {/* Loading card */} + + +

+ Even geduld… +

+
+ + )} +
+ ) +} diff --git a/fdm-app/app/root.tsx b/fdm-app/app/root.tsx index b347e78dd..542303430 100644 --- a/fdm-app/app/root.tsx +++ b/fdm-app/app/root.tsx @@ -19,6 +19,7 @@ import { getToast } from "remix-toast" import { toast as notify } from "sonner" import { Banner } from "~/components/custom/banner" import { ErrorBlock } from "~/components/custom/error" +import { NavigationProgress } from "~/components/custom/navigation-progress" import { Toaster } from "~/components/ui/sonner" import { clientConfig } from "~/lib/config" import { useChangelogStore } from "~/store/changelog" @@ -152,6 +153,7 @@ export function Layout() { + From 0a4f078c5969818ecf190d72fb79355290aa7afe Mon Sep 17 00:00:00 2001 From: SvenVw <37927107+SvenVw@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:49:50 +0100 Subject: [PATCH 3/5] docs: typo --- .changeset/heavy-steaks-mix.md | 2 +- .changeset/shy-times-fly.md | 2 +- .changeset/wide-animals-tan.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/heavy-steaks-mix.md b/.changeset/heavy-steaks-mix.md index 42bfdff88..a9cc488d5 100644 --- a/.changeset/heavy-steaks-mix.md +++ b/.changeset/heavy-steaks-mix.md @@ -2,4 +2,4 @@ "@nmi-agro/fdm-app": patch --- -In case the page load takes longer than 300ms log this to Sentry including the total duration to identify potential slow pages +If a page load takes longer than 300 ms, log the total duration to Sentry to identify potentially slow pages. diff --git a/.changeset/shy-times-fly.md b/.changeset/shy-times-fly.md index 34a8129da..59d198464 100644 --- a/.changeset/shy-times-fly.md +++ b/.changeset/shy-times-fly.md @@ -2,4 +2,4 @@ "@nmi-agro/fdm-app": minor --- -In case a page load takes longer than 300ms show a loading spinner and blur the page to prevent double clicking the navigation action +If a page load takes longer than 300 ms, show a loading spinner and blur the page to prevent double-clicking the navigation action. diff --git a/.changeset/wide-animals-tan.md b/.changeset/wide-animals-tan.md index 0a6cf85f1..13eb1f347 100644 --- a/.changeset/wide-animals-tan.md +++ b/.changeset/wide-animals-tan.md @@ -2,4 +2,4 @@ "@nmi-agro/fdm-app": patch --- -Suppress logging `BodyStreambuffer was aborted` to Sentry as this is caused by users navigating to another page while the page is still loading +Suppress logging `BodyStreamBuffer was aborted` to Sentry, as this is caused by users navigating to another page while the current page is still loading. From c82cb631c51f93baa35566feb5778207aceb4ef9 Mon Sep 17 00:00:00 2001 From: SvenVw <37927107+SvenVw@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:51:37 +0100 Subject: [PATCH 4/5] fix: bias in duration metric and fix the extra timer --- .../app/components/custom/navigation-progress.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fdm-app/app/components/custom/navigation-progress.tsx b/fdm-app/app/components/custom/navigation-progress.tsx index 9e005abdb..fcaff65c6 100644 --- a/fdm-app/app/components/custom/navigation-progress.tsx +++ b/fdm-app/app/components/custom/navigation-progress.tsx @@ -18,9 +18,11 @@ export function NavigationProgress() { // Show after 300ms — emit a count metric when it appears useEffect(() => { if (state !== "idle") { + if (startTimeRef.current === null) { + startTimeRef.current = Date.now() + } const timer = setTimeout(() => { setShow(true) - startTimeRef.current = Date.now() if (clientConfig.analytics.sentry) { Sentry.metrics.count("navigation_progress.shown", 1) } @@ -37,10 +39,10 @@ export function NavigationProgress() { duration, ) } - startTimeRef.current = null } setShow(false) - }, [state, show]) + startTimeRef.current = null + }, [state]) return ( @@ -63,7 +65,11 @@ export function NavigationProgress() { initial={{ opacity: 0, scale: 0.92, y: "-48%" }} animate={{ opacity: 1, scale: 1, y: "-50%" }} exit={{ opacity: 0, scale: 0.96, y: "-48%" }} - transition={{ type: "spring", stiffness: 420, damping: 28 }} + transition={{ + type: "spring", + stiffness: 420, + damping: 28, + }} >

From b5899ba82acbbe98b4914a649ed8ad4b1da4258e Mon Sep 17 00:00:00 2001 From: SvenVw <37927107+SvenVw@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:52:20 +0100 Subject: [PATCH 5/5] fix: add missing dependency --- fdm-app/app/components/custom/navigation-progress.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdm-app/app/components/custom/navigation-progress.tsx b/fdm-app/app/components/custom/navigation-progress.tsx index fcaff65c6..a6a59e73a 100644 --- a/fdm-app/app/components/custom/navigation-progress.tsx +++ b/fdm-app/app/components/custom/navigation-progress.tsx @@ -42,7 +42,7 @@ export function NavigationProgress() { } setShow(false) startTimeRef.current = null - }, [state]) + }, [state, show]) return (