Browse Source

ref(onboarding): Delete project on back (#44737)

Priscila Oliveira 2 years ago
parent
commit
55154946e4

+ 17 - 20
static/app/actionCreators/projects.tsx

@@ -127,26 +127,6 @@ export function setActiveProject(project: Project | null) {
   LatestContextStore.onSetActiveProject(project);
   LatestContextStore.onSetActiveProject(project);
 }
 }
 
 
-export function removeProject(api: Client, orgId: string, project: Project) {
-  const endpoint = `/projects/${orgId}/${project.slug}/`;
-
-  return api
-    .requestPromise(endpoint, {
-      method: 'DELETE',
-    })
-    .then(
-      () => {
-        addSuccessMessage(
-          tct('[project] was successfully removed', {project: project.slug})
-        );
-      },
-      err => {
-        addErrorMessage(tct('Error removing [project]', {project: project.slug}));
-        throw err;
-      }
-    );
-}
-
 export function transferProject(
 export function transferProject(
   api: Client,
   api: Client,
   orgId: string,
   orgId: string,
@@ -340,6 +320,23 @@ export function createProject(
   });
   });
 }
 }
 
 
+/**
+ * Deletes a project
+ *
+ * @param api API Client
+ * @param orgSlug Organization Slug
+ * @param projectSlug Project Slug
+ */
+export function removeProject(
+  api: Client,
+  orgSlug: string,
+  projectSlug: Project['slug']
+) {
+  return api.requestPromise(`/projects/${orgSlug}/${projectSlug}/`, {
+    method: 'DELETE',
+  });
+}
+
 /**
 /**
  * Load platform documentation specific to the project. The DSN and various
  * Load platform documentation specific to the project. The DSN and various
  * other project specific secrets will be included in the documentation.
  * other project specific secrets will be included in the documentation.

+ 1 - 0
static/app/views/onboarding/components/heartbeatFooter/index.tsx

@@ -165,6 +165,7 @@ export function HeartbeatFooter({projectSlug, router, route, location, newOrg}:
       new_organization: !!newOrg,
       new_organization: !!newOrg,
     });
     });
   }, [firstTransactionReceived, loading, newOrg, organization]);
   }, [firstTransactionReceived, loading, newOrg, organization]);
+
   useEffect(() => {
   useEffect(() => {
     if (loading || !firstErrorReceived) {
     if (loading || !firstErrorReceived) {
       return;
       return;

+ 21 - 0
static/app/views/onboarding/index.tsx

@@ -3,6 +3,7 @@ import {browserHistory, RouteComponentProps} from 'react-router';
 import styled from '@emotion/styled';
 import styled from '@emotion/styled';
 import {AnimatePresence, motion, MotionProps, useAnimation} from 'framer-motion';
 import {AnimatePresence, motion, MotionProps, useAnimation} from 'framer-motion';
 
 
+import {removeProject} from 'sentry/actionCreators/projects';
 import {Button, ButtonProps} from 'sentry/components/button';
 import {Button, ButtonProps} from 'sentry/components/button';
 import Hook from 'sentry/components/hook';
 import Hook from 'sentry/components/hook';
 import Link from 'sentry/components/links/link';
 import Link from 'sentry/components/links/link';
@@ -15,6 +16,7 @@ import {Organization, Project} from 'sentry/types';
 import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
 import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
 import Redirect from 'sentry/utils/redirect';
 import Redirect from 'sentry/utils/redirect';
 import testableTransition from 'sentry/utils/testableTransition';
 import testableTransition from 'sentry/utils/testableTransition';
+import useApi from 'sentry/utils/useApi';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
 import withOrganization from 'sentry/utils/withOrganization';
 import withOrganization from 'sentry/utils/withOrganization';
 import withProjects from 'sentry/utils/withProjects';
 import withProjects from 'sentry/utils/withProjects';
@@ -73,6 +75,8 @@ function getOrganizationOnboardingSteps(singleSelectPlatform: boolean): StepDesc
 }
 }
 
 
 function Onboarding(props: Props) {
 function Onboarding(props: Props) {
+  const api = useApi();
+
   const {
   const {
     organization,
     organization,
     params: {step: stepId},
     params: {step: stepId},
@@ -94,6 +98,10 @@ function Onboarding(props: Props) {
     'onboarding-remove-multiselect-platform'
     'onboarding-remove-multiselect-platform'
   );
   );
 
 
+  const projectDeletionOnBackClick = !!props.organization?.features.includes(
+    'onboarding-project-deletion-on-back-click'
+  );
+
   const onboardingSteps = getOrganizationOnboardingSteps(singleSelectPlatform);
   const onboardingSteps = getOrganizationOnboardingSteps(singleSelectPlatform);
   const stepObj = onboardingSteps.find(({id}) => stepId === id);
   const stepObj = onboardingSteps.find(({id}) => stepId === id);
   const stepIndex = onboardingSteps.findIndex(({id}) => stepId === id);
   const stepIndex = onboardingSteps.findIndex(({id}) => stepId === id);
@@ -151,6 +159,19 @@ function Onboarding(props: Props) {
       return;
       return;
     }
     }
 
 
+    // The user is going back to select a new platform,
+    // so we silently delete the last created project
+    if (projectDeletionOnBackClick && stepIndex === onboardingSteps.length - 1) {
+      const selectedPlatforms = clientState?.selectedPlatforms || [];
+      const platformToProjectIdMap = clientState?.platformToProjectIdMap || {};
+
+      const selectedProjectSlugs = selectedPlatforms
+        .map(platform => platformToProjectIdMap[platform])
+        .filter((slug): slug is string => slug !== undefined);
+
+      removeProject(api, organization.slug, selectedProjectSlugs[0]);
+    }
+
     if (stepObj.cornerVariant !== previousStep.cornerVariant) {
     if (stepObj.cornerVariant !== previousStep.cornerVariant) {
       cornerVariantControl.start('none');
       cornerVariantControl.start('none');
     }
     }

+ 17 - 4
static/app/views/settings/projectGeneralSettings/index.tsx

@@ -1,6 +1,7 @@
 import {Component} from 'react';
 import {Component} from 'react';
 import {browserHistory, RouteComponentProps} from 'react-router';
 import {browserHistory, RouteComponentProps} from 'react-router';
 
 
+import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
 import {
 import {
   changeProjectSlug,
   changeProjectSlug,
   removeProject,
   removeProject,
@@ -69,10 +70,22 @@ class ProjectGeneralSettings extends AsyncView<Props, State> {
       return;
       return;
     }
     }
 
 
-    removeProject(this.api, organization.slug, project).then(() => {
-      // Need to hard reload because lots of components do not listen to Projects Store
-      window.location.assign('/');
-    }, handleXhrErrorResponse('Unable to remove project'));
+    removeProject(this.api, organization.slug, project.slug)
+      .then(
+        () => {
+          addSuccessMessage(
+            tct('[project] was successfully removed', {project: project.slug})
+          );
+        },
+        err => {
+          addErrorMessage(tct('Error removing [project]', {project: project.slug}));
+          throw err;
+        }
+      )
+      .then(() => {
+        // Need to hard reload because lots of components do not listen to Projects Store
+        window.location.assign('/');
+      }, handleXhrErrorResponse('Unable to remove project'));
   };
   };
 
 
   handleTransferProject = async () => {
   handleTransferProject = async () => {