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}
+ />
+ );
+ })}
+
+
+
+
+
+
+