Skip to content

Commit d4a2724

Browse files
fix(prevent): Use disabled tag for toggle instead of tooltip (#100331)
Use the "disabled" tag that looks like the one on the Codecov toggle instead of current tooltip only behavior. Tooltip when self-hosted: <img width="616" height="201" alt="Screenshot 2025-09-25 at 12 04 25 PM" src="https://github.com/user-attachments/assets/dcaf5b66-50be-4353-b205-73a0baa0af12" /> Tooltip when non-US region: <img width="743" height="282" alt="Screenshot 2025-09-25 at 12 02 46 PM" src="https://github.com/user-attachments/assets/379d29e1-24af-43f0-9614-5da98cde25c2" /> Example of the one on the Codecov toggle (not touched, just here as comparison): <img width="728" height="630" alt="Screenshot 2025-09-25 at 12 02 42 PM" src="https://github.com/user-attachments/assets/fcb79cc3-05c2-4885-b798-5b149f506b7b" /> Note I had the beta one change from position: right to position: top when there are both tags so the 2 behave same when side-by-side <img width="721" height="257" alt="Screenshot 2025-09-25 at 12 02 52 PM" src="https://github.com/user-attachments/assets/4b46b6f3-f483-4c9f-bc0a-37b609fffe82" /> Old version being replaced: <img width="679" height="141" alt="Screenshot 2025-09-25 at 1 41 24 PM" src="https://github.com/user-attachments/assets/8b7d622b-8b7f-4958-b047-8bbcff840b1a" />
1 parent 606ac4b commit d4a2724

File tree

2 files changed

+79
-9
lines changed

2 files changed

+79
-9
lines changed

static/app/views/settings/organizationGeneralSettings/organizationSettingsForm.spec.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingL
55

66
import * as formIndicatorActions from 'sentry/components/forms/formIndicators';
77
import Indicators from 'sentry/components/indicators';
8+
import ConfigStore from 'sentry/stores/configStore';
89
import * as RegionUtils from 'sentry/utils/regions';
910
import OrganizationSettingsForm from 'sentry/views/settings/organizationGeneralSettings/organizationSettingsForm';
1011

@@ -357,9 +358,10 @@ describe('OrganizationSettingsForm', () => {
357358
});
358359
expect(preventAiField).toBeInTheDocument();
359360
expect(preventAiField).toBeEnabled();
361+
expect(screen.queryByTestId('prevent-ai-disabled-tag')).not.toBeInTheDocument();
360362
});
361363

