@@ -7,6 +7,7 @@ import {Container, Flex, Stack} from '@sentry/scraps/layout';
77import { Text } from '@sentry/scraps/text' ;
88
99import { addErrorMessage } from 'sentry/actionCreators/indicator' ;
10+ import { update as updateProject } from 'sentry/actionCreators/projects' ;
1011import { useOnboardingContext } from 'sentry/components/onboarding/onboardingContext' ;
1112import { useCreateProjectAndRules } from 'sentry/components/onboarding/useCreateProjectAndRules' ;
1213import { TeamSelector } from 'sentry/components/teamSelector' ;
@@ -15,7 +16,9 @@ import {t} from 'sentry/locale';
1516import type { Team } from 'sentry/types/organization' ;
1617import { trackAnalytics } from 'sentry/utils/analytics' ;
1718import { slugify } from 'sentry/utils/slugify' ;
19+ import { useApi } from 'sentry/utils/useApi' ;
1820import { useOrganization } from 'sentry/utils/useOrganization' ;
21+ import { useProjects } from 'sentry/utils/useProjects' ;
1922import { useTeams } from 'sentry/utils/useTeams' ;
2023import {
2124 DEFAULT_ISSUE_ALERT_OPTIONS_VALUES ,
@@ -32,10 +35,12 @@ import type {StepProps} from './types';
3235const PROJECT_DETAILS_WIDTH = '285px' ;
3336
3437export function ScmProjectDetails ( { onComplete} : StepProps ) {
38+ const api = useApi ( ) ;
3539 const organization = useOrganization ( ) ;
36- const { selectedPlatform, selectedFeatures, setCreatedProjectSlug} =
40+ const { selectedPlatform, selectedFeatures, createdProjectSlug , setCreatedProjectSlug} =
3741 useOnboardingContext ( ) ;
38- const { teams} = useTeams ( ) ;
42+ const { teams, fetching : isLoadingTeams } = useTeams ( ) ;
43+ const { projects, initiallyLoaded : projectsLoaded } = useProjects ( ) ;
3944 const createProjectAndRules = useCreateProjectAndRules ( ) ;
4045 useEffect ( ( ) => {
4146 trackAnalytics ( 'onboarding.scm_project_details_step_viewed' , { organization} ) ;
@@ -44,12 +49,21 @@ export function ScmProjectDetails({onComplete}: StepProps) {
4449 const firstAdminTeam = teams . find ( ( team : Team ) => team . access . includes ( 'team:admin' ) ) ;
4550 const defaultName = slugify ( selectedPlatform ?. key ?? '' ) ;
4651
47- // State tracks user edits; derived values fall back to defaults from context/teams
52+ // If the onboarding context still holds a created project slug (e.g. the
53+ // user went back after the project already received its first event),
54+ // look it up in the store so we can pre-populate and update in place.
55+ const existingProject = createdProjectSlug
56+ ? projects . find ( p => p . slug === createdProjectSlug )
57+ : undefined ;
58+
59+ // State tracks user edits; derived values fall back to the existing
60+ // project if one was found, then to defaults from context/teams.
4861 const [ projectName , setProjectName ] = useState < string | null > ( null ) ;
4962 const [ teamSlug , setTeamSlug ] = useState < string | null > ( null ) ;
5063
51- const projectNameResolved = projectName ?? defaultName ;
52- const teamSlugResolved = teamSlug ?? firstAdminTeam ?. slug ?? '' ;
64+ const projectNameResolved = projectName ?? existingProject ?. slug ?? defaultName ;
65+ const teamSlugResolved =
66+ teamSlug ?? existingProject ?. teams [ 0 ] ?. slug ?? firstAdminTeam ?. slug ?? '' ;
5367
5468 const [ alertRuleConfig , setAlertRuleConfig ] = useState < AlertRuleOptions > (
5569 DEFAULT_ISSUE_ALERT_OPTIONS_VALUES
@@ -94,13 +108,51 @@ export function ScmProjectDetails({onComplete}: StepProps) {
94108 projectNameResolved . length > 0 &&
95109 teamSlugResolved . length > 0 &&
96110 ! ! selectedPlatform &&
97- ! createProjectAndRules . isPending ;
111+ ! createProjectAndRules . isPending &&
112+ ! isLoadingTeams &&
113+ projectsLoaded ;
98114
99115 async function handleCreateProject ( ) {
100116 if ( ! selectedPlatform || ! canSubmit ) {
101117 return ;
102118 }
103119
120+ if ( existingProject ) {
121+ // A project was already created in a previous pass through this step.
122+ // TODO(onboarding): pre-populate and apply alertRuleConfig changes
123+ // from the existing project's rules.
124+ const platformChanged = existingProject . platform !== selectedPlatform . key ;
125+
126+ if ( platformChanged ) {
127+ // Platform changed — abandon the old project and fall through to
128+ // create a new one, matching legacy onboarding behavior.
129+ } else if ( projectName === null && teamSlug === null ) {
130+ // Nothing changed — reuse the existing project as-is.
131+ setCreatedProjectSlug ( existingProject . slug ) ;
132+ onComplete ( undefined , selectedFeatures ? { product : selectedFeatures } : undefined ) ;
133+ return ;
134+ } else {
135+ // Same platform but name or team changed — update in place.
136+ try {
137+ const updated = await updateProject ( api , {
138+ orgId : organization . slug ,
139+ projectId : existingProject . slug ,
140+ data : { name : projectNameResolved } ,
141+ } ) ;
142+
143+ setCreatedProjectSlug ( updated . slug ) ;
144+ onComplete (
145+ undefined ,
146+ selectedFeatures ? { product : selectedFeatures } : undefined
147+ ) ;
148+ } catch ( error ) {
149+ addErrorMessage ( t ( 'Failed to update project' ) ) ;
150+ Sentry . captureException ( error ) ;
151+ }
152+ return ;
153+ }
154+ }
155+
104156 trackAnalytics ( 'onboarding.scm_project_details_create_clicked' , { organization} ) ;
105157
106158 try {
0 commit comments