From ee058ef06c83c8de2014d0b843025e5b9e2912d1 Mon Sep 17 00:00:00 2001 From: Dominik Buszowiecki <44422760+DominikB2014@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:01:35 -0500 Subject: [PATCH] fix(insights): customers not seeing empty state screen on developer plan (#81808) --- .../cache/views/cacheLandingPage.spec.tsx | 4 +- .../components/modulePageProviders.spec.tsx | 52 ++++++++++++ .../common/components/modulePageProviders.tsx | 18 +---- .../moduleUpsellHookWrapper.spec.tsx | 44 ++++++++++ .../components/moduleUpsellHookWrapper.tsx | 15 +++- .../views/databaseLandingPage.spec.tsx | 2 +- .../views/databaseSpanSummaryPage.spec.tsx | 2 +- .../http/views/httpDomainSummaryPage.spec.tsx | 2 +- .../screens/views/screensLandingPage.tsx | 81 ++++++++++--------- 9 files changed, 158 insertions(+), 62 deletions(-) create mode 100644 static/app/views/insights/common/components/modulePageProviders.spec.tsx create mode 100644 static/app/views/insights/common/components/moduleUpsellHookWrapper.spec.tsx diff --git a/static/app/views/insights/cache/views/cacheLandingPage.spec.tsx b/static/app/views/insights/cache/views/cacheLandingPage.spec.tsx index cdffcca3ba993e..ccfc9f03d685ff 100644 --- a/static/app/views/insights/cache/views/cacheLandingPage.spec.tsx +++ b/static/app/views/insights/cache/views/cacheLandingPage.spec.tsx @@ -30,7 +30,7 @@ const requestMocks = { }; describe('CacheLandingPage', function () { - const organization = OrganizationFixture(); + const organization = OrganizationFixture({features: ['insights-addon-modules']}); jest.mocked(usePageFilters).mockReturnValue({ isReady: true, @@ -313,7 +313,7 @@ describe('CacheLandingPage', function () { initiallyLoaded: false, }); - render(); + render(, {organization}); await waitFor(() => { expect( diff --git a/static/app/views/insights/common/components/modulePageProviders.spec.tsx b/static/app/views/insights/common/components/modulePageProviders.spec.tsx new file mode 100644 index 00000000000000..2360d492b8f47b --- /dev/null +++ b/static/app/views/insights/common/components/modulePageProviders.spec.tsx @@ -0,0 +1,52 @@ +import {OrganizationFixture} from 'sentry-fixture/organization'; + +import {render, screen} from 'sentry-test/reactTestingLibrary'; + +import usePageFilters from 'sentry/utils/usePageFilters'; +import {ModulePageProviders} from 'sentry/views/insights/common/components/modulePageProviders'; +import {useHasFirstSpan} from 'sentry/views/insights/common/queries/useHasFirstSpan'; +import {ModuleName} from 'sentry/views/insights/types'; + +jest.mock('sentry/utils/usePageFilters'); +jest.mock('sentry/views/insights/common/queries/useHasFirstSpan'); +jest.mock('sentry/views/insights/common/utils/useHasDataTrackAnalytics'); + +describe('ModulePageProviders', () => { + beforeEach(() => { + jest.mocked(usePageFilters).mockReturnValue({ + isReady: true, + desyncedFilters: new Set(), + pinnedFilters: new Set(), + shouldPersist: true, + selection: { + datetime: { + period: '10d', + start: null, + end: null, + utc: false, + }, + environments: [], + projects: [2], + }, + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('renders without module feature', async () => { + jest.mocked(useHasFirstSpan).mockReturnValue(true); + + render( + +
Module Content
+
, + { + organization: OrganizationFixture(), + } + ); + + await screen.findByText('Module Content'); + }); +}); diff --git a/static/app/views/insights/common/components/modulePageProviders.tsx b/static/app/views/insights/common/components/modulePageProviders.tsx index 962a9a50ed2233..dba62ed727406c 100644 --- a/static/app/views/insights/common/components/modulePageProviders.tsx +++ b/static/app/views/insights/common/components/modulePageProviders.tsx @@ -1,18 +1,12 @@ -import Feature from 'sentry/components/acl/feature'; import * as Layout from 'sentry/components/layouts/thirds'; import NoProjectMessage from 'sentry/components/noProjectMessage'; import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import type {InsightEventKey} from 'sentry/utils/analytics/insightAnalyticEvents'; import useOrganization from 'sentry/utils/useOrganization'; -import {NoAccess} from 'sentry/views/insights/common/components/noAccess'; import {useHasDataTrackAnalytics} from 'sentry/views/insights/common/utils/useHasDataTrackAnalytics'; import {useModuleTitles} from 'sentry/views/insights/common/utils/useModuleTitle'; -import { - INSIGHTS_TITLE, - MODULE_FEATURE_MAP, - QUERY_DATE_RANGE_LIMIT, -} from 'sentry/views/insights/settings'; +import {INSIGHTS_TITLE, QUERY_DATE_RANGE_LIMIT} from 'sentry/views/insights/settings'; import type {ModuleName} from 'sentry/views/insights/types'; type ModuleNameStrings = `${ModuleName}`; @@ -38,8 +32,6 @@ export function ModulePageProviders({ 'insights-query-date-range-limit' ); - const features = MODULE_FEATURE_MAP[moduleName]; - useHasDataTrackAnalytics(moduleName as ModuleName, analyticEventName); const moduleTitle = moduleTitles[moduleName]; @@ -54,13 +46,7 @@ export function ModulePageProviders({ > - - {children} - + {children} diff --git a/static/app/views/insights/common/components/moduleUpsellHookWrapper.spec.tsx b/static/app/views/insights/common/components/moduleUpsellHookWrapper.spec.tsx new file mode 100644 index 00000000000000..7adf9ee0cdb8a8 --- /dev/null +++ b/static/app/views/insights/common/components/moduleUpsellHookWrapper.spec.tsx @@ -0,0 +1,44 @@ +import {OrganizationFixture} from 'sentry-fixture/organization'; + +import {render, screen} from 'sentry-test/reactTestingLibrary'; + +import {ModuleBodyUpsellHook} from 'sentry/views/insights/common/components/moduleUpsellHookWrapper'; +import {ModuleName} from 'sentry/views/insights/types'; + +jest.mock('sentry/utils/usePageFilters'); + +describe('ModulePageProviders', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('renders no feature if module is not enabled', async () => { + render( + +
Module Content
+
, + { + organization: OrganizationFixture({ + features: ['insights-entry-points'], + }), + } + ); + + await screen.findByText(`You don't have access to this feature`); + }); + + it('renders module content if module is enabled', async () => { + render( + +
Module Content
+
, + { + organization: OrganizationFixture({ + features: ['insights-initial-modules'], + }), + } + ); + + await screen.findByText(`Module Content`); + }); +}); diff --git a/static/app/views/insights/common/components/moduleUpsellHookWrapper.tsx b/static/app/views/insights/common/components/moduleUpsellHookWrapper.tsx index a45010e17eb48a..a79c88e53a1286 100644 --- a/static/app/views/insights/common/components/moduleUpsellHookWrapper.tsx +++ b/static/app/views/insights/common/components/moduleUpsellHookWrapper.tsx @@ -1,7 +1,10 @@ +import Feature from 'sentry/components/acl/feature'; import HookOrDefault from 'sentry/components/hookOrDefault'; +import {NoAccess} from 'sentry/components/noAccess'; +import useOrganization from 'sentry/utils/useOrganization'; import type {TitleableModuleNames} from 'sentry/views/insights/common/components/modulePageProviders'; +import {MODULE_FEATURE_MAP} from 'sentry/views/insights/settings'; -// TODO - remove, This is only necessary for domain views, where we don't want to show the full upsell page. export function ModuleBodyUpsellHook({ moduleName, children, @@ -9,9 +12,17 @@ export function ModuleBodyUpsellHook({ children: React.ReactNode; moduleName: TitleableModuleNames; }) { + const organization = useOrganization(); + return ( - {children} + + {children} + ); } diff --git a/static/app/views/insights/database/views/databaseLandingPage.spec.tsx b/static/app/views/insights/database/views/databaseLandingPage.spec.tsx index 94e1293c8bfbac..f4df7902a2e261 100644 --- a/static/app/views/insights/database/views/databaseLandingPage.spec.tsx +++ b/static/app/views/insights/database/views/databaseLandingPage.spec.tsx @@ -15,7 +15,7 @@ jest.mock('sentry/utils/useProjects'); jest.mock('sentry/views/insights/common/queries/useOnboardingProject'); describe('DatabaseLandingPage', function () { - const organization = OrganizationFixture(); + const organization = OrganizationFixture({features: ['insights-initial-modules']}); let spanListRequestMock: jest.Mock; let spanChartsRequestMock: jest.Mock; diff --git a/static/app/views/insights/database/views/databaseSpanSummaryPage.spec.tsx b/static/app/views/insights/database/views/databaseSpanSummaryPage.spec.tsx index 91af5dbf084ec6..ccb27e1a91a88d 100644 --- a/static/app/views/insights/database/views/databaseSpanSummaryPage.spec.tsx +++ b/static/app/views/insights/database/views/databaseSpanSummaryPage.spec.tsx @@ -13,7 +13,7 @@ jest.mock('sentry/utils/usePageFilters'); describe('DatabaseSpanSummaryPage', function () { const organization = OrganizationFixture({ - features: ['insights-related-issues-table'], + features: ['insights-related-issues-table', 'insights-initial-modules'], }); const group = GroupFixture(); diff --git a/static/app/views/insights/http/views/httpDomainSummaryPage.spec.tsx b/static/app/views/insights/http/views/httpDomainSummaryPage.spec.tsx index 6c59c736ddf63e..aa04150addb9cf 100644 --- a/static/app/views/insights/http/views/httpDomainSummaryPage.spec.tsx +++ b/static/app/views/insights/http/views/httpDomainSummaryPage.spec.tsx @@ -15,7 +15,7 @@ jest.mock('sentry/utils/useLocation'); jest.mock('sentry/utils/usePageFilters'); describe('HTTPSummaryPage', function () { - const organization = OrganizationFixture(); + const organization = OrganizationFixture({features: ['insights-initial-modules']}); let domainChartsRequestMock, domainTransactionsListRequestMock; diff --git a/static/app/views/insights/mobile/screens/views/screensLandingPage.tsx b/static/app/views/insights/mobile/screens/views/screensLandingPage.tsx index c26926d8850988..f8aecceb75ff55 100644 --- a/static/app/views/insights/mobile/screens/views/screensLandingPage.tsx +++ b/static/app/views/insights/mobile/screens/views/screensLandingPage.tsx @@ -23,6 +23,7 @@ import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import {ModulePageProviders} from 'sentry/views/insights/common/components/modulePageProviders'; +import {ModuleBodyUpsellHook} from 'sentry/views/insights/common/components/moduleUpsellHookWrapper'; import useCrossPlatformProject from 'sentry/views/insights/mobile/common/queries/useCrossPlatformProject'; import {PlatformSelector} from 'sentry/views/insights/mobile/screenload/components/platformSelector'; import {SETUP_CONTENT as TTFD_SETUP} from 'sentry/views/insights/mobile/screenload/data/setupContent'; @@ -299,47 +300,49 @@ export function ScreensLandingPage() { headerActions={isProjectCrossPlatform && } module={moduleName} /> - - - - - - - - - - - + + + - - {vitalItems.map(item => { - const metricValue = metricValueFor(item); - const status = - (metricValue && item.getStatus(metricValue)) ?? STATUS_UNKNOWN; - - return ( - { - setState({ - vital: item, - status: status, - }); - }} - key={item.field} - title={item.title} - description={item.description} - statusLabel={status.description} - status={status.score} - formattedValue={status.formattedValue} - /> - ); - })} - - + + + + + - - - + + + + + {vitalItems.map(item => { + const metricValue = metricValueFor(item); + const status = + (metricValue && item.getStatus(metricValue)) ?? STATUS_UNKNOWN; + + return ( + { + setState({ + vital: item, + status: status, + }); + }} + key={item.field} + title={item.title} + description={item.description} + statusLabel={status.description} + status={status.score} + formattedValue={status.formattedValue} + /> + ); + })} + + + + + + +