Skip to content

Commit 23ad31f

Browse files
authored
feat(seer): Disable all the Generate code buttons in Seer UI (#107454)
| Area | Img | | --- | --- | | New label | <img width="591" height="234" alt="Screenshot 2026-02-02 at 2 27 10 PM" src="https://github.com/user-attachments/assets/b58003e3-9a4a-4eaa-845c-3313c092e371" /> | prev starting autofix | <img width="405" height="230" alt="Screenshot 2026-02-02 at 3 18 43 PM" src="https://github.com/user-attachments/assets/1c40c426-11c6-4204-b362-d99721329893" /> | prev moving from solution to fix | <img width="360" height="147" alt="Screenshot 2026-02-02 at 3 07 55 PM" src="https://github.com/user-attachments/assets/b5f73878-a7a4-4382-bd21-7dd3c754e3a9" /> Fixes https://linear.app/getsentry/issue/CW-735/disable-code-it-up-aka-write-a-code-fix-buttons-in-autofix-ui-if-the
1 parent 488ab37 commit 23ad31f

File tree

4 files changed

+169
-93
lines changed

4 files changed

+169
-93
lines changed

static/app/components/events/autofix/autofixSolution.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,7 @@ function AutofixSolutionDisplay({
390390

391391
const hasNoRepos = repos.length === 0;
392392
const cantReadRepos = repos.every(repo => repo.is_readable === false);
393-
const codingDisabled =
394-
organization.enableSeerCoding === undefined ? false : !organization.enableSeerCoding;
393+
const enableSeerCoding = organization.enableSeerCoding !== false;
395394

396395
const handleAddInstruction = () => {
397396
if (instructions.trim()) {
@@ -622,11 +621,8 @@ function AutofixSolutionDisplay({
622621
<Tooltip
623622
isHoverable
624623
title={
625-
codingDisabled
626-
? t(
627-
'Your organization has disabled code generation with Seer. This can be re-enabled in organization settings by an admin.'
628-
)
629-
: hasNoRepos
624+
enableSeerCoding
625+
? hasNoRepos
630626
? tct(
631627
'Seer needs to be able to access your repos to write code for you. [link:Manage your integration and working repos here.]',
632628
{
@@ -642,6 +638,16 @@ function AutofixSolutionDisplay({
642638
"Seer can't access any of your selected repos. Check your GitHub integration and make sure Seer has read access."
643639
)
644640
: undefined
641+
: tct(
642+
'[settings:"Enable Code Generation"] must be enabled by an admin in settings.',
643+
{
644+
settings: (
645+
<Link
646+
to={`/settings/${organization.slug}/seer/#enableSeerCoding`}
647+
/>
648+
),
649+
}
650+
)
645651
}
646652
>
647653
<Button
@@ -652,7 +658,7 @@ function AutofixSolutionDisplay({
652658
: 'default'
653659
}
654660
busy={isPending}
655-
disabled={hasNoRepos || cantReadRepos || codingDisabled}
661+
disabled={hasNoRepos || cantReadRepos || !enableSeerCoding}
656662
onClick={handleCodeItUp}
657663
analyticsEventName="Autofix: Code It Up"
658664
analyticsEventKey="autofix.solution.code"

static/app/components/events/autofix/autofixStartBox.tsx

Lines changed: 93 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,78 @@ import starImage from 'sentry-images/spot/banner-star.svg';
55

66
import {Button, ButtonBar} from '@sentry/scraps/button';
77
import {Flex} from '@sentry/scraps/layout';
8+
import {Link} from '@sentry/scraps/link';
89
import {TextArea} from '@sentry/scraps/textarea';
10+
import {Tooltip} from '@sentry/scraps/tooltip';
911

1012
import {DropdownMenu} from 'sentry/components/dropdownMenu';
1113
import {AutofixStoppingPoint} from 'sentry/components/events/autofix/types';
1214
import {IconArrow, IconChevron, IconSeer} from 'sentry/icons';
13-
import {t} from 'sentry/locale';
15+
import {t, tct} from 'sentry/locale';
1416
import {space} from 'sentry/styles/space';
17+
import type {Organization} from 'sentry/types/organization';
1518
import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
19+
import useOrganization from 'sentry/utils/useOrganization';
1620

1721
interface AutofixStartBoxProps {
1822
groupId: string;
1923
onSend: (message: string, stoppingPoint?: AutofixStoppingPoint) => void;
2024
}
2125

22-
const STOPPING_POINT_OPTIONS = [
23-
{
24-
key: AutofixStoppingPoint.ROOT_CAUSE,
25-
label: t('Start Root Cause Analysis'),
26-
value: AutofixStoppingPoint.ROOT_CAUSE,
27-
},
28-
{
29-
key: AutofixStoppingPoint.SOLUTION,
30-
label: t('Plan a Solution'),
31-
value: AutofixStoppingPoint.SOLUTION,
32-
},
33-
{
34-
key: AutofixStoppingPoint.CODE_CHANGES,
35-
label: t('Write Code Changes'),
36-
value: AutofixStoppingPoint.CODE_CHANGES,
37-
},
38-
{
39-
key: AutofixStoppingPoint.OPEN_PR,
40-
label: t('Draft a Pull Request'),
41-
value: AutofixStoppingPoint.OPEN_PR,
42-
},
43-
] as const;
26+
function getStoppingPointOptions(organization: Organization) {
27+
const enableSeerCoding = organization.enableSeerCoding !== false;
28+
return [
29+
{
30+
key: AutofixStoppingPoint.ROOT_CAUSE,
31+
label: t('Start Root Cause Analysis'),
32+
value: AutofixStoppingPoint.ROOT_CAUSE,
33+
disabled: false,
34+
tooltip: undefined,
35+
},
36+
{
37+
key: AutofixStoppingPoint.SOLUTION,
38+
label: t('Plan a Solution'),
39+
value: AutofixStoppingPoint.SOLUTION,
40+
disabled: false,
41+
tooltip: undefined,
42+
},
43+
{
44+
key: AutofixStoppingPoint.CODE_CHANGES,
45+
label: t('Write Code Changes'),
46+
value: AutofixStoppingPoint.CODE_CHANGES,
47+
disabled: !enableSeerCoding,
48+
tooltip: enableSeerCoding
49+
? undefined
50+
: tct(
51+
'[settings:"Enable Code Generation"] must be enabled by an admin in settings.',
52+
{
53+
settings: (
54+
<Link to={`/settings/${organization.slug}/seer/#enableSeerCoding`} />
55+
),
56+
}
57+
),
58+
},
59+
{
60+
key: AutofixStoppingPoint.OPEN_PR,
61+
label: t('Draft a Pull Request'),
62+
value: AutofixStoppingPoint.OPEN_PR,
63+
disabled: !enableSeerCoding,
64+
tooltip: enableSeerCoding
65+
? undefined
66+
: tct(
67+
'[settings:"Enable Code Generation"] must be enabled by an admin in settings.',
68+
{
69+
settings: (
70+
<Link to={`/settings/${organization.slug}/seer/#enableSeerCoding`} />
71+
),
72+
}
73+
),
74+
},
75+
] as const;
76+
}
4477

4578
export function AutofixStartBox({onSend, groupId}: AutofixStartBoxProps) {
79+
const organization = useOrganization();
4680
const [message, setMessage] = useState('');
4781
const [selectedStoppingPoint, setSelectedStoppingPoint] =
4882
useLocalStorageState<AutofixStoppingPoint>(
@@ -61,19 +95,21 @@ export function AutofixStartBox({onSend, groupId}: AutofixStartBoxProps) {
6195
);
6296

6397
const {primaryOption, dropdownOptions} = useMemo(() => {
98+
const options = getStoppingPointOptions(organization);
6499
const primary =
65-
STOPPING_POINT_OPTIONS.find(opt => opt.value === selectedStoppingPoint) ??
66-
STOPPING_POINT_OPTIONS[0];
67-
const dropdown = STOPPING_POINT_OPTIONS.filter(
68-
opt => opt.value !== selectedStoppingPoint
69-
).map(opt => ({
70-
key: opt.key,
71-
label: opt.label,
72-
onAction: () =>
73-
handleSubmit({preventDefault: () => {}} as React.FormEvent, opt.value),
74-
}));
100+
options.find(opt => opt.value === selectedStoppingPoint) ?? options[0];
101+
const dropdown = options
102+
.filter(opt => opt.value !== selectedStoppingPoint)
103+
.map(opt => ({
104+
key: opt.key,
105+
label: opt.label,
106+
disabled: opt.disabled ?? false,
107+
tooltip: opt.tooltip,
108+
onAction: () =>
109+
handleSubmit({preventDefault: () => {}} as React.FormEvent, opt.value),
110+
}));
75111
return {primaryOption: primary, dropdownOptions: dropdown};
76-
}, [selectedStoppingPoint, handleSubmit]);
112+
}, [organization, selectedStoppingPoint, handleSubmit]);
77113

78114
return (
79115
<Wrapper>
@@ -132,23 +168,30 @@ export function AutofixStartBox({onSend, groupId}: AutofixStartBoxProps) {
132168
size="sm"
133169
/>
134170
<ButtonBar merged gap="0">
135-
<StyledButton
136-
type="submit"
137-
priority="primary"
138-
analyticsEventKey={
139-
message
140-
? 'autofix.give_instructions_clicked'
141-
: 'autofix.start_fix_clicked'
142-
}
143-
analyticsEventName={
144-
message
145-
? 'Autofix: Give Instructions Clicked'
146-
: 'Autofix: Start Fix Clicked'
147-
}
148-
analyticsParams={{group_id: groupId}}
171+
<Tooltip
172+
title={primaryOption.tooltip}
173+
skipWrapper
174+
disabled={!primaryOption.disabled}
149175
>
150-
{primaryOption.label}
151-
</StyledButton>
176+
<StyledButton
177+
type="submit"
178+
priority="primary"
179+
disabled={primaryOption.disabled}
180+
analyticsEventKey={
181+
message
182+
? 'autofix.give_instructions_clicked'
183+
: 'autofix.start_fix_clicked'
184+
}
185+
analyticsEventName={
186+
message
187+
? 'Autofix: Give Instructions Clicked'
188+
: 'Autofix: Start Fix Clicked'
189+
}
190+
analyticsParams={{group_id: groupId}}
191+
>
192+
{primaryOption.label}
193+
</StyledButton>
194+
</Tooltip>
152195
<DropdownMenu
153196
items={dropdownOptions}
154197
trigger={(triggerProps, isOpen) => (

static/app/components/events/autofix/autofixSteps.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ function Step({
152152

153153
export function AutofixSteps({data, groupId, runId, event}: AutofixStepsProps) {
154154
const organization = useOrganization();
155-
const codingDisabled =
156-
organization.enableSeerCoding === undefined ? false : !organization.enableSeerCoding;
155+
const enableSeerCoding = organization.enableSeerCoding !== false;
156+
157157
const steps = data.steps;
158158
const isMountedRef = useRef<boolean>(false);
159159
const {repos} = useAutofixRepos(groupId);
@@ -221,8 +221,8 @@ export function AutofixSteps({data, groupId, runId, event}: AutofixStepsProps) {
221221
.slice(0, index)
222222
.some(s => s.type === AutofixStepType.SOLUTION);
223223
const hideStep =
224-
(codingDisabled && hasSolutionStepBefore) ||
225-
(codingDisabled && step.type === AutofixStepType.CHANGES);
224+
(!enableSeerCoding && hasSolutionStepBefore) ||
225+
(!enableSeerCoding && step.type === AutofixStepType.CHANGES);
226226

227227
const previousStep = index > 0 ? steps[index - 1] : null;
228228
const previousStepErrored =

static/app/components/events/autofix/v2/nextSteps.tsx

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import {AnimatePresence, motion} from 'framer-motion';
44

55
import {Button, ButtonBar} from '@sentry/scraps/button';
66
import {Container, Flex} from '@sentry/scraps/layout';
7+
import {Link} from '@sentry/scraps/link';
78
import {Text} from '@sentry/scraps/text';
9+
import {Tooltip} from '@sentry/scraps/tooltip';
810

911
import {addLoadingMessage, clearIndicators} from 'sentry/actionCreators/indicator';
1012
import {DropdownMenu} from 'sentry/components/dropdownMenu';
@@ -15,8 +17,9 @@ import {
1517
import type {AutofixExplorerStep} from 'sentry/components/events/autofix/useExplorerAutofix';
1618
import {cardAnimationProps} from 'sentry/components/events/autofix/v2/utils';
1719
import {IconChat, IconChevron} from 'sentry/icons';
18-
import {t} from 'sentry/locale';
20+
import {t, tct} from 'sentry/locale';
1921
import {PluginIcon} from 'sentry/plugins/components/pluginIcon';
22+
import useOrganization from 'sentry/utils/useOrganization';
2023
import type {Artifact} from 'sentry/views/seerExplorer/types';
2124

2225
const STEP_LABELS: Record<AutofixExplorerStep, string> = {
@@ -126,19 +129,33 @@ function StepButton({
126129
isLoading?: boolean;
127130
onCodingAgentHandoff?: (integration: CodingAgentIntegration) => void;
128131
}) {
132+
const organization = useOrganization();
133+
const enableSeerCoding = organization.enableSeerCoding !== false;
129134
const priority = index === 0 ? 'primary' : 'default';
130135

131136
// Only show dropdown for code_changes step when integrations are available
132137
if (step !== 'code_changes' || !codingAgentIntegrations?.length) {
133138
return (
134-
<Button
135-
onClick={onStepClick}
136-
disabled={isLoading}
137-
busy={isBusy}
138-
priority={priority}
139+
<Tooltip
140+
disabled={enableSeerCoding}
141+
title={tct(
142+
'[settings:"Enable Code Generation"] must be enabled for Seer to create pull requests.',
143+
{
144+
settings: (
145+
<Link to={`/settings/${organization.slug}/seer/#enableSeerCoding`} />
146+
),
147+
}
148+
)}
139149
>
140-
{STEP_LABELS[step]}
141-
</Button>
150+
<Button
151+
onClick={onStepClick}
152+
disabled={isLoading || (step === 'code_changes' && !enableSeerCoding)}
153+
busy={isBusy}
154+
priority={priority}
155+
>
156+
{STEP_LABELS[step]}
157+
</Button>
158+
</Tooltip>
142159
);
143160
}
144161

@@ -170,29 +187,39 @@ function StepButton({
170187
});
171188

172189
return (
173-
<ButtonBar merged gap="0">
174-
<Button
175-
onClick={onStepClick}
176-
disabled={isLoading}
177-
busy={isBusy}
178-
priority={priority}
179-
>
180-
{STEP_LABELS[step]}
181-
</Button>
182-
<DropdownMenu
183-
items={dropdownItems}
184-
trigger={(triggerProps, isOpen) => (
185-
<DropdownTrigger
186-
{...triggerProps}
187-
disabled={isLoading}
188-
priority={priority}
189-
icon={<IconChevron direction={isOpen ? 'up' : 'down'} size="xs" />}
190-
aria-label={t('More code fix options')}
191-
/>
192-
)}
193-
position="bottom-end"
194-
/>
195-
</ButtonBar>
190+
<Tooltip
191+
disabled={enableSeerCoding}
192+
title={tct(
193+
'[settings:"Enable Code Generation"] must be enabled for Seer to create pull requests.',
194+
{
195+
settings: <Link to={`/settings/${organization.slug}/seer/#enableSeerCoding`} />,
196+
}
197+
)}
198+
>
199+
<ButtonBar merged gap="0">
200+
<Button
201+
onClick={onStepClick}
202+
disabled={isLoading || (step === 'code_changes' && !enableSeerCoding)}
203+
busy={isBusy}
204+
priority={priority}
205+
>
206+
{STEP_LABELS[step]}
207+
</Button>
208+
<DropdownMenu
209+
items={dropdownItems}
210+
trigger={(triggerProps, isOpen) => (
211+
<DropdownTrigger
212+
{...triggerProps}
213+
disabled={isLoading || (step === 'code_changes' && !enableSeerCoding)}
214+
priority={priority}
215+
icon={<IconChevron direction={isOpen ? 'up' : 'down'} size="xs" />}
216+
aria-label={t('More code fix options')}
217+
/>
218+
)}
219+
position="bottom-end"
220+
/>
221+
</ButtonBar>
222+
</Tooltip>
196223
);
197224
}
198225

0 commit comments

Comments
 (0)