Skip to content

Commit 6f32a56

Browse files
ref(onboarding): Remove multi-select platform for new orgs - (#43779)
1 parent a00103b commit 6f32a56

File tree

11 files changed

+226
-227
lines changed

11 files changed

+226
-227
lines changed

static/app/routes.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ function buildRoutes() {
247247
<IndexRedirect to="welcome/" />
248248
<Route
249249
path=":step/"
250-
component={make(() => import('sentry/views/onboarding/onboarding'))}
250+
component={make(() => import('sentry/views/onboarding'))}
251251
/>
252252
</Route>
253253
) : null}
@@ -257,10 +257,7 @@ function buildRoutes() {
257257
key="org-onboarding"
258258
>
259259
<IndexRedirect to="welcome/" />
260-
<Route
261-
path=":step/"
262-
component={make(() => import('sentry/views/onboarding/onboarding'))}
263-
/>
260+
<Route path=":step/" component={make(() => import('sentry/views/onboarding'))} />
264261
</Route>
265262
</Fragment>
266263
);

static/app/views/onboarding/components/createProjectsFooter.tsx

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import {
1111
} from 'sentry/actionCreators/indicator';
1212
import {createProject} from 'sentry/actionCreators/projects';
1313
import {Button} from 'sentry/components/button';
14+
import TextOverflow from 'sentry/components/textOverflow';
1415
import {PlatformKey} from 'sentry/data/platformCategories';
15-
import {t, tn} from 'sentry/locale';
16+
import {t, tct, tn} from 'sentry/locale';
1617
import ProjectsStore from 'sentry/stores/projectsStore';
1718
import space from 'sentry/styles/space';
1819
import {Organization} from 'sentry/types';
1920
import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
21+
import getPlatformName from 'sentry/utils/getPlatformName';
2022
import testableTransition from 'sentry/utils/testableTransition';
2123
import useApi from 'sentry/utils/useApi';
2224
import useTeams from 'sentry/utils/useTeams';
@@ -41,6 +43,10 @@ export default function CreateProjectsFooter({
4143
genSkipOnboardingLink,
4244
clearPlatforms,
4345
}: Props) {
46+
const singleSelectPlatform = !!organization?.features.includes(
47+
'onboarding-remove-multiselect-platform'
48+
);
49+
4450
const api = useApi();
4551
const {teams} = useTeams();
4652
const [persistedOnboardingState, setPersistedOnboardingState] =
@@ -51,8 +57,11 @@ export default function CreateProjectsFooter({
5157
// Do nothing if client state is not loaded yet.
5258
return;
5359
}
60+
5461
try {
55-
addLoadingMessage(t('Creating projects'));
62+
addLoadingMessage(
63+
singleSelectPlatform ? t('Creating project') : t('Creating projects')
64+
);
5665

5766
const responses = await Promise.all(
5867
platforms
@@ -82,7 +91,11 @@ export default function CreateProjectsFooter({
8291
clearIndicators();
8392
setTimeout(onComplete);
8493
} catch (err) {
85-
addErrorMessage(t('Failed to create projects'));
94+
addErrorMessage(
95+
singleSelectPlatform
96+
? t('Failed to create project')
97+
: t('Failed to create projects')
98+
);
8699
Sentry.captureException(err);
87100
}
88101
};
@@ -97,15 +110,33 @@ export default function CreateProjectsFooter({
97110
{genSkipOnboardingLink()}
98111
<SelectionWrapper>
99112
{platforms.length ? (
100-
<Fragment>
101-
<div>{platforms.map(renderPlatform)}</div>
102-
<PlatformSelected>
103-
{tn('%s platform selected', '%s platforms selected', platforms.length)}
104-
<ClearButton priority="link" onClick={clearPlatforms} size="zero">
105-
{t('Clear')}
106-
</ClearButton>
107-
</PlatformSelected>
108-
</Fragment>
113+
singleSelectPlatform ? (
114+
<Fragment>
115+
<div>{platforms.map(renderPlatform)}</div>
116+
<PlatformSelected>
117+
{tct('[platform] selected', {
118+
platform: (
119+
<PlatformName>
120+
{getPlatformName(platforms[0]) ?? 'other'}
121+
</PlatformName>
122+
),
123+
})}
124+
<ClearButton priority="link" onClick={clearPlatforms} size="zero">
125+
{t('Clear')}
126+
</ClearButton>
127+
</PlatformSelected>
128+
</Fragment>
129+
) : (
130+
<Fragment>
131+
<div>{platforms.map(renderPlatform)}</div>
132+
<PlatformsSelected>
133+
{tn('%s platform selected', '%s platforms selected', platforms.length)}
134+
<ClearButton priority="link" onClick={clearPlatforms} size="zero">
135+
{t('Clear')}
136+
</ClearButton>
137+
</PlatformsSelected>
138+
</Fragment>
139+
)
109140
) : null}
110141
</SelectionWrapper>
111142
<ButtonWrapper>
@@ -144,6 +175,7 @@ const ButtonWrapper = styled(motion.div)`
144175
height: 100%;
145176
align-items: center;
146177
margin-right: ${space(4)};
178+
margin-left: ${space(4)};
147179
`;
148180

149181
ButtonWrapper.defaultProps = {
@@ -156,10 +188,22 @@ const SelectedPlatformIcon = styled(PlatformIcon)`
156188
margin-right: ${space(1)};
157189
`;
158190

191+
const PlatformsSelected = styled('div')`
192+
margin-top: ${space(1)};
193+
`;
194+
159195
const PlatformSelected = styled('div')`
160196
margin-top: ${space(1)};
197+
display: grid;
198+
grid-template-columns: 1fr max-content max-content;
199+
align-items: center;
161200
`;
162201

163202
const ClearButton = styled(Button)`
164203
margin-left: ${space(2)};
204+
padding: 0;
205+
`;
206+
207+
const PlatformName = styled(TextOverflow)`
208+
margin-right: ${space(0.5)};
165209
`;

static/app/views/onboarding/components/heartbeatFooter/index.tsx

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {useLegacyStore} from 'sentry/stores/useLegacyStore';
1717
import pulsingIndicatorStyles from 'sentry/styles/pulsingIndicator';
1818
import space from 'sentry/styles/space';
1919
import {Project} from 'sentry/types';
20-
import getPlatformName from 'sentry/utils/getPlatformName';
2120
import useOrganization from 'sentry/utils/useOrganization';
2221
import useProjects from 'sentry/utils/useProjects';
2322

@@ -48,25 +47,15 @@ async function openChangeRouteModal(
4847
type Props = Pick<RouteComponentProps<{}, {}>, 'router' | 'route' | 'location'> & {
4948
projectSlug: Project['slug'];
5049
newOrg?: boolean;
51-
nextProjectSlug?: Project['slug'];
52-
onSetupNextProject?: () => void;
5350
};
5451

55-
export function HeartbeatFooter({
56-
projectSlug,
57-
router,
58-
route,
59-
location,
60-
newOrg,
61-
nextProjectSlug,
62-
onSetupNextProject,
63-
}: Props) {
52+
export function HeartbeatFooter({projectSlug, router, route, location, newOrg}: Props) {
6453
const organization = useOrganization();
6554
const preferences = useLegacyStore(PreferencesStore);
6655

6756
const {initiallyLoaded, fetchError, fetching, projects} = useProjects({
6857
orgId: organization.id,
69-
slugs: nextProjectSlug ? [projectSlug, nextProjectSlug] : [projectSlug],
58+
slugs: [projectSlug],
7059
});
7160

7261
const projectsLoading = !initiallyLoaded && fetching;
@@ -76,11 +65,6 @@ export function HeartbeatFooter({
7665
? projects.find(proj => proj.slug === projectSlug)
7766
: undefined;
7867

79-
const nextProject =
80-
!projectsLoading && !fetchError && projects.length === 2
81-
? projects.find(proj => proj.slug === nextProjectSlug)
82-
: undefined;
83-
8468
const {loading, firstErrorReceived, serverConnected} = useHeartbeat(
8569
project?.slug,
8670
project?.id
@@ -95,6 +79,7 @@ export function HeartbeatFooter({
9579
nextLocation?.pathname !== `/onboarding/${organization.slug}/setup-docs/`;
9680

9781
const isSetupDocsForNewOrgBackButton = `/onboarding/${organization.slug}/select-platform/`;
82+
const isWelcomeForNewOrgBackButton = `/onboarding/${organization.slug}/welcome/`;
9883

9984
const isGettingStartedForExistingOrg =
10085
location.pathname === `/${orgId}/${projectId}/getting-started/${platform}/` ||
@@ -109,7 +94,10 @@ export function HeartbeatFooter({
10994
// Next Location is always available when user clicks on a item with a new route
11095
if (nextLocation) {
11196
// Back button in the onboarding of new orgs
112-
if (nextLocation.pathname === isSetupDocsForNewOrgBackButton) {
97+
if (
98+
nextLocation.pathname === isSetupDocsForNewOrgBackButton ||
99+
nextLocation.pathname === isWelcomeForNewOrgBackButton
100+
) {
113101
return true;
114102
}
115103

@@ -171,7 +159,7 @@ export function HeartbeatFooter({
171159
<Fragment>
172160
<Beat status={BeatStatus.COMPLETE}>
173161
<IconCheckmark size="sm" isCircled />
174-
{t('SDK Connected')}
162+
{t('DSN response received')}
175163
</Beat>
176164
<Beat status={BeatStatus.COMPLETE}>
177165
<IconCheckmark size="sm" isCircled />
@@ -182,7 +170,7 @@ export function HeartbeatFooter({
182170
<Fragment>
183171
<Beat status={BeatStatus.COMPLETE}>
184172
<IconCheckmark size="sm" isCircled />
185-
{t('SDK Connected')}
173+
{t('DSN response received')}
186174
</Beat>
187175
<Beat status={BeatStatus.AWAITING}>
188176
<PulsingIndicator>2</PulsingIndicator>
@@ -193,7 +181,7 @@ export function HeartbeatFooter({
193181
<Fragment>
194182
<Beat status={BeatStatus.AWAITING}>
195183
<PulsingIndicator>1</PulsingIndicator>
196-
{t('Awaiting SDK connection')}
184+
{t('Awaiting DSN response')}
197185
</Beat>
198186
<Beat status={BeatStatus.PENDING}>
199187
<PulsingIndicator>2</PulsingIndicator>
@@ -206,17 +194,6 @@ export function HeartbeatFooter({
206194
<ButtonBar gap={1}>
207195
{newOrg ? (
208196
<Fragment>
209-
{nextProject &&
210-
(loading ? (
211-
<LoadingPlaceholderButton width="125px" />
212-
) : (
213-
<Button busy={projectsLoading} onClick={onSetupNextProject}>
214-
{nextProject.platform
215-
? t('Setup %s', getPlatformName(nextProject.platform))
216-
: t('Next Platform')}
217-
</Button>
218-
))}
219-
220197
{loading ? (
221198
<LoadingPlaceholderButton width="135px" />
222199
) : firstErrorReceived ? (

static/app/views/onboarding/components/heartbeatFooter/useHeartbeat.tsx

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useEffect, useState} from 'react';
1+
import {useState} from 'react';
22

33
import {
44
Group,
@@ -25,26 +25,21 @@ export function useHeartbeat(
2525

2626
const serverConnected = hasSession || firstTransactionReceived;
2727

28-
const {
29-
isLoading: eventIsLoading,
30-
refetch: eventRefetch,
31-
isFetchedAfterMount: eventIsFetchedAfterMount,
32-
} = useQuery<Project>([`/projects/${organization.slug}/${projectSlug}/`], {
33-
staleTime: 0,
34-
refetchInterval: DEFAULT_POLL_INTERVAL,
35-
enabled: !!projectSlug && !firstError, // Fetch only if the project is available and we have not yet received an error,
36-
onSuccess: data => {
37-
setFirstError(data.firstEvent);
38-
// When an error is received, a transaction is also received
39-
setFirstTransactionReceived(!!data.firstTransactionEvent);
40-
},
41-
});
28+
const {isLoading: eventIsLoading} = useQuery<Project>(
29+
[`/projects/${organization.slug}/${projectSlug}/`],
30+
{
31+
staleTime: 0,
32+
refetchInterval: DEFAULT_POLL_INTERVAL,
33+
enabled: !!projectSlug && !firstError, // Fetch only if the project is available and we have not yet received an error,
34+
onSuccess: data => {
35+
setFirstError(data.firstEvent);
36+
// When an error is received, a transaction is also received
37+
setFirstTransactionReceived(!!data.firstTransactionEvent);
38+
},
39+
}
40+
);
4241

43-
const {
44-
isLoading: sessionIsLoading,
45-
refetch: sessionsRefetch,
46-
isFetchedAfterMount: sessionIsFetchedAfterMount,
47-
} = useQuery<SessionApiResponse>(
42+
const {isLoading: sessionIsLoading} = useQuery<SessionApiResponse>(
4843
[
4944
`/organizations/${organization.slug}/sessions/`,
5045
{
@@ -72,26 +67,16 @@ export function useHeartbeat(
7267
// *not* include sample events, while just looking at the issues list will.
7368
// We will wait until the project.firstEvent is set and then locate the
7469
// event given that event datetime
75-
const {refetch: issuesRefetch} = useQuery<Group[]>(
76-
[`/projects/${organization.slug}/${projectSlug}/issues/`],
77-
{
78-
staleTime: 0,
79-
enabled: !!firstError && !firstIssue, // Only fetch if an error event is received and we have not yet located the first issue,
80-
onSuccess: data => {
81-
setFirstIssue(data.find((issue: Group) => issue.firstSeen === firstError));
82-
},
83-
}
84-
);
70+
useQuery<Group[]>([`/projects/${organization.slug}/${projectSlug}/issues/`], {
71+
staleTime: 0,
72+
enabled: !!firstError && !firstIssue, // Only fetch if an error event is received and we have not yet located the first issue,
73+
onSuccess: data => {
74+
setFirstIssue(data.find((issue: Group) => issue.firstSeen === firstError));
75+
},
76+
});
8577

8678
const firstErrorReceived = firstIssue ?? !!firstError;
87-
const isFetchedAfterMount = eventIsFetchedAfterMount && sessionIsFetchedAfterMount;
88-
const loading = eventIsLoading || sessionIsLoading || !isFetchedAfterMount;
89-
90-
useEffect(() => {
91-
eventRefetch();
92-
sessionsRefetch();
93-
issuesRefetch();
94-
}, [eventRefetch, issuesRefetch, sessionsRefetch, projectSlug]);
79+
const loading = eventIsLoading || sessionIsLoading;
9580

9681
return {
9782
loading,

0 commit comments

Comments
 (0)