Skip to content

Commit 9bfa1d7

Browse files
evanpurkhiserandrewshie-sentry
authored andcommitted
feat(detectors): Add permission checking to DisabledAlert enable button (#103175)
The DisabledAlert component now uses useCanEditDetector to verify that users have alerts:write permission before allowing them to enable detectors. Users without permission see a disabled button with a tooltip explaining they don't have permission to enable the monitor.
1 parent fbd08e1 commit 9bfa1d7

File tree

2 files changed

+43
-18
lines changed

2 files changed

+43
-18
lines changed
Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,67 @@
11
import {UptimeDetectorFixture} from 'sentry-fixture/detectors';
2+
import {OrganizationFixture} from 'sentry-fixture/organization';
3+
import {ProjectFixture} from 'sentry-fixture/project';
24

3-
import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
5+
import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
6+
7+
import ProjectsStore from 'sentry/stores/projectsStore';
48

59
import {DisabledAlert} from './disabledAlert';
610

711
describe('DisabledAlert', () => {
12+
const organization = OrganizationFixture({
13+
access: ['org:write', 'alerts:write'],
14+
alertsMemberWrite: true,
15+
});
16+
const project = ProjectFixture({access: ['alerts:write']});
17+
18+
beforeEach(() => {
19+
MockApiClient.clearMockResponses();
20+
act(() => ProjectsStore.loadInitialData([project]));
21+
});
22+
823
it('does not render when detector is enabled', () => {
9-
const detector = UptimeDetectorFixture({enabled: true});
24+
const detector = UptimeDetectorFixture({enabled: true, projectId: project.id});
1025

1126
const {container} = render(
12-
<DisabledAlert detector={detector} message="Test disabled message" />
27+
<DisabledAlert detector={detector} message="Test disabled message" />,
28+
{organization}
1329
);
1430

1531
expect(container).toBeEmptyDOMElement();
1632
});
1733

1834
it('renders alert with message and enable button when detector is disabled', () => {
19-
const detector = UptimeDetectorFixture({enabled: false});
35+
const detector = UptimeDetectorFixture({enabled: false, projectId: project.id});
2036

21-
render(<DisabledAlert detector={detector} message="Test disabled message" />);
37+
render(<DisabledAlert detector={detector} message="Test disabled message" />, {
38+
organization,
39+
});
2240

2341
expect(screen.getByText('Test disabled message')).toBeInTheDocument();
2442
expect(screen.getByRole('button', {name: 'Enable'})).toBeInTheDocument();
2543
});
2644

2745
it('enables detector when enable button is clicked', async () => {
28-
const detector = UptimeDetectorFixture({id: '123', enabled: false});
46+
const detector = UptimeDetectorFixture({
47+
id: '123',
48+
enabled: false,
49+
projectId: project.id,
50+
});
2951

3052
const updateRequest = MockApiClient.addMockResponse({
3153
url: '/organizations/org-slug/detectors/123/',
3254
method: 'PUT',
3355
body: {...detector, enabled: true},
3456
});
3557

36-
render(<DisabledAlert detector={detector} message="Test message" />);
58+
render(<DisabledAlert detector={detector} message="Test message" />, {
59+
organization,
60+
});
61+
62+
const enableButton = await screen.findByRole('button', {name: 'Enable'});
63+
expect(enableButton).toBeEnabled();
3764

38-
const enableButton = screen.getByRole('button', {name: 'Enable'});
3965
await userEvent.click(enableButton);
4066

4167
await waitFor(() => {
@@ -48,13 +74,4 @@ describe('DisabledAlert', () => {
4874
);
4975
});
5076
});
51-
52-
it('button is clickable when detector is disabled', () => {
53-
const detector = UptimeDetectorFixture({id: '123', enabled: false});
54-
55-
render(<DisabledAlert detector={detector} message="Test message" />);
56-
57-
const enableButton = screen.getByRole('button', {name: 'Enable'});
58-
expect(enableButton).toBeEnabled();
59-
});
6077
});

static/app/views/detectors/components/details/common/disabledAlert.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {IconPlay} from 'sentry/icons';
44
import {t} from 'sentry/locale';
55
import type {Detector} from 'sentry/types/workflowEngine/detectors';
66
import {useUpdateDetector} from 'sentry/views/detectors/hooks';
7+
import {useCanEditDetector} from 'sentry/views/detectors/utils/useCanEditDetector';
78

89
type DisabledAlertProps = {
910
detector: Detector;
@@ -17,6 +18,10 @@ type DisabledAlertProps = {
1718
*/
1819
export function DisabledAlert({detector, message}: DisabledAlertProps) {
1920
const {mutate: updateDetector, isPending: isEnabling} = useUpdateDetector();
21+
const canEdit = useCanEditDetector({
22+
detectorType: detector.type,
23+
projectId: detector.projectId,
24+
});
2025

2126
if (detector.enabled) {
2227
return null;
@@ -35,8 +40,11 @@ export function DisabledAlert({detector, message}: DisabledAlertProps) {
3540
size="xs"
3641
icon={<IconPlay />}
3742
onClick={handleEnable}
38-
disabled={isEnabling}
43+
disabled={isEnabling || !canEdit}
3944
aria-label={t('Enable')}
45+
title={
46+
canEdit ? undefined : t('You do not have permission to enable this monitor')
47+
}
4048
>
4149
{t('Enable')}
4250
</Button>

0 commit comments

Comments
 (0)