Skip to content

Commit aedfc9d

Browse files
feat(onboarding): Hide quick start guides that are not supported (#68381)
Some platforms don't support some features. As an example, if an org only has projects in platforms that don't support replay it doesn't make sense to show them replay onboarding tips. Product conversation [here](https://sentry.slack.com/archives/CTZCE4WBZ/p1712697918650289) that performance product aligns with this decision: if none of the projects on an org doesn't support a feature we shouldn't show those onboardings. Before in performance tab: ![Screenshot 2024-04-11 at 2 11 07 PM](https://github.com/getsentry/sentry/assets/132939361/27a323eb-9142-40d4-9ec2-6f0aae59a0bd) After, no side bar pops up: <img width="698" alt="Screenshot 2024-04-12 at 3 53 49 PM" src="https://github.com/getsentry/sentry/assets/132939361/b15bd378-8113-4290-9c54-281a0283fe21"> For general onboarding, before all tips showed: <img width="723" alt="Screenshot 2024-04-12 at 3 57 00 PM" src="https://github.com/getsentry/sentry/assets/132939361/52a1b307-4c9c-4d11-91b7-afa6fbe3fb33"> After, unrelated tips don't show: <img width="666" alt="Screenshot 2024-04-12 at 3 57 33 PM" src="https://github.com/getsentry/sentry/assets/132939361/6d7fdda9-dfac-448d-8581-44dcad977478">
1 parent 1a17eae commit aedfc9d

File tree

6 files changed

+179
-13
lines changed

6 files changed

+179
-13
lines changed

src/sentry/models/project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
"minidump",
111111
"native",
112112
"native-qt",
113-
"nintendo",
113+
"nintendo-switch",
114114
"node",
115115
"node-awslambda",
116116
"node-azurefunctions",
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import {ProjectFixture} from 'sentry-fixture/project';
2+
3+
import {filterSupportedTasks} from 'sentry/components/onboardingWizard/filterSupportedTasks';
4+
import {
5+
type OnboardingTask,
6+
OnboardingTaskKey,
7+
type PlatformKey,
8+
type Project,
9+
} from 'sentry/types';
10+
11+
describe('filterSupportedTasks', function () {
12+
const onboardingTasks: OnboardingTask[] = [
13+
{
14+
task: OnboardingTaskKey.FIRST_PROJECT,
15+
title: '',
16+
description: '',
17+
skippable: false,
18+
actionType: 'app',
19+
location: '',
20+
display: true,
21+
requisites: [],
22+
requisiteTasks: [],
23+
status: 'pending',
24+
},
25+
{
26+
task: OnboardingTaskKey.SESSION_REPLAY,
27+
title: '',
28+
description: '',
29+
skippable: true,
30+
requisites: [],
31+
actionType: 'app',
32+
location: '',
33+
display: true,
34+
requisiteTasks: [],
35+
status: 'pending',
36+
},
37+
{
38+
task: OnboardingTaskKey.USER_REPORTS,
39+
title: '',
40+
description: '',
41+
skippable: true,
42+
requisites: [],
43+
actionType: 'app',
44+
location: '',
45+
display: true,
46+
requisiteTasks: [],
47+
status: 'pending',
48+
},
49+
{
50+
task: OnboardingTaskKey.FIRST_TRANSACTION,
51+
title: '',
52+
description: '',
53+
skippable: true,
54+
requisites: [],
55+
actionType: 'app',
56+
location: '',
57+
display: true,
58+
requisiteTasks: [],
59+
status: 'pending',
60+
},
61+
];
62+
63+
it('filters out nothing if any supported platform', function () {
64+
const supportedProject = ProjectFixture({
65+
platform: 'javascript-react',
66+
}) as Project & {platform: PlatformKey};
67+
const unsupportedProject = ProjectFixture({
68+
platform: 'nintendo-switch',
69+
}) as Project & {platform: PlatformKey};
70+
const supportedTasks = filterSupportedTasks(
71+
[supportedProject, unsupportedProject],
72+
onboardingTasks
73+
);
74+
expect(supportedTasks.length).toBe(4);
75+
});
76+
77+
it('filters out for unsupported platform', function () {
78+
const project = ProjectFixture({
79+
platform: 'nintendo-switch',
80+
firstTransactionEvent: false,
81+
}) as Project & {platform: PlatformKey};
82+
const supportedTasks = filterSupportedTasks([project], onboardingTasks);
83+
expect(supportedTasks.length).toBe(1);
84+
});
85+
86+
it('filters out performance only if all projects are without support', function () {
87+
const project1 = ProjectFixture({
88+
platform: 'nintendo-switch',
89+
firstTransactionEvent: false,
90+
}) as Project & {platform: PlatformKey};
91+
const project2 = ProjectFixture({
92+
platform: 'elixir',
93+
firstTransactionEvent: false,
94+
}) as Project & {platform: PlatformKey};
95+
96+
const supportedTasks = filterSupportedTasks([project1, project2], onboardingTasks);
97+
expect(
98+
supportedTasks.filter(task =>
99+
[
100+
OnboardingTaskKey.FIRST_PROJECT,
101+
OnboardingTaskKey.SESSION_REPLAY,
102+
OnboardingTaskKey.USER_REPORTS,
103+
].includes(task.task)
104+
).length
105+
).toBe(3);
106+
});
107+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {
2+
feedbackOnboardingPlatforms,
3+
replayOnboardingPlatforms,
4+
withoutPerformanceSupport,
5+
} from 'sentry/data/platformCategories';
6+
import {type OnboardingTask, OnboardingTaskKey, type Project} from 'sentry/types';
7+
8+
const replayRelatedTasks = [OnboardingTaskKey.SESSION_REPLAY];
9+
const performanceRelatedTasks = [
10+
OnboardingTaskKey.FIRST_TRANSACTION,
11+
OnboardingTaskKey.PERFORMANCE_GUIDE,
12+
OnboardingTaskKey.METRIC_ALERT,
13+
];
14+
const feedbackRelatedTasks = [OnboardingTaskKey.USER_REPORTS];
15+
16+
export function filterSupportedTasks(
17+
projects: Project[] | undefined,
18+
allTasks: OnboardingTask[]
19+
): OnboardingTask[] {
20+
if (!projects) {
21+
return [];
22+
}
23+
// Remove tasks for features that are not supported
24+
const excludeList = allTasks.filter(
25+
task =>
26+
(!shouldShowReplayTasks(projects) && replayRelatedTasks.includes(task.task)) ||
27+
(!shouldShowPerformanceTasks(projects) &&
28+
performanceRelatedTasks.includes(task.task)) ||
29+
(!shouldShowFeedbackTasks(projects) && feedbackRelatedTasks.includes(task.task))
30+
);
31+
return allTasks.filter(task => !excludeList.includes(task));
32+
}
33+
34+
export function shouldShowPerformanceTasks(projects: Project[]): boolean {
35+
return !projects?.every(
36+
project => project.platform && withoutPerformanceSupport.has(project.platform)
37+
);
38+
}
39+
40+
export function shouldShowFeedbackTasks(projects: Project[]): boolean {
41+
return projects?.some(
42+
project => project.platform && feedbackOnboardingPlatforms.includes(project.platform)
43+
);
44+
}
45+
46+
export function shouldShowReplayTasks(projects: Project[]): boolean {
47+
return projects?.some(
48+
project => project.platform && replayOnboardingPlatforms.includes(project.platform)
49+
);
50+
}

static/app/components/onboardingWizard/taskConfig.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {openInviteMembersModal} from 'sentry/actionCreators/modal';
44
import {navigateTo} from 'sentry/actionCreators/navigation';
55
import type {Client} from 'sentry/api';
66
import type {OnboardingContextProps} from 'sentry/components/onboarding/onboardingContext';
7+
import {filterSupportedTasks} from 'sentry/components/onboardingWizard/filterSupportedTasks';
78
import {taskIsDone} from 'sentry/components/onboardingWizard/utils';
89
import {filterProjects} from 'sentry/components/performanceOnboarding/utils';
910
import {sourceMaps} from 'sentry/data/platformCategories';
@@ -445,11 +446,12 @@ export function getMergedTasks({organization, projects, onboardingContext}: Opti
445446
}) as OnboardingTask
446447
);
447448

449+
const supportedTasks = filterSupportedTasks(projects, allTasks);
448450
// Map incomplete requisiteTasks as full task objects
449-
return allTasks.map(task => ({
451+
return supportedTasks.map(task => ({
450452
...task,
451453
requisiteTasks: task.requisites
452-
.map(key => allTasks.find(task2 => task2.task === key)!)
454+
.map(key => supportedTasks.find(task2 => task2.task === key)!)
453455
.filter(reqTask => reqTask.status !== 'complete'),
454456
}));
455457
}

static/app/components/performanceOnboarding/sidebar.spec.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {SidebarPanelKey} from 'sentry/components/sidebar/types';
1111
import PageFiltersStore from 'sentry/stores/pageFiltersStore';
1212
import ProjectsStore from 'sentry/stores/projectsStore';
1313
import SidebarPanelStore from 'sentry/stores/sidebarPanelStore';
14+
import type {PlatformKey, Project} from 'sentry/types';
1415

1516
import {generateDocKeys} from './utils';
1617

@@ -59,6 +60,9 @@ describe('Sidebar > Performance Onboarding Checklist', function () {
5960
});
6061

6162
it('displays boost performance card', async function () {
63+
ProjectsStore.loadInitialData([
64+
ProjectFixture({platform: 'javascript-react', firstTransactionEvent: false}),
65+
]);
6266
renderSidebar({
6367
organization: {
6468
...organization,
@@ -82,7 +86,10 @@ describe('Sidebar > Performance Onboarding Checklist', function () {
8286
expect(screen.queryByText('Boost performance')).not.toBeInTheDocument();
8387
});
8488

85-
it('checklist feature disabled', async function () {
89+
it('checklist feature supported by platform but disabled', async function () {
90+
ProjectsStore.loadInitialData([
91+
ProjectFixture({platform: 'javascript-react', firstTransactionEvent: false}),
92+
]);
8693
renderSidebar({
8794
organization: {
8895
...organization,
@@ -177,15 +184,18 @@ describe('Sidebar > Performance Onboarding Checklist', function () {
177184
});
178185

179186
it('checklist feature enabled > navigate to performance page > project without performance support', async function () {
180-
ProjectsStore.loadInitialData([
181-
ProjectFixture({platform: 'elixir', firstTransactionEvent: false}),
182-
]);
187+
const project = ProjectFixture({
188+
platform: 'elixir',
189+
firstTransactionEvent: false,
190+
}) as Project & {platform: PlatformKey};
191+
ProjectsStore.loadInitialData([project]);
183192
renderSidebar({
184193
organization: {
185194
...organization,
186195
features: ['onboarding', 'performance-onboarding-checklist'],
187196
},
188197
});
198+
189199
window.open = jest.fn().mockImplementation(() => true);
190200

191201
const quickStart = await screen.findByText('Quick Start');
@@ -198,12 +208,7 @@ describe('Sidebar > Performance Onboarding Checklist', function () {
198208

199209
expect(screen.getByText('Capture your first error')).toBeInTheDocument();
200210
expect(screen.getByText('Level Up')).toBeInTheDocument();
201-
expect(screen.getByText('Boost performance')).toBeInTheDocument();
202-
const performanceCard = screen.getByTestId('setup_transactions');
203-
204-
await userEvent.click(performanceCard);
205-
expect(window.open).not.toHaveBeenCalled();
206-
expect(router.push).toHaveBeenCalledWith('/organizations/org-slug/performance/');
211+
expect(screen.queryByText('Boost performance')).not.toBeInTheDocument();
207212
});
208213

209214
it('displays checklist', async function () {

static/app/components/performanceOnboarding/sidebar.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {MenuItemProps} from 'sentry/components/dropdownMenu';
88
import {DropdownMenu} from 'sentry/components/dropdownMenu';
99
import IdBadge from 'sentry/components/idBadge';
1010
import LoadingIndicator from 'sentry/components/loadingIndicator';
11+
import {shouldShowPerformanceTasks} from 'sentry/components/onboardingWizard/filterSupportedTasks';
1112
import useOnboardingDocs from 'sentry/components/onboardingWizard/useOnboardingDocs';
1213
import OnboardingStep from 'sentry/components/sidebar/onboardingStep';
1314
import SidebarPanel from 'sentry/components/sidebar/sidebarPanel';
@@ -107,6 +108,7 @@ function PerformanceOnboardingSidebar(props: CommonSidebarProps) {
107108
!isActive ||
108109
!hasProjectAccess ||
109110
currentProject === undefined ||
111+
!shouldShowPerformanceTasks(projects) ||
110112
!projectsLoaded ||
111113
!projects ||
112114
projects.length <= 0 ||

0 commit comments

Comments
 (0)