362-
it('is disabled when non US region', () => {
364+
it('is disabled when non US region', async () => {
363365
jest.mocked(RegionUtils.getRegionDataFromOrganization).mockReturnValue({
364366
name: 'de',
365367
displayName: 'Europe (Frankfurt)',
@@ -379,6 +381,14 @@ describe('OrganizationSettingsForm', () => {
379381
});
380382
expect(preventAiField).toBeInTheDocument();
381383
expect(preventAiField).toBeDisabled();
384+
385+
// Hover over the disabled tag to show the tooltip
386+
const disabledTag = screen.getByTestId('prevent-ai-disabled-tag');
387+
expect(disabledTag).toBeInTheDocument();
388+
await userEvent.hover(disabledTag);
389+
expect(
390+
await screen.findByText('This feature is only available in the US region')
391+
).toBeInTheDocument();
382392
});
383393

384394
it('is enabled when user is an admin (has org:write access)', () => {
@@ -409,6 +419,7 @@ describe('OrganizationSettingsForm', () => {
409419
});
410420
expect(preventAiField).toBeInTheDocument();
411421
expect(preventAiField).toBeEnabled();
422+
expect(screen.queryByTestId('prevent-ai-disabled-tag')).not.toBeInTheDocument();
412423
});
413424

414425
it('is disabled when user is a member (does not have org:write access)', async () => {
@@ -438,6 +449,40 @@ describe('OrganizationSettingsForm', () => {
438449
});
439450
expect(preventAiField).toBeInTheDocument();
440451
expect(preventAiField).toBeDisabled();
452+
expect(screen.queryByTestId('prevent-ai-disabled-tag')).not.toBeInTheDocument();
453+
});
454+
455+
it('is disabled when self-hosted', async () => {
456+
ConfigStore.set('isSelfHosted', true);
457+
458+
render(
459+
<OrganizationSettingsForm
460+
{...routerProps}
461+
initialData={OrganizationFixture({
462+
hideAiFeatures: true,
463+
})}
464+
onSave={onSave}
465+
/>,
466+
{
467+
organization: {
468+
access: ['org:write'],
469+
},
470+
}
471+
);
472+
473+
const preventAiField = screen.getByRole('checkbox', {
474+
name: /Enable AI Code Review/i,
475+
});
476+
expect(preventAiField).toBeInTheDocument();
477+
expect(preventAiField).toBeDisabled();
478+
479+
// Hover over the disabled tag to show the tooltip
480+
const disabledTag = screen.getByTestId('prevent-ai-disabled-tag');
481+
expect(disabledTag).toBeInTheDocument();
482+
await userEvent.hover(disabledTag);
483+
expect(
484+
await screen.findByText('This feature is not available for self-hosted instances')
485+
).toBeInTheDocument();
441486
});
442487
});
443488
});
Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,48 @@
11
import {FeatureBadge} from 'sentry/components/core/badge/featureBadge';
2+
import {Tag} from 'sentry/components/core/badge/tag';
3+
import {Flex} from 'sentry/components/core/layout';
24
import {ExternalLink} from 'sentry/components/core/link';
5+
import {Tooltip} from 'sentry/components/core/tooltip';
36
import type {FieldObject} from 'sentry/components/forms/types';
7+
import {IconLock} from 'sentry/icons';
48
import {t, tct} from 'sentry/locale';
9+
import ConfigStore from 'sentry/stores/configStore';
510
import type {Organization} from 'sentry/types/organization';
611
import {getRegionDataFromOrganization} from 'sentry/utils/regions';
712

813
export const makePreventAiField = (organization: Organization): FieldObject => {
914
const regionData = getRegionDataFromOrganization(organization);
10-
const isUSOrg = regionData?.name === 'us';
15+
const isUSOrg = regionData?.name?.toLowerCase() === 'us';
16+
const isSelfHosted = ConfigStore.get('isSelfHosted');
17+
18+
const isDisabled = isSelfHosted || !isUSOrg;
19+
const disabledReason = isSelfHosted
20+
? t('This feature is not available for self-hosted instances')
21+
: t('This feature is only available in the US region');
1122

1223
return {
1324
name: 'enablePrReviewTestGeneration',
1425
type: 'boolean',
15-
label: tct('Enable AI Code Review [badge]', {
16-
badge: <FeatureBadge type="beta" style={{marginBottom: '2px'}} />,
17-
}),
26+
label: (
27+
<Flex gap="sm" align="center">
28+
{t('Enable AI Code Review')}
29+
<FeatureBadge
30+
type="beta"
31+
{...(isDisabled ? {tooltipProps: {position: 'top'}} : {})}
32+
/>
33+
{isDisabled && (
34+
<Tooltip title={disabledReason} position="top">
35+
<Tag
36+
role="status"
37+
icon={<IconLock locked />}
38+
data-test-id="prevent-ai-disabled-tag"
39+
>
40+
{t('disabled')}
41+
</Tag>
42+
</Tooltip>
43+
)}
44+
</Flex>
45+
),
1846
help: tct(
1947
'Use AI to review, find bugs, and generate tests in pull requests [link:Learn more]',
2048
{
@@ -28,9 +56,6 @@ export const makePreventAiField = (organization: Organization): FieldObject => {
2856
const hideAiFeatures = model.getValue('hideAiFeatures');
2957
return hideAiFeatures;
3058
},
31-
disabled: ({access}) => !isUSOrg || !access.has('org:write'),
32-
disabledReason: isUSOrg
33-
? null
34-
: t('AI Code Review is only available in the US region'),
59+
disabled: ({access}) => isDisabled || !access.has('org:write'),
3560
};
3661
};

0 commit comments

Comments
 (0)