Skip to content

Commit 47531c2

Browse files
authored
feat(seer): Change "Wrap Up" steps to be dynamic (#105201)
The Wrap Up steps are now based on what the user has configured. Do note that now, there is a possibility that the user can advance without turning on any Seer settings at all.
1 parent b8bb37a commit 47531c2

File tree

5 files changed

+147
-76
lines changed

5 files changed

+147
-76
lines changed

static/gsApp/views/seerAutomation/onboarding/configureRootCauseAnalysisStep.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export function ConfigureRootCauseAnalysisStep() {
5555
addRootCauseAnalysisRepository,
5656
addRepositoryProjectMappings,
5757
repositories,
58+
setAutoCreatePR,
5859
} = useSeerOnboardingContext();
5960

6061
const {
@@ -127,6 +128,8 @@ export function ConfigureRootCauseAnalysisStep() {
127128
}
128129
}
129130

131+
setAutoCreatePR(autoCreatePREnabled);
132+
130133
// Only submit if RCA is disabled (empty mapping is fine) or there are valid mappings
131134
const hasMappings = Object.keys(projectRepoMappings).length > 0;
132135
if (!hasMappings) {
@@ -165,6 +168,7 @@ export function ConfigureRootCauseAnalysisStep() {
165168
selectedRootCauseAnalysisRepositories,
166169
autoCreatePREnabled,
167170
organization,
171+
setAutoCreatePR,
168172
]);
169173

170174
const handleRepositoryProjectMappingsChange = useCallback(
@@ -184,6 +188,13 @@ export function ConfigureRootCauseAnalysisStep() {
184188
[changeRepositoryProjectMapping, repositoryProjectMapping]
185189
);
186190

191+
const handleAutoCreatePRChange = useCallback(
192+
(e: React.ChangeEvent<HTMLInputElement>) => {
193+
setAutoCreatePREnabled(e.target.checked);
194+
},
195+
[setAutoCreatePREnabled]
196+
);
197+
187198
const availableRepositories = useMemo(() => {
188199
return (
189200
repositories?.filter(
@@ -244,7 +255,7 @@ export function ConfigureRootCauseAnalysisStep() {
244255
<Switch
245256
size="lg"
246257
checked={autoCreatePREnabled}
247-
onChange={() => setAutoCreatePREnabled(!autoCreatePREnabled)}
258+
onChange={handleAutoCreatePRChange}
248259
/>
249260
</Field>
250261

static/gsApp/views/seerAutomation/onboarding/hooks/seerOnboardingContext.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
useMemo,
77
useRef,
88
useState,
9+
type RefObject,
910
} from 'react';
1011
import * as Sentry from '@sentry/react';
1112

@@ -22,6 +23,7 @@ import {useIntegrationProvider} from './useIntegrationProvider';
2223
interface SeerOnboardingContextProps {
2324
addRepositoryProjectMappings: (additionalMappings: Record<string, string[]>) => void;
2425
addRootCauseAnalysisRepository: (repoId: string) => void;
26+
autoCreatePR: RefObject<boolean | null> | null;
2527
changeRepositoryProjectMapping: (
2628
repoId: string,
2729
index: number,
@@ -40,11 +42,13 @@ interface SeerOnboardingContextProps {
4042
selectedCodeReviewRepositories: RepositoryWithSettings[];
4143
selectedCodeReviewRepositoriesMap: Record<string, boolean>;
4244
selectedRootCauseAnalysisRepositories: RepositoryWithSettings[];
45+
setAutoCreatePR: (value: boolean) => void;
4346
setCodeReviewRepositories: (newSelections: Record<string, boolean>) => void;
4447
unselectedCodeReviewRepositories: RepositoryWithSettings[];
4548
}
4649

4750
const SeerOnboardingContext = createContext<SeerOnboardingContextProps>({
51+
autoCreatePR: null,
4852
installationData: undefined,
4953
isInstallationPending: false,
5054
isProviderPending: false,
@@ -59,6 +63,7 @@ const SeerOnboardingContext = createContext<SeerOnboardingContextProps>({
5963
changeRepositoryProjectMapping: () => {},
6064
changeRootCauseAnalysisRepository: () => {},
6165
clearRootCauseAnalysisRepositories: () => {},
66+
setAutoCreatePR: () => {},
6267
setCodeReviewRepositories: () => {},
6368
removeRootCauseAnalysisRepository: () => {},
6469
addRootCauseAnalysisRepository: () => {},
@@ -73,6 +78,9 @@ export function SeerOnboardingProvider({children}: {children: React.ReactNode})
7378
const [repositoryProjectMapping, setRepositoryProjectMapping] = useState<
7479
Record<string, string[]>
7580
>({});
81+
// This is not state because we just avoid re-render. This is used on a different view than
82+
// where it is set, so we don't need the reactivity.
83+
const autoCreatePRRef = useRef<boolean | null>(null);
7684

7785
// Track if we've initialized the map to avoid overwriting user changes
7886
const hasInitializedCodeReviewMap = useRef(false);
@@ -132,6 +140,10 @@ export function SeerOnboardingProvider({children}: {children: React.ReactNode})
132140
[selectedCodeReviewRepositoriesMap, repositoriesMap]
133141
);
134142

143+
const setAutoCreatePR = useCallback((value: boolean) => {
144+
autoCreatePRRef.current = value;
145+
}, []);
146+
135147
const setCodeReviewRepositories = useCallback(
136148
(newSelections: Record<string, boolean>) => {
137149
setSelectedCodeReviewRepositoriesMap(prev => ({...prev, ...newSelections}));
@@ -312,6 +324,8 @@ export function SeerOnboardingProvider({children}: {children: React.ReactNode})
312324
addRepositoryProjectMappings,
313325
changeRepositoryProjectMapping,
314326
clearRootCauseAnalysisRepositories,
327+
setAutoCreatePR,
328+
autoCreatePR: autoCreatePRRef,
315329
}}
316330
>
317331
{children}

static/gsApp/views/seerAutomation/onboarding/nextStepsStep.tsx

Lines changed: 0 additions & 73 deletions
This file was deleted.

static/gsApp/views/seerAutomation/onboarding/stepsManager.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {ConfigureCodeReviewStep} from './configureCodeReviewStep';
1313
import {ConfigureDefaultsStep} from './configureDefaultsStep';
1414
import {ConfigureRootCauseAnalysisStep} from './configureRootCauseAnalysisStep';
1515
import {ConnectGithubStep} from './connectGithubStep';
16-
import {NextStepsStep} from './nextStepsStep';
16+
import {WrapUpStep} from './wrapUpStep';
1717

1818
export function StepsManager() {
1919
const {provider, isProviderPending, isInstallationPending} = useSeerOnboardingContext();
@@ -54,7 +54,7 @@ export function StepsManager() {
5454
</GuidedSteps.Step>
5555

5656
<GuidedSteps.Step stepKey={String(Steps.WRAP_UP)} title={t('Wrap Up')}>
57-
<NextStepsStep />
57+
<WrapUpStep />
5858
</GuidedSteps.Step>
5959
</Fragment>
6060
);
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import {Fragment, useMemo} from 'react';
2+
import styled from '@emotion/styled';
3+
4+
import nextStepsImg from 'sentry-images/spot/seer-config-bug-2.svg';
5+
6+
import {LinkButton} from '@sentry/scraps/button/linkButton';
7+
import {Link} from '@sentry/scraps/link';
8+
import {Text} from '@sentry/scraps/text';
9+
10+
import PanelBody from 'sentry/components/panels/panelBody';
11+
import {t, tct} from 'sentry/locale';
12+
import useOrganization from 'sentry/utils/useOrganization';
13+
14+
import {useSeerOnboardingContext} from './hooks/seerOnboardingContext';
15+
import {ActionSection, MaxWidthPanel, PanelDescription, StepContent} from './common';
16+
17+
export function WrapUpStep() {
18+
const organization = useOrganization();
19+
const {selectedCodeReviewRepositories, repositoryProjectMapping, autoCreatePR} =
20+
useSeerOnboardingContext();
21+
22+
const hasCodeReview = useMemo(
23+
() => selectedCodeReviewRepositories.length > 0,
24+
[selectedCodeReviewRepositories]
25+
);
26+
const hasRCA = useMemo(
27+
() => Object.keys(repositoryProjectMapping).length > 0,
28+
[repositoryProjectMapping]
29+
);
30+
const hasAutoCreatePR = useMemo(
31+
() => (hasRCA && autoCreatePR?.current) ?? false,
32+
[autoCreatePR, hasRCA]
33+
);
34+
const hasCompletedAnySteps = hasCodeReview || hasRCA || hasAutoCreatePR;
35+
36+
return (
37+
<Fragment>
38+
<StepContentWithBackground>
39+
<MaxWidthPanel>
40+
<PanelBody>
41+
{hasCompletedAnySteps ? (
42+
<PanelDescription>
43+
<Text bold>{t('Congratulations, you’ve finished setting up Seer!')}</Text>
44+
<p>
45+
{t(
46+
'For connected projects and repos, you will now be able to have Seer:'
47+
)}
48+
</p>
49+
<NextStepsList>
50+
{hasCodeReview && (
51+
<li>
52+
{t(
53+
'Review your PRs and catch bugs before you ship them to production'
54+
)}
55+
</li>
56+
)}
57+
{hasRCA && (
58+
<li>
59+
{t(
60+
'Perform root cause analysis on your issues and propose solutions'
61+
)}
62+
</li>
63+
)}
64+
{hasAutoCreatePR && <li>{t('Create PRs to fix issues')}</li>}
65+
</NextStepsList>
66+
<Text>
67+
{tct(
68+
'If you want to adjust your configurations, you can modify them on the [settings:Seer Settings Page], or configure [projects:projects] and [repos:repos] individually. ',
69+
{
70+
settings: <Link to={`/settings/${organization.slug}/seer/`} />,
71+
projects: (
72+
<Link to={`/settings/${organization.slug}/seer/projects/`} />
73+
),
74+
repos: <Link to={`/settings/${organization.slug}/seer/repos/`} />,
75+
}
76+
)}
77+
</Text>
78+
</PanelDescription>
79+
) : (
80+
<PanelDescription>
81+
<Text>
82+
{tct(
83+
'You can restart the wizard and continue setting up Seer, or if you prefer, you can set-up Seer on the [settings:Seer Settings Page], or configure [projects:projects] and [repos:repos] individually. ',
84+
{
85+
settings: <Link to={`/settings/${organization.slug}/seer/`} />,
86+
projects: (
87+
<Link to={`/settings/${organization.slug}/seer/projects/`} />
88+
),
89+
repos: <Link to={`/settings/${organization.slug}/seer/repos/`} />,
90+
}
91+
)}
92+
</Text>
93+
</PanelDescription>
94+
)}
95+
</PanelBody>
96+
</MaxWidthPanel>
97+
98+
<ActionSection>
99+
<LinkButton
100+
priority="primary"
101+
size="md"
102+
to={`/settings/${organization.slug}/seer/`}
103+
>
104+
{t('Finish')}
105+
</LinkButton>
106+
</ActionSection>
107+
</StepContentWithBackground>
108+
</Fragment>
109+
);
110+
}
111+
112+
const StepContentWithBackground = styled(StepContent)`
113+
background: url(${nextStepsImg}) no-repeat 638px 0;
114+
background-size: 233px 212px;
115+
`;
116+
117+
const NextStepsList = styled('ul')`
118+
margin: ${p => p.theme.space.xl} 0;
119+
`;

0 commit comments

Comments
 (0)