From 7d72b1546c7df919c484345adabecaaf76843a22 Mon Sep 17 00:00:00 2001 From: TkDodo Date: Fri, 3 Oct 2025 22:09:55 +0200 Subject: [PATCH] fix(ui): always render tabs in insights/frontend to avoid flash during first navigation --- static/app/components/route.tsx | 1 + static/app/routes.tsx | 6 ++++++ static/app/utils/reactRouter6Compat/router.tsx | 2 +- .../resources/views/resourcesLandingPage.tsx | 2 -- .../webVitals/views/webVitalsLandingPage.tsx | 3 --- .../insights/http/views/httpLandingPage.tsx | 3 --- .../pages/frontend/frontendOverviewPage.tsx | 3 --- .../views/insights/pages/frontend/layout.tsx | 18 ++++++++++++++++++ .../views/insights/sessions/views/overview.tsx | 3 --- 9 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 static/app/views/insights/pages/frontend/layout.tsx diff --git a/static/app/components/route.tsx b/static/app/components/route.tsx index 9e0749875d3b54..b8bcee4b93ee7c 100644 --- a/static/app/components/route.tsx +++ b/static/app/components/route.tsx @@ -17,6 +17,7 @@ interface BaseRouteObject { * Including an `Outlet` component as a child element. */ deprecatedRouteProps?: never; + handle?: Record; /** * Is a index route */ diff --git a/static/app/routes.tsx b/static/app/routes.tsx index 43c5bc172e41bd..d3e901b88155b5 100644 --- a/static/app/routes.tsx +++ b/static/app/routes.tsx @@ -1870,6 +1870,7 @@ function buildRoutes(): RouteObject[] { children: [ { index: true, + handle: {module: ModuleName.HTTP}, component: make( () => import('sentry/views/insights/http/views/httpLandingPage') ), @@ -1887,6 +1888,7 @@ function buildRoutes(): RouteObject[] { children: [ { index: true, + handle: {module: ModuleName.VITAL}, component: make( () => import('sentry/views/insights/browser/webVitals/views/webVitalsLandingPage') @@ -1905,6 +1907,7 @@ function buildRoutes(): RouteObject[] { children: [ { index: true, + handle: {module: ModuleName.RESOURCE}, component: make( () => import('sentry/views/insights/browser/resources/views/resourcesLandingPage') @@ -1985,6 +1988,7 @@ function buildRoutes(): RouteObject[] { path: `${MODULE_BASE_URLS[ModuleName.SESSIONS]}/`, children: [ { + handle: {module: ModuleName.SESSIONS}, index: true, component: make(() => import('sentry/views/insights/sessions/views/overview')), }, @@ -2021,9 +2025,11 @@ function buildRoutes(): RouteObject[] { }, { path: `${FRONTEND_LANDING_SUB_PATH}/`, + component: make(() => import('sentry/views/insights/pages/frontend/layout')), children: [ { index: true, + handle: {module: undefined}, component: make( () => import('sentry/views/insights/pages/frontend/frontendOverviewPage') ), diff --git a/static/app/utils/reactRouter6Compat/router.tsx b/static/app/utils/reactRouter6Compat/router.tsx index 93441dd94adb0f..6ccb67f00f19f8 100644 --- a/static/app/utils/reactRouter6Compat/router.tsx +++ b/static/app/utils/reactRouter6Compat/router.tsx @@ -140,7 +140,7 @@ export function translateSentryRoute(tree: SentryRouteObject): RouteObject { // to shim the `useRoutes` hook to act like it did n react-router 3, // where the path was not resolved (looks like /issues/:issueId). Once we // remove usages of useRoutes we can remove this value from the handle. - const handle = {name, path}; + const handle = {...tree.handle, name, path}; if (tree.index) { return {index: true, element: getElement(component, deprecatedRouteProps), handle}; diff --git a/static/app/views/insights/browser/resources/views/resourcesLandingPage.tsx b/static/app/views/insights/browser/resources/views/resourcesLandingPage.tsx index adbdc32e033d9c..6b55470f6add53 100644 --- a/static/app/views/insights/browser/resources/views/resourcesLandingPage.tsx +++ b/static/app/views/insights/browser/resources/views/resourcesLandingPage.tsx @@ -20,7 +20,6 @@ import {ModulesOnboarding} from 'sentry/views/insights/common/components/modules import {ToolRibbon} from 'sentry/views/insights/common/components/ribbon'; import {DomainSelector} from 'sentry/views/insights/common/views/spans/selectors/domainSelector'; import SubregionSelector from 'sentry/views/insights/common/views/spans/selectors/subregionSelector'; -import {FrontendHeader} from 'sentry/views/insights/pages/frontend/frontendPageHeader'; import {ModuleName} from 'sentry/views/insights/types'; const {SPAN_OP, SPAN_DOMAIN} = BrowserStarfishFields; @@ -31,7 +30,6 @@ function ResourcesLandingPage() { return ( - diff --git a/static/app/views/insights/browser/webVitals/views/webVitalsLandingPage.tsx b/static/app/views/insights/browser/webVitals/views/webVitalsLandingPage.tsx index 765d0c26a8b78d..5fb90d74749cb8 100644 --- a/static/app/views/insights/browser/webVitals/views/webVitalsLandingPage.tsx +++ b/static/app/views/insights/browser/webVitals/views/webVitalsLandingPage.tsx @@ -23,7 +23,6 @@ import {ModulePageFilterBar} from 'sentry/views/insights/common/components/modul import {ModulePageProviders} from 'sentry/views/insights/common/components/modulePageProviders'; import {ModulesOnboarding} from 'sentry/views/insights/common/components/modulesOnboarding'; import {useWebVitalsDrawer} from 'sentry/views/insights/common/utils/useWebVitalsDrawer'; -import {FrontendHeader} from 'sentry/views/insights/pages/frontend/frontendPageHeader'; import {ModuleName, SpanFields, type SubregionCode} from 'sentry/views/insights/types'; const WEB_VITALS_COUNT = 5; @@ -68,8 +67,6 @@ function WebVitalsLandingPage() { return ( - - diff --git a/static/app/views/insights/http/views/httpLandingPage.tsx b/static/app/views/insights/http/views/httpLandingPage.tsx index 616f7633b3b3c6..a26e9e47914cfe 100644 --- a/static/app/views/insights/http/views/httpLandingPage.tsx +++ b/static/app/views/insights/http/views/httpLandingPage.tsx @@ -30,8 +30,6 @@ import { import {Referrer} from 'sentry/views/insights/http/referrers'; import {BackendHeader} from 'sentry/views/insights/pages/backend/backendPageHeader'; import {BACKEND_LANDING_SUB_PATH} from 'sentry/views/insights/pages/backend/settings'; -import {FrontendHeader} from 'sentry/views/insights/pages/frontend/frontendPageHeader'; -import {FRONTEND_LANDING_SUB_PATH} from 'sentry/views/insights/pages/frontend/settings'; import {MobileHeader} from 'sentry/views/insights/pages/mobile/mobilePageHeader'; import {MOBILE_LANDING_SUB_PATH} from 'sentry/views/insights/pages/mobile/settings'; import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; @@ -105,7 +103,6 @@ export function HTTPLandingPage() { return ( - {view === FRONTEND_LANDING_SUB_PATH && } {view === BACKEND_LANDING_SUB_PATH && } {view === MOBILE_LANDING_SUB_PATH && } diff --git a/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx b/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx index 16a41308bd9b8f..e31db64a1fe8b9 100644 --- a/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx +++ b/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx @@ -41,13 +41,11 @@ import { isAValidSort, type ValidSort, } from 'sentry/views/insights/pages/frontend/frontendOverviewTable'; -import {FrontendHeader} from 'sentry/views/insights/pages/frontend/frontendPageHeader'; import {useFrontendTableData} from 'sentry/views/insights/pages/frontend/queries/useFrontendTableData'; import type {PageSpanOps} from 'sentry/views/insights/pages/frontend/settings'; import { DEFAULT_SORT, DEFAULT_SPAN_OP_SELECTION, - FRONTEND_LANDING_TITLE, PAGE_SPAN_OPS, SPAN_OP_QUERY_PARAM, } from 'sentry/views/insights/pages/frontend/settings'; @@ -143,7 +141,6 @@ function FrontendOverviewPage() { organization={organization} renderDisabled={NoAccess} > - diff --git a/static/app/views/insights/pages/frontend/layout.tsx b/static/app/views/insights/pages/frontend/layout.tsx new file mode 100644 index 00000000000000..7eb6722fd94601 --- /dev/null +++ b/static/app/views/insights/pages/frontend/layout.tsx @@ -0,0 +1,18 @@ +import {Fragment} from 'react'; +import {Outlet, useMatches} from 'react-router-dom'; + +import {FrontendHeader} from 'sentry/views/insights/pages/frontend/frontendPageHeader'; +import {ModuleName} from 'sentry/views/insights/types'; + +function FrontendLayout() { + const handle = useMatches().at(-1)?.handle as {module?: ModuleName} | undefined; + + return ( + + {handle && 'module' in handle ? : null} + + + ); +} + +export default FrontendLayout; diff --git a/static/app/views/insights/sessions/views/overview.tsx b/static/app/views/insights/sessions/views/overview.tsx index 5bfd7dff645a10..07605d81fd70b9 100644 --- a/static/app/views/insights/sessions/views/overview.tsx +++ b/static/app/views/insights/sessions/views/overview.tsx @@ -11,7 +11,6 @@ import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLay import {ModulePageProviders} from 'sentry/views/insights/common/components/modulePageProviders'; import {ModulesOnboardingPanel} from 'sentry/views/insights/common/components/modulesOnboarding'; import {ToolRibbon} from 'sentry/views/insights/common/components/ribbon'; -import {FrontendHeader} from 'sentry/views/insights/pages/frontend/frontendPageHeader'; import {FRONTEND_LANDING_SUB_PATH} from 'sentry/views/insights/pages/frontend/settings'; import {MobileHeader} from 'sentry/views/insights/pages/mobile/mobilePageHeader'; import {MOBILE_LANDING_SUB_PATH} from 'sentry/views/insights/pages/mobile/settings'; @@ -65,8 +64,6 @@ function SessionsOverview() { function ViewSpecificHeader({view}: {view: DomainView | ''}) { switch (view) { - case FRONTEND_LANDING_SUB_PATH: - return ; case MOBILE_LANDING_SUB_PATH: return ; default: