Skip to content

Commit f927dbf

Browse files
authored
feat(workflow_engine): Add list of tags to help users define alerts (#103711)
# Description Currently we use a free form text field for the `tagged event` condition. We've had a few user issues that that the tagged event was configured on an event that hasn't been seen. This is only using the tags seen on error events; this is a bit closer to the intent of the condition and hope this clarifies the condition for the user. https://github.com/user-attachments/assets/d9acdf19-7584-4f0f-93c2-db5a54339145
1 parent c827797 commit f927dbf

File tree

4 files changed

+73
-8
lines changed

4 files changed

+73
-8
lines changed

static/app/views/automations/components/actionFilters/taggedEvent.tsx

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
import {useMemo} from 'react';
2+
3+
import {useFetchOrganizationTags} from 'sentry/actionCreators/tags';
14
import {AutomationBuilderInput} from 'sentry/components/workflowEngine/form/automationBuilderInput';
25
import {AutomationBuilderSelect} from 'sentry/components/workflowEngine/form/automationBuilderSelect';
36
import {t, tct} from 'sentry/locale';
47
import type {SelectValue} from 'sentry/types/core';
8+
import type {Tag} from 'sentry/types/group';
59
import type {DataCondition} from 'sentry/types/workflowEngine/dataConditions';
10+
import useOrganization from 'sentry/utils/useOrganization';
11+
import {Dataset} from 'sentry/views/alerts/rules/metric/types';
612
import {
713
MATCH_CHOICES,
814
type MatchType,
@@ -33,16 +39,54 @@ function KeyField() {
3339
const {condition, condition_id, onUpdate} = useDataConditionNodeContext();
3440
const {removeError} = useAutomationBuilderErrorContext();
3541

42+
// TODO - get form context, get the detector ids from the context.
43+
// if there are connected detectors / projects, then grab the project id list and use that. otherwise, -1.
44+
const projectIds = ['-1'];
45+
46+
// Select all the tags for an organization to generate a list of the most likely tags
47+
const organization = useOrganization();
48+
const {data: tagOptions = [], isLoading} = useFetchOrganizationTags(
49+
{
50+
orgSlug: organization.slug,
51+
projectIds,
52+
dataset: Dataset.ISSUE_PLATFORM,
53+
useCache: true,
54+
keepPreviousData: true,
55+
},
56+
{}
57+
);
58+
59+
const sortedOptions = useMemo(() => {
60+
const sorted = tagOptions.toSorted((a, b) => {
61+
return (a.totalValues || 0) > (b.totalValues || 0) ? -1 : 1;
62+
});
63+
64+
if (
65+
condition.comparison.key &&
66+
!sorted.some(tag => tag.key === condition.comparison.key)
67+
) {
68+
sorted.unshift(condition.comparison);
69+
}
70+
71+
return Object.values(sorted).map((tag: Tag) => ({
72+
value: tag.key,
73+
label: tag.key,
74+
}));
75+
}, [tagOptions, condition.comparison]);
76+
3677
return (
37-
<AutomationBuilderInput
78+
<AutomationBuilderSelect
79+
disabled={isLoading}
80+
creatable
3881
name={`${condition_id}.comparison.key`}
39-
placeholder={t('tag')}
40-
value={condition.comparison.key ?? ''}
41-
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
42-
onUpdate({comparison: {...condition.comparison, key: e.target.value}});
82+
aria-label={t('Tag')}
83+
placeholder={isLoading ? t('Loading tags\u2026') : t('tag')}
84+
value={condition.comparison.key}
85+
options={sortedOptions}
86+
onChange={(e: SelectValue<MatchType>) => {
87+
onUpdate({comparison: {...condition.comparison, key: e.value}});
4388
removeError(condition.id);
4489
}}
45-
aria-label={t('Tag')}
4690
/>
4791
);
4892
}

static/app/views/automations/components/dataConditionNodeList.spec.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ describe('DataConditionNodeList', () => {
9090

9191
beforeEach(() => {
9292
MockApiClient.clearMockResponses();
93+
MockApiClient.addMockResponse({
94+
url: `/organizations/${organization.slug}/tags/`,
95+
body: [],
96+
});
9397
MockApiClient.addMockResponse({
9498
url: `/organizations/${organization.slug}/data-conditions/`,
9599
body: dataConditionHandlers,
@@ -156,7 +160,9 @@ describe('DataConditionNodeList', () => {
156160
{organization}
157161
);
158162

159-
await userEvent.type(screen.getByRole('textbox', {name: 'Tag'}), 's');
163+
// Wait until the request for tags is completed
164+
const tagInput = await screen.findByRole('textbox', {name: 'Tag'});
165+
await userEvent.type(tagInput, 'names{enter}');
160166
expect(mockUpdateCondition).toHaveBeenCalledWith('1', {
161167
comparison: {key: 'names', match: MatchType.CONTAINS, value: 'moo deng'},
162168
});

static/app/views/automations/edit.spec.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ describe('EditAutomation', () => {
6666
body: {id: automation.createdBy, name: 'Test User'},
6767
});
6868

69+
// Mock the organization tags
70+
MockApiClient.addMockResponse({
71+
url: `/organizations/${organization.slug}/tags/`,
72+
method: 'GET',
73+
body: [],
74+
});
75+
6976
jest.mocked(useParams).mockReturnValue({
7077
automationId: automation.id,
7178
});

static/app/views/automations/new.spec.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ describe('AutomationNewSettings', () => {
4949
],
5050
});
5151

52+
// Mock the tags for an organization
53+
MockApiClient.addMockResponse({
54+
url: `/organizations/${organization.slug}/tags/`,
55+
method: 'GET',
56+
body: [],
57+
});
58+
5259
MockApiClient.addMockResponse({
5360
url: `/organizations/${organization.slug}/data-conditions/`,
5461
method: 'GET',
@@ -119,7 +126,8 @@ describe('AutomationNewSettings', () => {
119126
screen.getByRole('textbox', {name: 'Add filter'}),
120127
/tagged event/i
121128
);
122-
await userEvent.type(screen.getByRole('textbox', {name: 'Tag'}), 'env');
129+
const tagInput = await screen.findByRole('textbox', {name: 'Tag'});
130+
await userEvent.type(tagInput, 'env{enter}');
123131
await userEvent.type(screen.getByRole('textbox', {name: 'Value'}), 'prod');
124132

125133
// Add an action to the block (Slack), also updates the automatic naming

0 commit comments

Comments
 (0)