Browse Source

feat(crons): Add monitor-status-toggle hook (#62072)

This will be used in sentry.io to make clear that enabling / disabling a
monitor is a billed action.

This also adjusts the types slightly of the button to make it more clear
what the action is.
Evan Purkhiser 1 year ago
parent
commit
10952e0d4d

+ 2 - 0
static/app/types/hooks.tsx

@@ -10,6 +10,7 @@ import type SelectorItems from 'sentry/components/timeRangeSelector/selectorItem
 import type {SVGIconProps} from 'sentry/icons/svgIcon';
 import type {Group} from 'sentry/types';
 import type {UseExperiment} from 'sentry/utils/useExperiment';
+import type {StatusToggleButtonProps} from 'sentry/views/monitors/components/statusToggleButton';
 import type {OrganizationStatsProps} from 'sentry/views/organizationStats/index';
 import type {RouteAnalyticsContext} from 'sentry/views/routeAnalyticsContextProvider';
 import type {NavigationItem, NavigationSection} from 'sentry/views/settings/types';
@@ -165,6 +166,7 @@ export type ComponentHooks = {
   'component:header-selector-items': () => React.ComponentType<SelectorItemsProps>;
   'component:issue-priority-feedback': () => React.ComponentType<QualitativeIssueFeedbackProps>;
   'component:member-list-header': () => React.ComponentType<MemberListHeaderProps>;
+  'component:monitor-status-toggle': () => React.ComponentType<StatusToggleButtonProps>;
   'component:org-stats-banner': () => React.ComponentType<DashboardHeadersProps>;
   'component:product-selection-availability': () => React.ComponentType<ProductSelectionAvailabilityProps>;
   'component:product-unavailable-cta': () => React.ComponentType<ProductUnavailableCTAProps>;

+ 6 - 7
static/app/views/monitors/components/monitorHeaderActions.tsx

@@ -50,22 +50,21 @@ function MonitorHeaderActions({monitor, orgId, onUpdate}: Props) {
     }
   };
 
-  const toggleMute = () => handleUpdate({isMuted: !monitor.isMuted});
-
-  const toggleStatus = () =>
-    handleUpdate({status: monitor.status === 'active' ? 'disabled' : 'active'});
-
   return (
     <ButtonBar gap={1}>
       <FeedbackWidgetButton />
       <Button
         size="sm"
         icon={monitor.isMuted ? <IconSubscribed /> : <IconUnsubscribed />}
-        onClick={toggleMute}
+        onClick={() => handleUpdate({isMuted: !monitor.isMuted})}
       >
         {monitor.isMuted ? t('Unmute') : t('Mute')}
       </Button>
-      <StatusToggleButton size="sm" onClick={toggleStatus} monitor={monitor} />
+      <StatusToggleButton
+        size="sm"
+        monitor={monitor}
+        onToggleStatus={status => handleUpdate({status})}
+      />
       <Confirm
         onConfirm={handleDelete}
         message={t('Are you sure you want to permanently delete this cron monitor?')}

+ 3 - 2
static/app/views/monitors/components/overviewTimeline/timelineTableRow.tsx

@@ -12,6 +12,7 @@ import {IconEllipsis} from 'sentry/icons';
 import {t, tct} from 'sentry/locale';
 import {fadeIn} from 'sentry/styles/animations';
 import {space} from 'sentry/styles/space';
+import {ObjectStatus} from 'sentry/types';
 import useOrganization from 'sentry/utils/useOrganization';
 import {StatusToggleButton} from 'sentry/views/monitors/components/statusToggleButton';
 import {Monitor, MonitorStatus} from 'sentry/views/monitors/types';
@@ -27,7 +28,7 @@ interface Props extends Omit<CheckInTimelineProps, 'bucketedData' | 'environment
   bucketedData?: MonitorBucket[];
   onDeleteEnvironment?: (env: string) => void;
   onToggleMuteEnvironment?: (env: string, isMuted: boolean) => void;
-  onToggleStatus?: (monitor: Monitor) => void;
+  onToggleStatus?: (monitor: Monitor, status: ObjectStatus) => void;
   /**
    * Whether only one monitor is being rendered in a larger view with this component
    * turns off things like zebra striping, hover effect, and showing monitor name
@@ -72,7 +73,7 @@ export function TimelineTableRow({
           <StatusToggleButton
             monitor={monitor}
             size="xs"
-            onClick={() => onToggleStatus(monitor)}
+            onToggleStatus={status => onToggleStatus(monitor, status)}
           />
         )}
       </DetailsActions>

+ 24 - 4
static/app/views/monitors/components/statusToggleButton.tsx

@@ -1,13 +1,20 @@
 import {BaseButtonProps, Button} from 'sentry/components/button';
+import HookOrDefault from 'sentry/components/hookOrDefault';
 import {IconPause, IconPlay} from 'sentry/icons';
 import {t} from 'sentry/locale';
+import {ObjectStatus} from 'sentry/types';
 import {Monitor} from 'sentry/views/monitors/types';
 
-interface StatusToggleButtonProps extends BaseButtonProps {
+interface StatusToggleButtonProps extends Omit<BaseButtonProps, 'onClick'> {
   monitor: Monitor;
+  onToggleStatus: (status: ObjectStatus) => void;
 }
 
-function StatusToggleButton({monitor, ...props}: StatusToggleButtonProps) {
+function SimpleStatusToggle({
+  monitor,
+  onToggleStatus,
+  ...props
+}: StatusToggleButtonProps) {
   const {status} = monitor;
   const isDisabeld = status === 'disabled';
 
@@ -17,7 +24,20 @@ function StatusToggleButton({monitor, ...props}: StatusToggleButtonProps) {
     ? t('Reactive this monitor')
     : t('Disable this monitor and discard incoming check-ins');
 
-  return <Button icon={<Icon />} aria-label={label} title={label} {...props} />;
+  return (
+    <Button
+      icon={<Icon />}
+      aria-label={label}
+      title={label}
+      onClick={() => onToggleStatus(isDisabeld ? 'active' : 'disabled')}
+      {...props}
+    />
+  );
 }
 
-export {StatusToggleButton};
+const StatusToggleButton = HookOrDefault({
+  hookName: 'component:monitor-status-toggle',
+  defaultComponent: SimpleStatusToggle,
+});
+
+export {StatusToggleButton, StatusToggleButtonProps};

+ 1 - 1
static/app/views/monitors/details.tsx

@@ -115,7 +115,7 @@ function MonitorDetails({params, location}: Props) {
                   <StatusToggleButton
                     monitor={monitor}
                     size="xs"
-                    onClick={() => handleUpdate({status: 'active'})}
+                    onToggleStatus={status => handleUpdate({status})}
                   >
                     {t('Reactivate')}
                   </StatusToggleButton>