Skip to content

Commit 8524738

Browse files
malwilleyandrewshie-sentry
authored andcommitted
feat(aci): Add search bar filtering to detector list page (#93251)
1 parent ac789cb commit 8524738

File tree

4 files changed

+123
-3
lines changed

4 files changed

+123
-3
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import {SearchQueryBuilder} from 'sentry/components/searchQueryBuilder';
2+
import {t} from 'sentry/locale';
3+
import type {TagCollection} from 'sentry/types/group';
4+
import type {FieldDefinition} from 'sentry/utils/fields';
5+
import {FieldKind} from 'sentry/utils/fields';
6+
import {useLocation} from 'sentry/utils/useLocation';
7+
import {useNavigate} from 'sentry/utils/useNavigate';
8+
import {DETECTOR_FILTER_KEYS} from 'sentry/views/detectors/constants';
9+
10+
function getDetectorFilterKeyDefinition(filterKey: string): FieldDefinition | null {
11+
if (DETECTOR_FILTER_KEYS.hasOwnProperty(filterKey) && DETECTOR_FILTER_KEYS[filterKey]) {
12+
const {description, valueType, keywords, values} = DETECTOR_FILTER_KEYS[filterKey];
13+
14+
return {
15+
kind: FieldKind.FIELD,
16+
desc: description,
17+
valueType,
18+
keywords,
19+
values,
20+
};
21+
}
22+
23+
return null;
24+
}
25+
26+
const FILTER_KEYS: TagCollection = Object.fromEntries(
27+
Object.keys(DETECTOR_FILTER_KEYS).map(key => {
28+
const {values} = DETECTOR_FILTER_KEYS[key] ?? {};
29+
30+
return [
31+
key,
32+
{
33+
key,
34+
name: key,
35+
predefined: values !== undefined,
36+
values,
37+
},
38+
];
39+
})
40+
);
41+
42+
export function DetectorSearch() {
43+
const location = useLocation();
44+
const navigate = useNavigate();
45+
const query = typeof location.query.query === 'string' ? location.query.query : '';
46+
47+
return (
48+
<SearchQueryBuilder
49+
initialQuery={query}
50+
placeholder={t('Search for monitors')}
51+
onSearch={searchQuery => {
52+
navigate({
53+
pathname: location.pathname,
54+
query: {
55+
...location.query,
56+
query: searchQuery,
57+
},
58+
});
59+
}}
60+
filterKeys={FILTER_KEYS}
61+
getTagValues={() => Promise.resolve([])}
62+
searchSource="detectors-list"
63+
fieldDefinitionGetter={getDetectorFilterKeyDefinition}
64+
disallowUnsupportedFilters
65+
disallowWildcard
66+
disallowLogicalOperators
67+
searchOnChange
68+
/>
69+
);
70+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,25 @@
1+
import {FieldValueType} from 'sentry/utils/fields';
2+
13
export const DETECTOR_LIST_PAGE_LIMIT = 25;
4+
5+
export const DETECTOR_FILTER_KEYS: Record<
6+
string,
7+
{
8+
description: string;
9+
keywords: string[];
10+
valueType: FieldValueType;
11+
values?: string[];
12+
}
13+
> = {
14+
name: {
15+
description: 'Name of the detector (exact match)',
16+
valueType: FieldValueType.STRING,
17+
keywords: ['title'],
18+
},
19+
type: {
20+
description: 'Type of the detector (error, metric_issue, etc)',
21+
valueType: FieldValueType.STRING,
22+
values: ['error', 'metric_issue', 'uptime_domain_failure'],
23+
keywords: ['type'],
24+
},
25+
};

static/app/views/detectors/list.spec.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {DetectorFixture} from 'sentry-fixture/detectors';
22
import {PageFiltersFixture} from 'sentry-fixture/pageFilters';
33
import {UserFixture} from 'sentry-fixture/user';
44

5-
import {render, screen} from 'sentry-test/reactTestingLibrary';
5+
import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
66

77
import PageFiltersStore from 'sentry/stores/pageFiltersStore';
88
import DetectorsList from 'sentry/views/detectors/list';
@@ -41,4 +41,30 @@ describe('DetectorsList', function () {
4141
})
4242
);
4343
});
44+
45+
describe('search', function () {
46+
it('can filter by type', async function () {
47+
const mockDetectorsRequestErrorType = MockApiClient.addMockResponse({
48+
url: '/organizations/org-slug/detectors/',
49+
body: [DetectorFixture({type: 'error', name: 'Error Detector'})],
50+
match: [MockApiClient.matchQuery({query: 'type:error'})],
51+
});
52+
53+
render(<DetectorsList />);
54+
await screen.findByText('Detector 1');
55+
56+
// Click through menus to select type:error
57+
await userEvent.click(screen.getByRole('combobox', {name: 'Add a search term'}));
58+
await userEvent.click(await screen.findByRole('option', {name: 'type'}));
59+
const options = await screen.findAllByRole('option');
60+
expect(options).toHaveLength(3);
61+
expect(options[0]).toHaveTextContent('error');
62+
expect(options[1]).toHaveTextContent('metric_issue');
63+
expect(options[2]).toHaveTextContent('uptime_domain_failure');
64+
await userEvent.click(screen.getByText('error'));
65+
66+
await screen.findByText('Error Detector');
67+
expect(mockDetectorsRequestErrorType).toHaveBeenCalled();
68+
});
69+
});
4470
});

static/app/views/detectors/list.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {Flex} from 'sentry/components/container/flex';
44
import {LinkButton} from 'sentry/components/core/button/linkButton';
55
import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
66
import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter';
7-
import SearchBar from 'sentry/components/searchBar';
87
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
98
import {ActionsProvider} from 'sentry/components/workflowEngine/layout/actions';
109
import ListLayout from 'sentry/components/workflowEngine/layout/list';
@@ -16,6 +15,7 @@ import {useLocation} from 'sentry/utils/useLocation';
1615
import useOrganization from 'sentry/utils/useOrganization';
1716
import usePageFilters from 'sentry/utils/usePageFilters';
1817
import DetectorListTable from 'sentry/views/detectors/components/detectorListTable';
18+
import {DetectorSearch} from 'sentry/views/detectors/components/detectorSearch';
1919
import {useDetectorsQuery} from 'sentry/views/detectors/hooks';
2020
import {makeMonitorBasePathname} from 'sentry/views/detectors/pathnames';
2121

@@ -55,7 +55,7 @@ function TableHeader() {
5555
<Flex gap={space(2)}>
5656
<ProjectPageFilter />
5757
<div style={{flexGrow: 1}}>
58-
<SearchBar placeholder={t('Search for events, users, tags, and more')} />
58+
<DetectorSearch />
5959
</div>
6060
</Flex>
6161
);

0 commit comments

Comments
 (0)