Browse Source

chore(metrics): remove create alert and create widget actions (#78603)

Ogi 5 months ago
parent
commit
86f5776ab0

+ 9 - 5
static/app/components/modals/metricWidgetViewerModal.tsx

@@ -17,6 +17,7 @@ import type {Organization} from 'sentry/types/organization';
 import {defined} from 'sentry/utils';
 import {getMetricsUrl} from 'sentry/utils/metrics';
 import {toDisplayType} from 'sentry/utils/metrics/dashboard';
+import {hasCustomMetrics} from 'sentry/utils/metrics/features';
 import {parseMRI} from 'sentry/utils/metrics/mri';
 import {MetricExpressionType} from 'sentry/utils/metrics/types';
 import {useVirtualMetricsContext} from 'sentry/utils/metrics/virtualMetricsContext';
@@ -298,13 +299,14 @@ function MetricWidgetViewerModal({
   const handleClose = useCallback(() => {
     if (
       userHasModified &&
+      hasCustomMetrics(organization) &&
       // eslint-disable-next-line no-alert
       !window.confirm(t('You have unsaved changes, are you sure you want to close?'))
     ) {
       return;
     }
     closeModal();
-  }, [userHasModified, closeModal]);
+  }, [userHasModified, closeModal, organization]);
 
   const {mri, aggregation, query, condition} = metricQueries[0];
 
@@ -325,7 +327,7 @@ function MetricWidgetViewerModal({
           <CloseButton onClick={handleClose} />
         </Header>
         <Body>
-          <MetricsBetaEndAlert />
+          <MetricsBetaEndAlert organization={organization} />
           <Queries
             displayType={displayType}
             metricQueries={metricQueries}
@@ -363,9 +365,11 @@ function MetricWidgetViewerModal({
             >
               {t('Open in Metrics')}
             </LinkButton>
-            <Button priority="primary" onClick={handleSubmit}>
-              {t('Save changes')}
-            </Button>
+            {hasCustomMetrics(organization) && (
+              <Button priority="primary" onClick={handleSubmit}>
+                {t('Save changes')}
+              </Button>
+            )}
           </ButtonBar>
         </Footer>
       </OrganizationContext.Provider>

+ 7 - 3
static/app/components/modals/metricWidgetViewerModal/queries.tsx

@@ -30,7 +30,11 @@ import {
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import {isCustomMetric} from 'sentry/utils/metrics';
-import {hasMetricAlertFeature, hasMetricsNewInputs} from 'sentry/utils/metrics/features';
+import {
+  hasCustomMetrics,
+  hasMetricAlertFeature,
+  hasMetricsNewInputs,
+} from 'sentry/utils/metrics/features';
 import {MetricExpressionType} from 'sentry/utils/metrics/types';
 import useOrganization from 'sentry/utils/useOrganization';
 import usePageFilters from 'sentry/utils/usePageFilters';
@@ -336,9 +340,9 @@ function QueryContextMenu({
       },
     };
 
-    return customMetric
+    return hasCustomMetrics(organization)
       ? [duplicateQueryItem, aliasItem, addAlertItem, removeQueryItem, settingsItem]
-      : [duplicateQueryItem, aliasItem, addAlertItem, removeQueryItem];
+      : [duplicateQueryItem, aliasItem, removeQueryItem, settingsItem];
   }, [
     metricsQuery.mri,
     createAlert,

+ 1 - 1
static/app/views/alerts/rules/metric/details/body.tsx

@@ -173,7 +173,7 @@ export default function MetricDetailsBody({
       <StyledLayoutBody>
         {isCustomMetricAlert(rule.aggregate) &&
           !isInsightsMetricAlert(rule.aggregate) && (
-            <MetricsBetaEndAlert style={{marginBottom: 0}} />
+            <MetricsBetaEndAlert style={{marginBottom: 0}} organization={organization} />
           )}
       </StyledLayoutBody>
       {selectedIncident?.alertRule.status === AlertRuleStatus.SNAPSHOT && (

+ 3 - 1
static/app/views/alerts/rules/metric/ruleForm.tsx

@@ -1219,7 +1219,9 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
       <Main fullWidth>
         <PermissionAlert access={['alerts:write']} project={project} />
         {isCustomMetricAlert(rule.aggregate) &&
-          !isInsightsMetricAlert(rule.aggregate) && <MetricsBetaEndAlert />}
+          !isInsightsMetricAlert(rule.aggregate) && (
+            <MetricsBetaEndAlert organization={organization} />
+          )}
 
         {eventView && <IncompatibleAlertQuery eventView={eventView} />}
         <Form

+ 1 - 2
static/app/views/dashboards/dashboard.tsx

@@ -342,8 +342,7 @@ class Dashboard extends Component<Props, State> {
       widget_type: widget.displayType,
     });
 
-    if (widget.widgetType === WidgetType.METRICS && hasCustomMetrics(organization)) {
-      // TODO(ddm): open preview modal
+    if (widget.widgetType === WidgetType.METRICS) {
       return;
     }
 

+ 17 - 20
static/app/views/dashboards/widgetCard/index.tsx

@@ -26,7 +26,6 @@ import {getFormattedDate} from 'sentry/utils/dates';
 import type {TableDataWithTitle} from 'sentry/utils/discover/discoverQuery';
 import type {AggregationOutputType} from 'sentry/utils/discover/fields';
 import {parseFunction} from 'sentry/utils/discover/fields';
-import {hasCustomMetrics} from 'sentry/utils/metrics/features';
 import {hasOnDemandMetricWidgetFeature} from 'sentry/utils/onDemandMetrics/features';
 import {ExtractedMetricsTag} from 'sentry/utils/performance/contexts/metricsEnhancedPerformanceDataContext';
 import {
@@ -282,25 +281,23 @@ class WidgetCard extends Component<Props, State> {
     );
 
     if (widget.widgetType === WidgetType.METRICS) {
-      if (hasCustomMetrics(organization)) {
-        return (
-          <MetricWidgetCard
-            index={this.props.index}
-            isEditingDashboard={this.props.isEditingDashboard}
-            onEdit={this.props.onEdit}
-            onDelete={this.props.onDelete}
-            onDuplicate={this.props.onDuplicate}
-            router={this.props.router}
-            location={this.props.location}
-            organization={organization}
-            selection={selection}
-            widget={widget}
-            dashboardFilters={dashboardFilters}
-            renderErrorMessage={renderErrorMessage}
-            showContextMenu={this.props.showContextMenu}
-          />
-        );
-      }
+      return (
+        <MetricWidgetCard
+          index={this.props.index}
+          isEditingDashboard={this.props.isEditingDashboard}
+          onEdit={this.props.onEdit}
+          onDelete={this.props.onDelete}
+          onDuplicate={this.props.onDuplicate}
+          router={this.props.router}
+          location={this.props.location}
+          organization={organization}
+          selection={selection}
+          widget={widget}
+          dashboardFilters={dashboardFilters}
+          renderErrorMessage={renderErrorMessage}
+          showContextMenu={this.props.showContextMenu}
+        />
+      );
     }
 
     return (

+ 1 - 11
static/app/views/metrics/layout.tsx

@@ -4,7 +4,6 @@ import * as Sentry from '@sentry/react';
 
 import emptyStateImg from 'sentry-images/spot/custom-metrics-empty-state.svg';
 
-import Alert from 'sentry/components/alert';
 import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import FeatureBadge from 'sentry/components/badge/featureBadge';
 import {Button, LinkButton} from 'sentry/components/button';
@@ -23,7 +22,6 @@ import {space} from 'sentry/styles/space';
 import type {Organization} from 'sentry/types/organization';
 import {trackAnalytics} from 'sentry/utils/analytics';
 import {METRICS_DOCS_URL} from 'sentry/utils/metrics/constants';
-import {hasCustomMetrics} from 'sentry/utils/metrics/features';
 import {useVirtualMetricsContext} from 'sentry/utils/metrics/virtualMetricsContext';
 import useDismissAlert from 'sentry/utils/useDismissAlert';
 import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
@@ -102,14 +100,6 @@ export const MetricsLayout = memo(() => {
     hasSentCustomMetrics,
   });
 
-  if (!hasCustomMetrics(organization)) {
-    return (
-      <Layout.Page withPadding>
-        <Alert type="warning">{t("You don't have access to this feature")}</Alert>
-      </Layout.Page>
-    );
-  }
-
   return (
     <Fragment>
       <Layout.Header>
@@ -144,7 +134,7 @@ export const MetricsLayout = memo(() => {
       <Layout.Body>
         <FloatingFeedbackWidget />
         <Layout.Main fullWidth>
-          <MetricsBetaEndAlert />
+          <MetricsBetaEndAlert organization={organization} />
 
           <FilterContainer>
             <PageFilterBar condensed>

+ 119 - 108
static/app/views/metrics/metricQueryContextMenu.tsx

@@ -67,121 +67,132 @@ export function MetricQueryContextMenu({
   const canDelete = widgets.filter(isMetricsQueryWidget).length > 1;
   const hasDashboardFeature = organization.features.includes('dashboards-edit');
 
-  const items = useMemo<MenuItemProps[]>(
-    () => [
-      {
-        leadingItems: [<IconCopy key="icon" />],
-        key: 'duplicate',
-        label: t('Duplicate'),
-        onAction: () => {
-          trackAnalytics('ddm.widget.duplicate', {
-            organization,
-          });
-          Sentry.metrics.increment('ddm.widget.duplicate');
-          duplicateWidget(widgetIndex);
-        },
+  const items = useMemo<MenuItemProps[]>(() => {
+    const duplicateItem = {
+      leadingItems: [<IconCopy key="icon" />],
+      key: 'duplicate',
+      label: t('Duplicate'),
+      onAction: () => {
+        trackAnalytics('ddm.widget.duplicate', {
+          organization,
+        });
+        Sentry.metrics.increment('ddm.widget.duplicate');
+        duplicateWidget(widgetIndex);
       },
-      {
-        leadingItems: [<IconSiren key="icon" />],
-        key: 'add-alert',
-        label: <CreateMetricAlertFeature>{t('Create Alert')}</CreateMetricAlertFeature>,
-        disabled: !createAlert || !hasMetricAlertFeature(organization),
-        onAction: () => {
-          trackAnalytics('ddm.create-alert', {
-            organization,
-            source: 'widget',
-          });
-          Sentry.metrics.increment('ddm.widget.alert');
-          createAlert?.();
-        },
+    };
+
+    const createAlertItem = {
+      leadingItems: [<IconSiren key="icon" />],
+      key: 'add-alert',
+      label: <CreateMetricAlertFeature>{t('Create Alert')}</CreateMetricAlertFeature>,
+      disabled: !createAlert || !hasMetricAlertFeature(organization),
+      onAction: () => {
+        trackAnalytics('ddm.create-alert', {
+          organization,
+          source: 'widget',
+        });
+        Sentry.metrics.increment('ddm.widget.alert');
+        createAlert?.();
       },
-      {
-        leadingItems: [<IconDashboard key="icon" />],
-        key: 'add-dashboard',
-        label: (
-          <Feature
-            organization={organization}
-            hookName="feature-disabled:dashboards-edit"
-            features="dashboards-edit"
-            renderDisabled={p => (
-              <Hovercard
-                body={
-                  <FeatureDisabled
-                    features={p.features}
-                    hideHelpToggle
-                    featureName={t('Metric Alerts')}
-                  />
-                }
-              >
-                {typeof p.children === 'function' ? p.children(p) : p.children}
-              </Hovercard>
-            )}
-          >
-            <span>{t('Add to Dashboard')}</span>
-          </Feature>
-        ),
-        disabled: !createDashboardWidget || !hasDashboardFeature,
-        onAction: () => {
-          if (!organization.features.includes('dashboards-edit')) {
-            return;
-          }
-          trackAnalytics('ddm.add-to-dashboard', {
-            organization,
-            source: 'widget',
-          });
-          Sentry.metrics.increment('ddm.widget.dashboard');
-          createDashboardWidget?.();
-        },
+    };
+
+    const addToDashboardItem = {
+      leadingItems: [<IconDashboard key="icon" />],
+      key: 'add-dashboard',
+      label: (
+        <Feature
+          organization={organization}
+          hookName="feature-disabled:dashboards-edit"
+          features="dashboards-edit"
+          renderDisabled={p => (
+            <Hovercard
+              body={
+                <FeatureDisabled
+                  features={p.features}
+                  hideHelpToggle
+                  featureName={t('Metric Alerts')}
+                />
+              }
+            >
+              {typeof p.children === 'function' ? p.children(p) : p.children}
+            </Hovercard>
+          )}
+        >
+          <span>{t('Add to Dashboard')}</span>
+        </Feature>
+      ),
+      disabled: !createDashboardWidget || !hasDashboardFeature,
+      onAction: () => {
+        if (!organization.features.includes('dashboards-edit')) {
+          return;
+        }
+        trackAnalytics('ddm.add-to-dashboard', {
+          organization,
+          source: 'widget',
+        });
+        Sentry.metrics.increment('ddm.widget.dashboard');
+        createDashboardWidget?.();
       },
-      {
-        leadingItems: [<IconSettings key="icon" />],
-        key: 'settings',
-        disabled: !isCustomMetric({mri: metricsQuery.mri}),
-        label: t('Configure Metric'),
-        onAction: () => {
-          trackAnalytics('ddm.widget.settings', {
-            organization,
-          });
-          Sentry.metrics.increment('ddm.widget.settings');
+    };
+
+    const settingsItem = {
+      leadingItems: [<IconSettings key="icon" />],
+      key: 'settings',
+      disabled: !isCustomMetric({mri: metricsQuery.mri}),
+      label: t('Configure Metric'),
+      onAction: () => {
+        trackAnalytics('ddm.widget.settings', {
+          organization,
+        });
+        Sentry.metrics.increment('ddm.widget.settings');
 
-          if (!isVirtualMetric(metricsQuery)) {
-            navigateTo(
-              `/settings/projects/:projectId/metrics/${encodeURIComponent(
-                metricsQuery.mri
-              )}`,
-              router
-            );
-          }
-        },
+        if (!isVirtualMetric(metricsQuery)) {
+          navigateTo(
+            `/settings/projects/:projectId/metrics/${encodeURIComponent(
+              metricsQuery.mri
+            )}`,
+            router
+          );
+        }
       },
-      {
-        leadingItems: [<IconClose key="icon" />],
-        key: 'delete',
-        label: t('Remove Metric'),
-        disabled: !canDelete,
-        onAction: () => {
-          Sentry.metrics.increment('ddm.widget.delete');
-          removeWidget(widgetIndex);
-        },
+    };
+
+    const deleteItem = {
+      leadingItems: [<IconClose key="icon" />],
+      key: 'delete',
+      label: t('Delete'),
+      disabled: !canDelete,
+      onAction: () => {
+        trackAnalytics('ddm.widget.delete', {
+          organization,
+        });
+        Sentry.metrics.increment('ddm.widget.delete');
+        removeWidget(widgetIndex);
       },
-    ],
-    [
-      createAlert,
-      organization,
-      metricsQuery,
-      createDashboardWidget,
-      hasDashboardFeature,
-      canDelete,
-      duplicateWidget,
-      widgetIndex,
-      router,
-      removeWidget,
-    ]
-  );
+    };
 
-  if (!hasCustomMetrics(organization)) {
-    return null;
-  }
+    if (hasCustomMetrics(organization)) {
+      return [
+        duplicateItem,
+        createAlertItem,
+        addToDashboardItem,
+        settingsItem,
+        deleteItem,
+      ];
+    }
+    return [duplicateItem, settingsItem, deleteItem];
+  }, [
+    createAlert,
+    organization,
+    metricsQuery,
+    createDashboardWidget,
+    hasDashboardFeature,
+    canDelete,
+    duplicateWidget,
+    widgetIndex,
+    router,
+    removeWidget,
+  ]);
 
   return (
     <DropdownMenu

+ 21 - 2
static/app/views/metrics/metricsBetaEndAlert.tsx

@@ -1,12 +1,31 @@
 import Alert, {type AlertProps} from 'sentry/components/alert';
 import ExternalLink from 'sentry/components/links/externalLink';
 import {tct} from 'sentry/locale';
+import type {Organization} from 'sentry/types/organization';
+import {hasCustomMetrics} from 'sentry/utils/metrics/features';
 
-export function MetricsBetaEndAlert({style}: Pick<AlertProps, 'style'>) {
+export function MetricsBetaEndAlert({
+  style,
+  organization,
+}: Pick<AlertProps, 'style'> & {organization: Organization}) {
+  if (!hasCustomMetrics(organization)) {
+    return (
+      <Alert type="error" showIcon style={style}>
+        {tct(
+          'The Metrics beta program has ended on October 7th. This page is still available in read-only mode for 90 days. For more details, please [link:read the FAQs]. Thank you again for participating.',
+          {
+            link: (
+              <ExternalLink href="https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Coming-to-an-End" />
+            ),
+          }
+        )}
+      </Alert>
+    );
+  }
   return (
     <Alert type="error" showIcon style={style}>
       {tct(
-        'Thank you for participating in our Metrics beta program. After careful consideration, we are ending the beta program and will retire the current Metrics solution on October 7th. Stay tuned for updates and [link:read the FAQs] for more details.',
+        'Thank you for participating in our Metrics beta program. After careful consideration, we are ending the beta program and will retire the current Metrics solution on Nov 7th. Stay tuned for updates and [link:read the FAQs] for more details.',
         {
           link: (
             <ExternalLink href="https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Coming-to-an-End" />

+ 4 - 0
static/app/views/metrics/pageHeaderActions.spec.tsx

@@ -3,6 +3,10 @@ import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
 import {PageHeaderActions} from 'sentry/views/metrics/pageHeaderActions';
 
 jest.mock('sentry/views/metrics/useCreateDashboard');
+jest.mock('sentry/utils/metrics/features', () => ({
+  hasCustomMetrics: jest.fn(() => true),
+  hasMetricsNewInputs: jest.fn(() => true),
+}));
 
 describe('Metrics Page Header Actions', function () {
   describe('add metric buttons', function () {

Some files were not shown because too many files changed in this diff