Browse Source

feat(alerts): Add filter by name to alert rules (WOR-742) (#24658)

Scott Cooper 4 years ago
parent
commit
57995c07f7

+ 27 - 1
src/sentry/static/sentry/app/views/alerts/rules/index.tsx

@@ -13,6 +13,7 @@ import Link from 'app/components/links/link';
 import GlobalSelectionHeader from 'app/components/organizations/globalSelectionHeader';
 import Pagination from 'app/components/pagination';
 import {PanelTable, PanelTableHeader} from 'app/components/panels';
+import SearchBar from 'app/components/searchBar';
 import SentryDocumentTitle from 'app/components/sentryDocumentTitle';
 import {IconArrow, IconCheckmark} from 'app/icons';
 import {t, tct} from 'app/locale';
@@ -98,6 +99,17 @@ class AlertRulesList extends AsyncComponent<Props, State & AsyncComponent['state
     });
   };
 
+  handleChangeSearch = (name: string) => {
+    const {router, location} = this.props;
+    router.push({
+      pathname: location.pathname,
+      query: {
+        ...location.query,
+        name,
+      },
+    });
+  };
+
   handleDeleteRule = async (projectId: string, rule: IssueAlertRule) => {
     const {params} = this.props;
     const {orgId} = params;
@@ -172,6 +184,11 @@ class AlertRulesList extends AsyncComponent<Props, State & AsyncComponent['state
             </List>
           )}
         </Filter>
+        <StyledSearchBar
+          placeholder={t('Search by name')}
+          query={location.query?.name}
+          onSearch={this.handleChangeSearch}
+        />
       </FilterWrapper>
     );
   }
@@ -199,7 +216,10 @@ class AlertRulesList extends AsyncComponent<Props, State & AsyncComponent['state
     return (
       <StyledLayoutBody>
         <Layout.Main fullWidth>
-          <Feature features={['organizations:team-alerts-ownership']}>
+          <Feature
+            organization={organization}
+            features={['organizations:team-alerts-ownership']}
+          >
             {({hasFeature}) => (
               <React.Fragment>
                 {hasFeature && this.renderFilterBar()}
@@ -333,9 +353,15 @@ const TeamName = styled('div')`
 `;
 
 const FilterWrapper = styled('div')`
+  display: flex;
   margin-bottom: ${space(1.5)};
 `;
 
+const StyledSearchBar = styled(SearchBar)`
+  flex-grow: 1;
+  margin-left: ${space(1.5)};
+`;
+
 const List = styled('ul')`
   list-style: none;
   margin: 0;

+ 26 - 1
tests/js/spec/views/alerts/rules/index.spec.jsx

@@ -7,7 +7,7 @@ import ProjectsStore from 'app/stores/projectsStore';
 import AlertRulesList from 'app/views/alerts/rules';
 
 describe('OrganizationRuleList', () => {
-  const {routerContext, organization} = initializeOrg();
+  const {routerContext, organization, router} = initializeOrg();
   let rulesMock;
   let projectMock;
 
@@ -17,6 +17,7 @@ describe('OrganizationRuleList', () => {
         organization={organization}
         params={{orgId: organization.slug}}
         location={{query: {}, search: ''}}
+        router={router}
         {...props}
       />,
       routerContext
@@ -127,4 +128,28 @@ describe('OrganizationRuleList', () => {
     const addLink = wrapper.find('button[aria-label="Create Alert Rule"]');
     expect(addLink.props()['aria-disabled']).toBe(false);
   });
+
+  it('searches by name', async () => {
+    const ownershipOrg = {
+      ...organization,
+      features: ['team-alerts-ownership'],
+    };
+    const wrapper = await createWrapper({organization: ownershipOrg});
+    expect(wrapper.find('StyledSearchBar').exists()).toBe(true);
+
+    const testQuery = 'test name';
+    wrapper
+      .find('StyledSearchBar')
+      .find('input')
+      .simulate('change', {target: {value: testQuery}})
+      .simulate('submit', {preventDefault() {}});
+
+    expect(router.push).toHaveBeenCalledWith(
+      expect.objectContaining({
+        query: {
+          name: testQuery,
+        },
+      })
+    );
+  });
 });