Browse Source

feat(crons): Add crons to issue filters (#52029)

Scott Cooper 1 year ago
parent
commit
7f95ea2933

+ 1 - 0
static/app/components/stream/group.tsx

@@ -300,6 +300,7 @@ function BaseGroupRow({
     [IssueCategory.ERROR]: t('Error Events'),
     [IssueCategory.PERFORMANCE]: t('Transaction Events'),
     [IssueCategory.PROFILE]: t('Profile Events'),
+    [IssueCategory.CRON]: t('Cron Events'),
   };
 
   const groupCount = !defined(primaryCount) ? (

+ 5 - 1
static/app/stores/tagStore.tsx

@@ -82,7 +82,11 @@ const storeConfig: TagStoreDefinition = {
       [FieldKey.ISSUE_CATEGORY]: {
         key: FieldKey.ISSUE_CATEGORY,
         name: 'Issue Category',
-        values: [IssueCategory.ERROR, IssueCategory.PERFORMANCE],
+        values: [
+          IssueCategory.ERROR,
+          IssueCategory.PERFORMANCE,
+          ...(org.features.includes('issue-platform') ? [IssueCategory.CRON] : []),
+        ],
         predefined: true,
       },
       [FieldKey.ISSUE_TYPE]: {

+ 1 - 0
static/app/types/group.tsx

@@ -51,6 +51,7 @@ export enum SavedSearchType {
 export enum IssueCategory {
   PERFORMANCE = 'performance',
   ERROR = 'error',
+  CRON = 'cron',
   PROFILE = 'profile',
 }
 

+ 1 - 0
static/app/utils/issueTypeConfig/index.tsx

@@ -39,6 +39,7 @@ const issueTypeConfig: Config = {
   [IssueCategory.ERROR]: errorConfig,
   [IssueCategory.PERFORMANCE]: performanceConfig,
   [IssueCategory.PROFILE]: performanceConfig,
+  [IssueCategory.CRON]: performanceConfig,
 };
 
 const eventOccurrenceTypeToIssueCategory = (eventOccurrenceType: number) => {

+ 22 - 12
static/app/views/issueList/filters.spec.tsx

@@ -4,21 +4,20 @@ import IssueListFilters from 'sentry/views/issueList/filters';
 
 describe('IssueListFilters', () => {
   const onSearch = jest.fn();
-  const savedSearch = TestStubs.Search({
-    id: '789',
-    query: 'is:unresolved TypeError',
-    sort: 'date',
-    name: 'Unresolved TypeErrors',
-    projectId: 1,
-  });
+  const baseQuery = 'is:unresolved';
 
-  MockApiClient.addMockResponse({
-    method: 'GET',
-    url: '/organizations/org-slug/searches/',
-    body: [savedSearch],
+  beforeEach(() => {
+    MockApiClient.addMockResponse({
+      method: 'GET',
+      url: '/organizations/org-slug/searches/',
+      body: [],
+    });
   });
 
-  const baseQuery = 'is:unresolved';
+  afterEach(() => {
+    jest.clearAllMocks();
+    MockApiClient.clearMockResponses();
+  });
 
   it('should search the correct category when the IssueCategoryFilter dropdown is used', async () => {
     render(<IssueListFilters query={baseQuery} onSearch={onSearch} />);
@@ -70,4 +69,15 @@ describe('IssueListFilters', () => {
     rerender(<IssueListFilters query="" onSearch={onSearch} />);
     expect(filterDropdown).toHaveTextContent('All Categories');
   });
+
+  it('should filter by cron monitors', async () => {
+    render(<IssueListFilters query="" onSearch={onSearch} />, {
+      organization: TestStubs.Organization({features: ['issue-platform']}),
+    });
+
+    await userEvent.click(screen.getByRole('button', {name: 'All Categories'}));
+    await userEvent.click(screen.getByRole('option', {name: /Crons/}));
+
+    expect(onSearch).toHaveBeenCalledWith('issue.category:cron');
+  });
 });

+ 30 - 8
static/app/views/issueList/issueCategoryFilter.tsx

@@ -13,17 +13,20 @@ import useOrganization from 'sentry/utils/useOrganization';
 
 const ISSUE_CATEGORY_FILTER = 'issue.category';
 
-function IssueCategoryFilter({
-  query,
-  onSearch,
-}: {
+interface IssueCategoryFilterProps {
   onSearch: (query: string) => void;
   query: string;
-}) {
+}
+
+function IssueCategoryFilter({query, onSearch}: IssueCategoryFilterProps) {
   const [isPerformanceSeen, setIsPerformanceSeen] = useLocalStorageState(
     'issue-category-dropdown-seen:performance',
     false
   );
+  const [isCronSeen, setIsCronSeen] = useLocalStorageState(
+    'issue-category-dropdown-seen:crons',
+    false
+  );
   const organization = useOrganization();
 
   const renderLabel = useCallback(
@@ -38,11 +41,18 @@ function IssueCategoryFilter({
               {!isTriggerLabel && !isPerformanceSeen && <FeatureBadge type="new" />}
             </LabelWrapper>
           );
+        case IssueCategory.CRON:
+          return (
+            <LabelWrapper>
+              {t('Crons')}
+              {!isTriggerLabel && !isCronSeen && <FeatureBadge type="new" />}
+            </LabelWrapper>
+          );
         default:
           return <LabelWrapper>{t('All Categories')}</LabelWrapper>;
       }
     },
-    [isPerformanceSeen]
+    [isPerformanceSeen, isCronSeen]
   );
 
   const options = useMemo(
@@ -58,8 +68,17 @@ function IssueCategoryFilter({
         value: IssueCategory.PERFORMANCE,
         textValue: IssueCategory.PERFORMANCE,
       },
+      ...(organization.features.includes('issue-platform')
+        ? [
+            {
+              label: renderLabel(IssueCategory.CRON),
+              value: IssueCategory.CRON,
+              textValue: IssueCategory.CRON,
+            },
+          ]
+        : []),
     ],
-    [renderLabel]
+    [renderLabel, organization]
   );
 
   const [selectedOption, setSelectedOption] = useState<SelectOption<string>>(options[0]);
@@ -92,9 +111,12 @@ function IssueCategoryFilter({
       search.setFilterValues(ISSUE_CATEGORY_FILTER, [option.value]);
     }
 
-    if (option.value === 'performance') {
+    if (option.value === IssueCategory.PERFORMANCE) {
       setIsPerformanceSeen(true);
     }
+    if (option.value === IssueCategory.CRON) {
+      setIsCronSeen(true);
+    }
 
     trackAnalytics('issues_stream.issue_category_dropdown_changed', {
       organization,