-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(alerts): Adds experimental EAP alerts as an option in the alerts…
… product (#79039) This change adds EAP Alerts as an option to the create alerts ui, so that we can enable testing of the experimental EAP dataset through the alerts and subscriptions flow. This is just for prototyping and there is no intention to ship this to GA as it currently is.
- Loading branch information
1 parent
5165f63
commit bb2d814
Showing
13 changed files
with
291 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {initializeOrg} from 'sentry-test/initializeOrg'; | ||
import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary'; | ||
|
||
import EAPField from 'sentry/views/alerts/rules/metric/eapField'; | ||
|
||
describe('EAPField', () => { | ||
it('renders', () => { | ||
const {project} = initializeOrg(); | ||
render( | ||
<EAPField | ||
aggregate={'count(span.duration)'} | ||
onChange={() => {}} | ||
project={project} | ||
/> | ||
); | ||
screen.getByText('count'); | ||
screen.getByText('span.duration'); | ||
}); | ||
|
||
it('should call onChange with the new aggregate string when switching aggregates', async () => { | ||
const {project} = initializeOrg(); | ||
const onChange = jest.fn(); | ||
render( | ||
<EAPField | ||
aggregate={'count(span.duration)'} | ||
onChange={onChange} | ||
project={project} | ||
/> | ||
); | ||
await userEvent.click(screen.getByText('count')); | ||
await userEvent.click(await screen.findByText('max')); | ||
await waitFor(() => expect(onChange).toHaveBeenCalledWith('max(span.duration)', {})); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import {useCallback, useEffect} from 'react'; | ||
import styled from '@emotion/styled'; | ||
|
||
import SelectControl from 'sentry/components/forms/controls/selectControl'; | ||
import {t} from 'sentry/locale'; | ||
import {space} from 'sentry/styles/space'; | ||
import type {Project} from 'sentry/types/project'; | ||
import {parseFunction} from 'sentry/utils/discover/fields'; | ||
import {ALLOWED_EXPLORE_VISUALIZE_AGGREGATES} from 'sentry/utils/fields'; | ||
|
||
export const DEFAULT_EAP_FIELD = 'span.duration'; | ||
export const DEFAULT_EAP_METRICS_ALERT_FIELD = `count(${DEFAULT_EAP_FIELD})`; | ||
|
||
interface Props { | ||
aggregate: string; | ||
onChange: (value: string, meta: Record<string, any>) => void; | ||
project: Project; | ||
} | ||
|
||
// Use the same aggregates/operations available in the explore view | ||
const OPERATIONS = [ | ||
...ALLOWED_EXPLORE_VISUALIZE_AGGREGATES.map(aggregate => ({ | ||
label: aggregate, | ||
value: aggregate, | ||
})), | ||
]; | ||
|
||
// TODD(edward): Just hardcode the EAP fields for now. We should use SpanTagsProvider in the future to match the Explore UI. | ||
const EAP_FIELD_OPTIONS = [ | ||
{ | ||
name: 'span.duration', | ||
}, | ||
{ | ||
name: 'span.self_time', | ||
}, | ||
]; | ||
|
||
function EAPField({aggregate, onChange}: Props) { | ||
// We parse out the aggregation and field from the aggregate string. | ||
// This only works for aggregates with <= 1 argument. | ||
const { | ||
name: aggregation, | ||
arguments: [field], | ||
} = parseFunction(aggregate) ?? {arguments: [undefined]}; | ||
|
||
useEffect(() => { | ||
const selectedMriMeta = EAP_FIELD_OPTIONS.find(metric => metric.name === field); | ||
if (field && !selectedMriMeta) { | ||
const newSelection = EAP_FIELD_OPTIONS[0]; | ||
if (newSelection) { | ||
onChange(`count(${newSelection.name})`, {}); | ||
} else if (aggregate !== DEFAULT_EAP_METRICS_ALERT_FIELD) { | ||
onChange(DEFAULT_EAP_METRICS_ALERT_FIELD, {}); | ||
} | ||
} | ||
}, [onChange, aggregate, aggregation, field]); | ||
|
||
const handleFieldChange = useCallback( | ||
option => { | ||
const selectedMeta = EAP_FIELD_OPTIONS.find(metric => metric.name === option.value); | ||
if (!selectedMeta) { | ||
return; | ||
} | ||
onChange(`${aggregation}(${option.value})`, {}); | ||
}, | ||
[onChange, aggregation] | ||
); | ||
|
||
const handleOperationChange = useCallback( | ||
option => { | ||
if (field) { | ||
onChange(`${option.value}(${field})`, {}); | ||
} else { | ||
onChange(`${option.value}(${DEFAULT_EAP_FIELD})`, {}); | ||
} | ||
}, | ||
[field, onChange] | ||
); | ||
|
||
// As SelectControl does not support an options size limit out of the box | ||
// we work around it by using the async variant of the control | ||
const getFieldOptions = useCallback((searchText: string) => { | ||
const filteredMeta = EAP_FIELD_OPTIONS.filter( | ||
({name}) => | ||
searchText === '' || name.toLowerCase().includes(searchText.toLowerCase()) | ||
); | ||
|
||
const options = filteredMeta.map(metric => { | ||
return { | ||
label: metric.name, | ||
value: metric.name, | ||
}; | ||
}); | ||
return options; | ||
}, []); | ||
|
||
// When using the async variant of SelectControl, we need to pass in an option object instead of just the value | ||
const selectedOption = field && { | ||
label: field, | ||
value: field, | ||
}; | ||
|
||
return ( | ||
<Wrapper> | ||
<StyledSelectControl | ||
searchable | ||
placeholder={t('Select an operation')} | ||
options={OPERATIONS} | ||
value={aggregation} | ||
onChange={handleOperationChange} | ||
/> | ||
<StyledSelectControl | ||
searchable | ||
placeholder={t('Select a metric')} | ||
noOptionsMessage={() => | ||
EAP_FIELD_OPTIONS.length === 0 | ||
? t('No metrics in this project') | ||
: t('No options') | ||
} | ||
async | ||
defaultOptions={getFieldOptions('')} | ||
loadOptions={searchText => Promise.resolve(getFieldOptions(searchText))} | ||
filterOption={() => true} | ||
value={selectedOption} | ||
onChange={handleFieldChange} | ||
/> | ||
</Wrapper> | ||
); | ||
} | ||
|
||
export default EAPField; | ||
|
||
const Wrapper = styled('div')` | ||
display: flex; | ||
gap: ${space(1)}; | ||
`; | ||
|
||
const StyledSelectControl = styled(SelectControl)` | ||
width: 200px; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.