From a95756c3d2ddf272acfe5c623244657d70eb8432 Mon Sep 17 00:00:00 2001 From: Dominik Buszowiecki Date: Fri, 16 May 2025 10:43:14 -0400 Subject: [PATCH 1/2] changes to experiment selector --- .../views/insights/common/utils/useEap.tsx | 27 +++++-- .../pages/backend/backendOverviewPage.tsx | 19 ++++- .../pages/backend/eapExperimentButton.tsx | 81 +++++++++++++++++++ .../pages/backend/oldBackendOverviewPage.tsx | 11 ++- .../views/insights/pages/backend/settings.ts | 2 + .../views/insights/pages/domainViewHeader.tsx | 64 +-------------- .../app/views/insights/pages/useFilters.tsx | 10 ++- static/app/views/insights/settings.ts | 2 - 8 files changed, 137 insertions(+), 79 deletions(-) create mode 100644 static/app/views/insights/pages/backend/eapExperimentButton.tsx diff --git a/static/app/views/insights/common/utils/useEap.tsx b/static/app/views/insights/common/utils/useEap.tsx index 77bc18d2f2d494..d5ad72eaf8241c 100644 --- a/static/app/views/insights/common/utils/useEap.tsx +++ b/static/app/views/insights/common/utils/useEap.tsx @@ -1,19 +1,34 @@ +import {defined} from 'sentry/utils'; +import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState'; -import {EAP_LOCAL_STORAGE_KEY} from 'sentry/views/insights/settings'; +import { + BACKEND_LANDING_SUB_PATH, + USE_NEW_BACKEND_EXPERIENCE, +} from 'sentry/views/insights/pages/backend/settings'; +import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; export const useInsightsEap = (): boolean => { const organization = useOrganization(); - + const location = useLocation(); + const {isInOverviewPage, view} = useDomainViewFilters(); const hasEapFlag = organization.features.includes('insights-modules-use-eap'); - const [isEapEnabledLocalState] = useSyncedLocalStorageState( - EAP_LOCAL_STORAGE_KEY, - false + const [isNewBackendExperienceEnabled] = useSyncedLocalStorageState( + USE_NEW_BACKEND_EXPERIENCE, + true ); if (!hasEapFlag) { return false; } - return isEapEnabledLocalState; + if (defined(location.query.useEap)) { + return location.query.useEap === '1'; + } + + if (view === BACKEND_LANDING_SUB_PATH && isInOverviewPage) { + return isNewBackendExperienceEnabled; + } + + return true; }; diff --git a/static/app/views/insights/pages/backend/backendOverviewPage.tsx b/static/app/views/insights/pages/backend/backendOverviewPage.tsx index c43529b635f0b5..0bfc30b090b6aa 100644 --- a/static/app/views/insights/pages/backend/backendOverviewPage.tsx +++ b/static/app/views/insights/pages/backend/backendOverviewPage.tsx @@ -35,6 +35,7 @@ import { isAValidSort, type ValidSort, } from 'sentry/views/insights/pages/backend/backendTable'; +import {EAPExperimentButton} from 'sentry/views/insights/pages/backend/eapExperimentButton'; import {OldBackendOverviewPage} from 'sentry/views/insights/pages/backend/oldBackendOverviewPage'; import { BACKEND_LANDING_TITLE, @@ -50,7 +51,10 @@ import {useIsLaravelInsightsAvailable} from 'sentry/views/insights/pages/platfor import {JobsWidget} from 'sentry/views/insights/pages/platform/laravel/jobsWidget'; import {QueriesWidget} from 'sentry/views/insights/pages/platform/laravel/queriesWidget'; import {NextJsOverviewPage} from 'sentry/views/insights/pages/platform/nextjs'; -import {useIsNextJsInsightsEnabled} from 'sentry/views/insights/pages/platform/nextjs/features'; +import { + useIsNextJsInsightsAvailable, + useIsNextJsInsightsEnabled, +} from 'sentry/views/insights/pages/platform/nextjs/features'; import {NewNextJsExperienceButton} from 'sentry/views/insights/pages/platform/nextjs/newNextjsExperienceToggle'; import {DurationWidget} from 'sentry/views/insights/pages/platform/shared/durationWidget'; import {IssuesWidget} from 'sentry/views/insights/pages/platform/shared/issuesWidget'; @@ -65,14 +69,14 @@ function BackendOverviewPage() { useOverviewPageTrackPageload(); const isLaravelPageAvailable = useIsLaravelInsightsAvailable(); const [isNextJsPageEnabled] = useIsNextJsInsightsEnabled(); - const useEap = useInsightsEap(); + const isNewBackendExperienceEnabled = useInsightsEap(); if (isLaravelPageAvailable) { return ; } if (isNextJsPageEnabled) { return ; } - if (useEap) { + if (isNewBackendExperienceEnabled) { return ; } return ; @@ -86,6 +90,7 @@ function EAPBackendOverviewPage() { const navigate = useNavigate(); const {selection} = usePageFilters(); const cursor = decodeScalar(location.query?.[QueryParameterNames.PAGES_CURSOR]); + const isNextJsInsightsAvailable = useIsNextJsInsightsAvailable(); const {query: searchBarQuery} = useLocationQuery({ fields: { @@ -198,7 +203,13 @@ function EAPBackendOverviewPage() { > } + headerActions={ + isNextJsInsightsAvailable ? ( + + ) : ( + + ) + } /> diff --git a/static/app/views/insights/pages/backend/eapExperimentButton.tsx b/static/app/views/insights/pages/backend/eapExperimentButton.tsx new file mode 100644 index 00000000000000..d40f29c966bdb0 --- /dev/null +++ b/static/app/views/insights/pages/backend/eapExperimentButton.tsx @@ -0,0 +1,81 @@ +import type {Key} from 'react'; +import styled from '@emotion/styled'; + +import DropdownButton from 'sentry/components/dropdownButton'; +import {DropdownMenu} from 'sentry/components/dropdownMenu'; +import {IconLab} from 'sentry/icons'; +import {trackAnalytics} from 'sentry/utils/analytics'; +import {useLocalStorageState} from 'sentry/utils/useLocalStorageState'; +import {useLocation} from 'sentry/utils/useLocation'; +import {useNavigate} from 'sentry/utils/useNavigate'; +import useOrganization from 'sentry/utils/useOrganization'; +import {useInsightsEap} from 'sentry/views/insights/common/utils/useEap'; +import {USE_NEW_BACKEND_EXPERIENCE} from 'sentry/views/insights/pages/backend/settings'; +import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; + +export function EAPExperimentButton() { + const organization = useOrganization(); + const {view} = useDomainViewFilters(); + const location = useLocation(); + const isEapFlagEnabled = organization.features.includes('insights-modules-use-eap'); + const isNewBackendExperienceEnabled = useInsightsEap(); // useEap accounts for the local storage state + const [_, setNewBackendExperienceEnabled] = useLocalStorageState( + USE_NEW_BACKEND_EXPERIENCE, + true + ); + const navigate = useNavigate(); + + const toggleUseEap = () => { + const newState = !isNewBackendExperienceEnabled; + setNewBackendExperienceEnabled(newState); + trackAnalytics('insights.eap.toggle', { + organization, + isEapEnabled: newState, + page: 'overview', + view, + }); + navigate({ + pathname: location.pathname, + query: { + ...location.query, + useEap: newState ? '1' : '0', + }, + }); + }; + + const handleExperimentDropdownAction = (key: Key) => { + if (key === 'eap') { + toggleUseEap(); + } + }; + + if (!isEapFlagEnabled) { + return null; + } + + return ( + ( + + {/* Passing icon as child to avoid extra icon margin */} + + + )} + onAction={handleExperimentDropdownAction} + items={[ + { + key: 'eap', + label: isNewBackendExperienceEnabled ? 'Switch to Old UI' : 'Switch to New UI', + }, + ]} + position="bottom-end" + /> + ); +} + +const StyledDropdownButton = styled(DropdownButton)` + color: ${p => p.theme.button.primary.background}; + :hover { + color: ${p => p.theme.button.primary.background}; + } +`; diff --git a/static/app/views/insights/pages/backend/oldBackendOverviewPage.tsx b/static/app/views/insights/pages/backend/oldBackendOverviewPage.tsx index 7fe28a199a7f52..5a7554c22cf723 100644 --- a/static/app/views/insights/pages/backend/oldBackendOverviewPage.tsx +++ b/static/app/views/insights/pages/backend/oldBackendOverviewPage.tsx @@ -33,6 +33,7 @@ import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLay import {ToolRibbon} from 'sentry/views/insights/common/components/ribbon'; import {useOnboardingProject} from 'sentry/views/insights/common/queries/useOnboardingProject'; import {BackendHeader} from 'sentry/views/insights/pages/backend/backendPageHeader'; +import {EAPExperimentButton} from 'sentry/views/insights/pages/backend/eapExperimentButton'; import { BACKEND_LANDING_TITLE, OVERVIEW_PAGE_ALLOWED_OPS, @@ -45,6 +46,7 @@ import { MOBILE_PLATFORMS, OVERVIEW_PAGE_ALLOWED_OPS as BACKEND_OVERVIEW_PAGE_OPS, } from 'sentry/views/insights/pages/mobile/settings'; +import {useIsNextJsInsightsAvailable} from 'sentry/views/insights/pages/platform/nextjs/features'; import {NewNextJsExperienceButton} from 'sentry/views/insights/pages/platform/nextjs/newNextjsExperienceToggle'; import { generateBackendPerformanceEventView, @@ -98,6 +100,7 @@ export function OldBackendOverviewPage() { const {teams} = useUserTeams(); const mepSetting = useMEPSettingContext(); const {selection} = usePageFilters(); + const isNextJsInsightsAvailable = useIsNextJsInsightsAvailable(); const withStaticFilters = canUseMetricsData(organization); const eventView = generateBackendPerformanceEventView(location, withStaticFilters); @@ -232,7 +235,13 @@ export function OldBackendOverviewPage() { > } + headerActions={ + isNextJsInsightsAvailable ? ( + + ) : ( + + ) + } /> diff --git a/static/app/views/insights/pages/backend/settings.ts b/static/app/views/insights/pages/backend/settings.ts index fca2350e27ac2e..1bea5cfe12d470 100644 --- a/static/app/views/insights/pages/backend/settings.ts +++ b/static/app/views/insights/pages/backend/settings.ts @@ -25,3 +25,5 @@ export const DEFAULT_SORT: ValidSort = { }; export const BACKEND_PLATFORMS: PlatformKey[] = [...backend]; + +export const USE_NEW_BACKEND_EXPERIENCE = 'insights-backend-use-new-backend-experience'; diff --git a/static/app/views/insights/pages/domainViewHeader.tsx b/static/app/views/insights/pages/domainViewHeader.tsx index e3910e2850adac..305b8f63d48978 100644 --- a/static/app/views/insights/pages/domainViewHeader.tsx +++ b/static/app/views/insights/pages/domainViewHeader.tsx @@ -1,24 +1,18 @@ import {Fragment} from 'react'; import styled from '@emotion/styled'; -import type {Key} from '@react-types/shared'; import {Breadcrumbs, type Crumb} from 'sentry/components/breadcrumbs'; import {FeatureBadge} from 'sentry/components/core/badge/featureBadge'; import {ButtonBar} from 'sentry/components/core/button/buttonBar'; -import DropdownButton from 'sentry/components/dropdownButton'; -import {DropdownMenu} from 'sentry/components/dropdownMenu'; import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton'; import * as Layout from 'sentry/components/layouts/thirds'; import {extractSelectionParameters} from 'sentry/components/organizations/pageFilters/utils'; import {TabList} from 'sentry/components/tabs'; import type {TabListItemProps} from 'sentry/components/tabs/item'; -import {IconBusiness, IconLab} from 'sentry/icons'; +import {IconBusiness} from 'sentry/icons'; import {space} from 'sentry/styles/space'; -import {trackAnalytics} from 'sentry/utils/analytics'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; -import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState'; -import {useInsightsEap} from 'sentry/views/insights/common/utils/useEap'; import {useModuleTitles} from 'sentry/views/insights/common/utils/useModuleTitle'; import { type RoutableModuleNames, @@ -27,14 +21,12 @@ import { import {useIsLaravelInsightsAvailable} from 'sentry/views/insights/pages/platform/laravel/features'; import {useIsNextJsInsightsEnabled} from 'sentry/views/insights/pages/platform/nextjs/features'; import {OVERVIEW_PAGE_TITLE} from 'sentry/views/insights/pages/settings'; -import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; import { isModuleConsideredNew, isModuleEnabled, isModuleVisible, } from 'sentry/views/insights/pages/utils'; import FeedbackButtonTour from 'sentry/views/insights/sessions/components/tour/feedbackButtonTour'; -import {EAP_LOCAL_STORAGE_KEY} from 'sentry/views/insights/settings'; import {ModuleName} from 'sentry/views/insights/types'; export type Props = { @@ -68,24 +60,6 @@ export function DomainViewHeader({ const moduleURLBuilder = useModuleURLBuilder(); const isLaravelInsightsAvailable = useIsLaravelInsightsAvailable(); const [isNextJsInsightsEnabled] = useIsNextJsInsightsEnabled(); - const useEap = useInsightsEap(); - const {view} = useDomainViewFilters(); - const hasEapFlag = organization.features.includes('insights-modules-use-eap'); - const [_, setIsEapEnabledLocalState] = useSyncedLocalStorageState( - EAP_LOCAL_STORAGE_KEY, - false - ); - - const toggleUseEap = () => { - const newState = !useEap; - setIsEapEnabledLocalState(newState); - trackAnalytics('insights.eap.toggle', { - organization, - isEapEnabled: newState, - page: selectedModule || 'overview', - view, - }); - }; const crumbs: Crumb[] = [ { @@ -101,7 +75,6 @@ export function DomainViewHeader({ const globalQuery = { ...extractSelectionParameters(location?.query), - useEap: location.query?.useEap, }; const tabList: TabListItemProps[] = [ @@ -127,12 +100,6 @@ export function DomainViewHeader({ })), ]; - const handleExperimentDropdownAction = (key: Key) => { - if (key === 'eap') { - toggleUseEap(); - } - }; - return ( @@ -161,28 +128,6 @@ export function DomainViewHeader({ /> )} {additonalHeaderActions} - {hasEapFlag && ( - - ( - - {/* Passing icon as child to avoid extra icon margin */} - - - )} - onAction={handleExperimentDropdownAction} - items={[ - { - key: 'eap', - label: useEap - ? 'Switch to Metrics Dataset' - : 'Switch to EAP Dataset', - }, - ]} - position="bottom-end" - /> - - )} @@ -228,10 +173,3 @@ const TabContainer = styled('div')` text-align: left; gap: ${space(0.5)}; `; - -const StyledDropdownButton = styled(DropdownButton)` - color: ${p => p.theme.button.primary.background}; - :hover { - color: ${p => p.theme.button.primary.background}; - } -`; diff --git a/static/app/views/insights/pages/useFilters.tsx b/static/app/views/insights/pages/useFilters.tsx index 1f484d3439b619..e700c5df6a22df 100644 --- a/static/app/views/insights/pages/useFilters.tsx +++ b/static/app/views/insights/pages/useFilters.tsx @@ -20,15 +20,17 @@ const domainViews = [ export type DomainViewFilters = { isInDomainView?: boolean; + isInOverviewPage?: boolean; view?: DomainView; }; export const useDomainViewFilters = () => { const location = useLocation(); const pathSegments = location.pathname.split('/').filter(Boolean); - const indexOfPerformance = pathSegments.indexOf(DOMAIN_VIEW_BASE_URL); - const isInDomainView = indexOfPerformance !== -1; - const view = pathSegments[indexOfPerformance + 1] as DomainViewFilters['view']; + const indexOfInsights = pathSegments.indexOf(DOMAIN_VIEW_BASE_URL); + const isInDomainView = indexOfInsights !== -1; + const view = pathSegments[indexOfInsights + 1] as DomainViewFilters['view']; + const isInOverviewPage = pathSegments.length === indexOfInsights + 2; // TODO: remove this with `useInsightsEap`, only needed to seperately control eap on overview page if (!domainViews.includes(view || '')) { return {isInDomainView: false}; @@ -38,7 +40,9 @@ export const useDomainViewFilters = () => { return { view, isInDomainView, + isInOverviewPage, }; } + return {isInDomainView}; }; diff --git a/static/app/views/insights/settings.ts b/static/app/views/insights/settings.ts index cb6dbb45771e28..1d95e62f523aae 100644 --- a/static/app/views/insights/settings.ts +++ b/static/app/views/insights/settings.ts @@ -254,5 +254,3 @@ export const MODULES_CONSIDERED_NEW: Set = new Set([ ]); export const INGESTION_DELAY = 90; - -export const EAP_LOCAL_STORAGE_KEY = 'insights-modules-use-eap'; From 82b139cf28fc9bd4ff09fc1a5ad24d1e28449384 Mon Sep 17 00:00:00 2001 From: Dominik Buszowiecki Date: Fri, 16 May 2025 10:47:13 -0400 Subject: [PATCH 2/2] fixes --- static/app/views/insights/common/utils/useEap.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/app/views/insights/common/utils/useEap.tsx b/static/app/views/insights/common/utils/useEap.tsx index d5ad72eaf8241c..55323dde8c61c6 100644 --- a/static/app/views/insights/common/utils/useEap.tsx +++ b/static/app/views/insights/common/utils/useEap.tsx @@ -1,7 +1,7 @@ import {defined} from 'sentry/utils'; +import {useLocalStorageState} from 'sentry/utils/useLocalStorageState'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; -import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState'; import { BACKEND_LANDING_SUB_PATH, USE_NEW_BACKEND_EXPERIENCE, @@ -13,7 +13,7 @@ export const useInsightsEap = (): boolean => { const location = useLocation(); const {isInOverviewPage, view} = useDomainViewFilters(); const hasEapFlag = organization.features.includes('insights-modules-use-eap'); - const [isNewBackendExperienceEnabled] = useSyncedLocalStorageState( + const [isNewBackendExperienceEnabled] = useLocalStorageState( USE_NEW_BACKEND_EXPERIENCE, true );