Skip to content

Commit 0a508c6

Browse files
feat(prevent): Add logaf sensitivity dropdown to ai config (#101040)
(cherry picked from commit 8580194)
1 parent 75641c2 commit 0a508c6

File tree

6 files changed

+145
-38
lines changed

6 files changed

+145
-38
lines changed

static/app/types/prevent.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Add any new providers here e.g., 'github' | 'bitbucket' | 'gitlab'
22
export type PreventAIProvider = 'github';
33

4+
export type Sensitivity = 'low' | 'medium' | 'high' | 'critical';
5+
46
interface PreventAIRepo {
57
fullName: string;
68
id: string;
@@ -18,7 +20,7 @@ export interface PreventAIOrg {
1820
interface PreventAIFeatureConfig {
1921
enabled: boolean;
2022
triggers: PreventAIFeatureTriggers;
21-
sensitivity?: string;
23+
sensitivity?: Sensitivity;
2224
}
2325

2426
export interface PreventAIFeatureTriggers {

static/app/views/prevent/preventAI/hooks/useUpdatePreventAIFeature.spec.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ describe('useUpdatePreventAIFeature', () => {
2525
test_generation: {
2626
enabled: false,
2727
triggers: {on_command_phrase: false, on_ready_for_review: false},
28-
sensitivity: 'medium',
2928
},
3029
bug_prediction: {
3130
enabled: false,
@@ -46,7 +45,6 @@ describe('useUpdatePreventAIFeature', () => {
4645
test_generation: {
4746
enabled: false,
4847
triggers: {on_command_phrase: false, on_ready_for_review: false},
49-
sensitivity: 'medium',
5048
},
5149
bug_prediction: {
5250
enabled: false,
@@ -193,19 +191,19 @@ describe('useUpdatePreventAIFeature', () => {
193191
expect(feature?.triggers.on_ready_for_review).toBe(true);
194192
});
195193

196-
it('should preserve sensitivity', () => {
194+
it('should update sensitivity', () => {
197195
const config = structuredClone(mockOrg.preventAiConfigGithub!);
198196
const updatedConfig = makePreventAIConfig(config, {
199197
feature: 'bug_prediction',
200-
enabled: false,
198+
enabled: true,
201199
orgName: 'org-1',
202200
repoName: 'repo-xyz',
203-
trigger: {on_ready_for_review: true},
201+
sensitivity: 'low',
204202
});
205203
const feature =
206204
updatedConfig.github_organizations?.['org-1']?.repo_overrides?.['repo-xyz']
207205
?.bug_prediction;
208-
expect(feature?.sensitivity).toBe('medium');
206+
expect(feature?.sensitivity).toBe('low');
209207
});
210208
});
211209
});

static/app/views/prevent/preventAI/hooks/useUpdatePreventAIFeature.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import {updateOrganization} from 'sentry/actionCreators/organizations';
22
import type {Organization} from 'sentry/types/organization';
3-
import type {PreventAIConfig, PreventAIFeatureTriggers} from 'sentry/types/prevent';
3+
import type {
4+
PreventAIConfig,
5+
PreventAIFeatureTriggers,
6+
Sensitivity,
7+
} from 'sentry/types/prevent';
48
import {fetchMutation, useMutation} from 'sentry/utils/queryClient';
59
import useOrganization from 'sentry/utils/useOrganization';
610

@@ -10,6 +14,7 @@ interface UpdatePreventAIFeatureParams {
1014
orgName: string;
1115
// if repoName is provided, edit repo_overrides for that repo, otherwise edit org_defaults
1216
repoName?: string;
17+
sensitivity?: Sensitivity;
1318
trigger?: Partial<PreventAIFeatureTriggers>;
1419
}
1520

@@ -73,7 +78,7 @@ export function makePreventAIConfig(
7378
featureConfig[params.feature] = {
7479
enabled: params.enabled,
7580
triggers: {...featureConfig[params.feature].triggers, ...params.trigger},
76-
sensitivity: featureConfig[params.feature].sensitivity,
81+
sensitivity: params.sensitivity ?? featureConfig[params.feature].sensitivity,
7782
};
7883

7984
return updatedConfig;

static/app/views/prevent/preventAI/manageReposPanel.spec.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe('ManageReposPanel', () => {
3535
bug_prediction: {
3636
enabled: true,
3737
triggers: {on_command_phrase: true, on_ready_for_review: false},
38+
sensitivity: 'medium',
3839
},
3940
test_generation: {
4041
enabled: false,
@@ -43,6 +44,7 @@ describe('ManageReposPanel', () => {
4344
vanilla: {
4445
enabled: true,
4546
triggers: {on_command_phrase: false, on_ready_for_review: false},
47+
sensitivity: 'medium',
4648
},
4749
},
4850
repo_overrides: {},
@@ -69,9 +71,9 @@ describe('ManageReposPanel', () => {
6971

7072
it('shows feature toggles with correct initial state', async () => {
7173
render(<ManageReposPanel {...defaultProps} />, {organization: mockOrganization});
72-
expect(await screen.findByLabelText(/PR Review/i)).toBeChecked();
73-
expect(await screen.findByLabelText(/Test Generation/i)).not.toBeChecked();
74-
expect(await screen.findByLabelText(/Error Prediction/i)).toBeChecked();
74+
expect(await screen.findByLabelText(/Enable PR Review/i)).toBeChecked();
75+
expect(await screen.findByLabelText(/Enable Test Generation/i)).not.toBeChecked();
76+
expect(await screen.findByLabelText(/Enable Error Prediction/i)).toBeChecked();
7577
expect(
7678
await screen.findByLabelText(/Auto Run on Opened Pull Requests/i)
7779
).not.toBeChecked();
@@ -84,9 +86,9 @@ describe('ManageReposPanel', () => {
8486
isLoading: true,
8587
};
8688
render(<ManageReposPanel {...defaultProps} />, {organization: mockOrganization});
87-
expect(await screen.findByLabelText(/PR Review/i)).toBeDisabled();
88-
expect(await screen.findByLabelText(/Test Generation/i)).toBeDisabled();
89-
expect(await screen.findByLabelText(/Error Prediction/i)).toBeDisabled();
89+
expect(await screen.findByLabelText(/Enable PR Review/i)).toBeDisabled();
90+
expect(await screen.findByLabelText(/Enable Test Generation/i)).toBeDisabled();
91+
expect(await screen.findByLabelText(/Enable Error Prediction/i)).toBeDisabled();
9092
});
9193

9294
it('shows error message if updateError is present', async () => {
@@ -99,6 +101,22 @@ describe('ManageReposPanel', () => {
99101
expect(await screen.findByText(/Could not update settings/i)).toBeInTheDocument();
100102
});
101103

104+
it('shows sensitivity options when feature is enabled', async () => {
105+
render(<ManageReposPanel {...defaultProps} />, {organization: mockOrganization});
106+
const prReviewCheckbox = await screen.findByLabelText(/Enable PR Review/i);
107+
const errorPredictionCheckbox = await screen.findByLabelText(
108+
/Enable Error Prediction/i
109+
);
110+
expect(prReviewCheckbox).toBeChecked();
111+
expect(errorPredictionCheckbox).toBeChecked();
112+
expect(
113+
await screen.findByTestId(/pr-review-sensitivity-dropdown/i)
114+
).toBeInTheDocument();
115+
expect(
116+
await screen.findByTestId(/error-prediction-sensitivity-dropdown/i)
117+
).toBeInTheDocument();
118+
});
119+
102120
describe('getRepoConfig', () => {
103121
it('returns repo override config when present', () => {
104122
const orgConfig: PreventAIOrgConfig = {

static/app/views/prevent/preventAI/manageReposPanel.tsx

Lines changed: 102 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {Alert} from 'sentry/components/core/alert';
22
import {Button} from 'sentry/components/core/button';
3+
import {CompactSelect} from 'sentry/components/core/compactSelect';
34
import {Flex} from 'sentry/components/core/layout';
45
import {ExternalLink} from 'sentry/components/core/link';
56
import {Switch} from 'sentry/components/core/switch';
@@ -9,7 +10,7 @@ import SlideOverPanel from 'sentry/components/slideOverPanel';
910
import {IconClose} from 'sentry/icons';
1011
import {t, tct} from 'sentry/locale';
1112
import {type PreventAIOrgConfig} from 'sentry/types/prevent';
12-
import type {PreventAIFeatureConfigsByName} from 'sentry/types/prevent';
13+
import type {PreventAIFeatureConfigsByName, Sensitivity} from 'sentry/types/prevent';
1314
import useOrganization from 'sentry/utils/useOrganization';
1415
import {useUpdatePreventAIFeature} from 'sentry/views/prevent/preventAI/hooks/useUpdatePreventAIFeature';
1516

@@ -20,6 +21,31 @@ interface ManageReposPanelProps {
2021
repoName: string;
2122
}
2223

24+
interface SensitivityOption {
25+
details: string;
26+
label: string;
27+
value: Sensitivity;
28+
}
29+
30+
const sensitivityOptions: SensitivityOption[] = [
31+
{value: 'low', label: 'Low', details: 'Post all potential issues for maximum breadth.'},
32+
{
33+
value: 'medium',
34+
label: 'Medium',
35+
details: 'Post likely issues for a balance of thoroughness and noise.',
36+
},
37+
{
38+
value: 'high',
39+
label: 'High',
40+
details: 'Post only major issues to highlight most impactful findings.',
41+
},
42+
{
43+
value: 'critical',
44+
label: 'Critical',
45+
details: 'Post only high-impact, high-sensitivity issues for maximum focus.',
46+
},
47+
];
48+
2349
function ManageReposPanel({
2450
collapsed,
2551
onClose,
@@ -111,9 +137,9 @@ function ManageReposPanel({
111137
justify="between"
112138
>
113139
<Flex direction="column" gap="sm">
114-
<Text size="md">Enable PR Review</Text>
140+
<Text size="md">{t('Enable PR Review')}</Text>
115141
<Text variant="muted" size="sm">
116-
Run when @sentry review is commented on a PR.
142+
{t('Run when @sentry review is commented on a PR.')}
117143
</Text>
118144
</Flex>
119145
<Switch
@@ -132,6 +158,41 @@ function ManageReposPanel({
132158
aria-label="Enable PR Review"
133159
/>
134160
</Flex>
161+
{repoConfig.vanilla.enabled && (
162+
<Flex paddingLeft="xl" direction="column">
163+
<Flex direction="column" borderLeft="muted" paddingLeft="md">
164+
<FieldGroup
165+
label={<Text size="md">{t('Sensitivity')}</Text>}
166+
help={
167+
<Text size="xs" variant="muted">
168+
{t('Set the sensitivity level for PR review analysis.')}
169+
</Text>
170+
}
171+
alignRight
172+
flexibleControlStateSize
173+
>
174+
<CompactSelect
175+
value={repoConfig.vanilla.sensitivity ?? 'medium'}
176+
options={sensitivityOptions}
177+
disabled={isLoading || !canEditSettings}
178+
onChange={async option =>
179+
await enableFeature({
180+
feature: 'vanilla',
181+
enabled: true,
182+
orgName,
183+
repoName,
184+
sensitivity: option.value,
185+
})
186+
}
187+
aria-label="PR Review Sensitivity"
188+
menuWidth={350}
189+
maxMenuWidth={500}
190+
data-test-id="pr-review-sensitivity-dropdown"
191+
/>
192+
</FieldGroup>
193+
</Flex>
194+
</Flex>
195+
)}
135196
</Flex>
136197

137198
{/* Test Generation Feature */}
@@ -145,9 +206,9 @@ function ManageReposPanel({
145206
justify="between"
146207
>
147208
<Flex direction="column" gap="sm">
148-
<Text size="md">Enable Test Generation</Text>
209+
<Text size="md">{t('Enable Test Generation')}</Text>
149210
<Text variant="muted" size="sm">
150-
Run when @sentry generate-test is commented on a PR.
211+
{t('Run when @sentry generate-test is commented on a PR.')}
151212
</Text>
152213
</Flex>
153214
<Switch
@@ -179,9 +240,9 @@ function ManageReposPanel({
179240
justify="between"
180241
>
181242
<Flex direction="column" gap="sm">
182-
<Text size="md">Enable Error Prediction</Text>
243+
<Text size="md">{t('Enable Error Prediction')}</Text>
183244
<Text variant="muted" size="sm">
184-
Allow organization members to review potential bugs.
245+
{t('Allow organization members to review potential bugs.')}
185246
</Text>
186247
</Flex>
187248
<Switch
@@ -190,7 +251,6 @@ function ManageReposPanel({
190251
disabled={isLoading || !canEditSettings}
191252
onChange={async () => {
192253
const newValue = !repoConfig.bug_prediction.enabled;
193-
// Enable/disable the main bug prediction feature
194254
await enableFeature({
195255
feature: 'bug_prediction',
196256
enabled: newValue,
@@ -202,23 +262,45 @@ function ManageReposPanel({
202262
/>
203263
</Flex>
204264
{repoConfig.bug_prediction.enabled && (
205-
// width 150% because FieldGroup > FieldDescription has fixed width 50%
206-
<Flex paddingLeft="xl" width="150%">
207-
<Flex
208-
direction="column"
209-
borderLeft="muted"
210-
radius="md"
211-
paddingLeft="md"
212-
width="100%"
213-
>
265+
<Flex paddingLeft="xl" direction="column">
266+
<Flex direction="column" borderLeft="muted" paddingLeft="md">
267+
<FieldGroup
268+
label={<Text size="md">{t('Sensitivity')}</Text>}
269+
help={
270+
<Text size="xs" variant="muted">
271+
{t('Set the sensitivity level for error prediction.')}
272+
</Text>
273+
}
274+
alignRight
275+
flexibleControlStateSize
276+
>
277+
<CompactSelect
278+
value={repoConfig.bug_prediction.sensitivity ?? 'medium'}
279+
options={sensitivityOptions}
280+
disabled={isLoading || !canEditSettings}
281+
onChange={async option =>
282+
await enableFeature({
283+
feature: 'bug_prediction',
284+
enabled: true,
285+
orgName,
286+
repoName,
287+
sensitivity: option.value,
288+
})
289+
}
290+
aria-label="Error Prediction Sensitivity"
291+
menuWidth={350}
292+
maxMenuWidth={500}
293+
data-test-id="error-prediction-sensitivity-dropdown"
294+
/>
295+
</FieldGroup>
214296
<FieldGroup
215297
label={<Text size="md">{t('Auto Run on Opened Pull Requests')}</Text>}
216298
help={
217299
<Text size="xs" variant="muted">
218300
{t('Run when a PR is published, ignoring new pushes.')}
219301
</Text>
220302
}
221-
inline
303+
alignRight
222304
flexibleControlStateSize
223305
>
224306
<Switch
@@ -243,10 +325,10 @@ function ManageReposPanel({
243325
label={<Text size="md">{t('Run When Mentioned')}</Text>}
244326
help={
245327
<Text size="xs" variant="muted">
246-
{t('Run when @sentry review is commented on a PR')}
328+
{t('Run when @sentry review is commented on a PR.')}
247329
</Text>
248330
}
249-
inline
331+
alignRight
250332
flexibleControlStateSize
251333
>
252334
<Switch

tests/js/fixtures/prevent.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type {Sensitivity} from 'sentry/types/prevent';
2+
13
export function PreventAIConfigFixture() {
24
return {
35
schema_version: 'v1',
@@ -7,17 +9,17 @@ export function PreventAIConfigFixture() {
79
bug_prediction: {
810
enabled: false,
911
triggers: {on_command_phrase: false, on_ready_for_review: false},
10-
sensitivity: 'medium',
12+
sensitivity: 'medium' as Sensitivity,
1113
},
1214
test_generation: {
1315
enabled: false,
1416
triggers: {on_command_phrase: false, on_ready_for_review: false},
15-
sensitivity: 'medium',
17+
sensitivity: 'medium' as Sensitivity,
1618
},
1719
vanilla: {
1820
enabled: false,
1921
triggers: {on_command_phrase: false, on_ready_for_review: false},
20-
sensitivity: 'medium',
22+
sensitivity: 'medium' as Sensitivity,
2123
},
2224
},
2325
repo_overrides: {},

0 commit comments

Comments
 (0)