Browse Source

feat(alerts): Optional url to create alerts from wizard without projects (#33548)

* feat(alerts): Optional url to create alerts from wizard without projects

* retain project slug from alert list
Taylan Gocmen 2 years ago
parent
commit
b9e4eb40cc

+ 12 - 3
static/app/components/createAlertButton.tsx

@@ -353,10 +353,19 @@ const CreateAlertButton = withRouter(
     ...buttonProps
   }: Props) => {
     const api = useApi();
-
     const createAlertUrl = (providedProj: string) => {
-      const alertsBaseUrl = `/organizations/${organization.slug}/alerts/${providedProj}`;
-      return `${alertsBaseUrl}/wizard/${referrer ? `?referrer=${referrer}` : ''}`;
+      const hasAlertWizardV3 = organization.features.includes('alert-wizard-v3');
+      const alertsBaseUrl = hasAlertWizardV3
+        ? `/organizations/${organization.slug}/alerts`
+        : `/organizations/${organization.slug}/alerts/${providedProj}`;
+      const alertsArgs = [
+        `${referrer ? `referrer=${referrer}` : ''}`,
+        `${hasAlertWizardV3 && providedProj ? `project=${providedProj}` : ''}`,
+      ].filter(item => item !== '');
+
+      return `${alertsBaseUrl}/wizard/${alertsArgs.length ? '?' : ''}${alertsArgs.join(
+        '&'
+      )}`;
     };
 
     function handleClickWithoutProject(event: React.MouseEvent) {

+ 12 - 0
static/app/routes.tsx

@@ -1081,12 +1081,24 @@ function buildRoutes() {
           />
         </Route>
       </Route>
+      <Route
+        path="wizard/"
+        name={t('Alert Creation Wizard')}
+        component={SafeLazyLoad}
+        componentPromise={() => import('sentry/views/alerts/builder/projectProvider')}
+      >
+        <IndexRoute
+          component={SafeLazyLoad}
+          componentPromise={() => import('sentry/views/alerts/wizard')}
+        />
+      </Route>
       <Route
         path="new/"
         name={t('New Alert Rule')}
         component={SafeLazyLoad}
         componentPromise={() => import('sentry/views/alerts/builder/projectProvider')}
       >
+        <IndexRedirect to="/organizations/:orgId/alerts/wizard/" />
         <Route
           path=":alertType/"
           component={SafeLazyLoad}

+ 13 - 4
static/app/views/alerts/builder/projectProvider.tsx

@@ -26,10 +26,18 @@ function AlertBuilderProjectProvider(props: Props) {
 
   const {children, params, organization, ...other} = props;
   const projectId = params.projectId || props.location.query.project;
-  const {projects, initiallyLoaded, fetching, fetchError} = useProjects({
-    slugs: [projectId],
-  });
-  const project = projects.find(({slug}) => slug === projectId);
+  const hasAlertWizardV3 = organization.features.includes('alert-wizard-v3');
+  const useFirstProject = hasAlertWizardV3 && projectId === undefined;
+
+  // calling useProjects() without args fetches all projects
+  const {projects, initiallyLoaded, fetching, fetchError} = useFirstProject
+    ? useProjects()
+    : useProjects({
+        slugs: [projectId],
+      });
+  const project = useFirstProject
+    ? projects.find(p => p)
+    : projects.find(({slug}) => slug === projectId);
 
   useEffect(() => {
     if (!project) {
@@ -56,6 +64,7 @@ function AlertBuilderProjectProvider(props: Props) {
         ...other,
         ...children.props,
         project,
+        projectId: useFirstProject ? project.slug : projectId,
         organization,
       })
     : children;

+ 17 - 22
static/app/views/alerts/wizard/index.tsx

@@ -32,12 +32,13 @@ import RadioPanelGroup from './radioPanelGroup';
 
 type RouteParams = {
   orgId: string;
-  projectId: string;
+  projectId?: string;
 };
 
 type Props = RouteComponentProps<RouteParams, {}> & {
   organization: Organization;
   project: Project;
+  projectId: string;
 };
 
 type State = {
@@ -70,12 +71,9 @@ class AlertWizard extends Component<Props, State> {
   };
 
   renderCreateAlertButton() {
-    const {
-      organization,
-      location,
-      params: {projectId},
-    } = this.props;
+    const {organization, location, params, projectId: _projectId} = this.props;
     const {alertOption} = this.state;
+    const projectId = params.projectId ?? _projectId;
     let metricRuleTemplate: Readonly<WizardRuleTemplate> | undefined =
       AlertWizardRuleTemplates[alertOption];
     const isMetricAlert = !!metricRuleTemplate;
@@ -90,25 +88,26 @@ class AlertWizard extends Component<Props, State> {
       metricRuleTemplate = {...metricRuleTemplate, dataset: Dataset.METRICS};
     }
 
-    const to = {
-      pathname: hasAlertWizardV3
-        ? `/organizations/${organization.slug}/alerts/new/${
+    const to = hasAlertWizardV3
+      ? {
+          pathname: `/organizations/${organization.slug}/alerts/new/${
             isMetricAlert ? AlertRuleType.METRIC : AlertRuleType.ISSUE
-          }/`
-        : `/organizations/${organization.slug}/alerts/${projectId}/new/`,
-      query: hasAlertWizardV3
-        ? {
+          }/`,
+          query: {
             ...(metricRuleTemplate ? metricRuleTemplate : {}),
             project: projectId,
             createFromV3: true,
             referrer: location?.query?.referrer,
-          }
-        : {
+          },
+        }
+      : {
+          pathname: `/organizations/${organization.slug}/alerts/${projectId}/new/`,
+          query: {
             ...(metricRuleTemplate ? metricRuleTemplate : {}),
             createFromWizard: true,
             referrer: location?.query?.referrer,
           },
-    };
+        };
 
     const noFeatureMessage = t('Requires incidents feature.');
     const renderNoAccess = p => (
@@ -166,13 +165,9 @@ class AlertWizard extends Component<Props, State> {
   }
 
   render() {
-    const {
-      organization,
-      params: {projectId},
-      routes,
-      location,
-    } = this.props;
+    const {organization, params, projectId: _projectId, routes, location} = this.props;
     const {alertOption} = this.state;
+    const projectId = params.projectId ?? _projectId;
     const title = t('Alert Creation Wizard');
     const panelContent = AlertWizardPanelContent[alertOption];
     return (

+ 1 - 0
tests/js/spec/views/alerts/wizard/alertWizard.spec.tsx

@@ -29,6 +29,7 @@ describe('AlertWizard', () => {
         routeParams={router.params}
         location={router.location}
         params={{orgId: organization.slug, projectId: project.slug}}
+        projectId={project.slug}
       />,
       {context: routerContext, organization}
     );