Skip to content

Commit 7801b99

Browse files
committed
fix(aci): Better handling for error monitor edit permissions
1 parent 76dde99 commit 7801b99

File tree

6 files changed

+129
-70
lines changed

6 files changed

+129
-70
lines changed

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

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import {addSuccessMessage} from 'sentry/actionCreators/indicator';
44
import {openConfirmModal} from 'sentry/components/confirm';
55
import {Button} from 'sentry/components/core/button';
66
import {LinkButton} from 'sentry/components/core/button/linkButton';
7-
import {Link} from 'sentry/components/core/link';
87
import {Tooltip} from 'sentry/components/core/tooltip';
98
import {IconEdit} from 'sentry/icons';
10-
import {t, tct} from 'sentry/locale';
9+
import {t} from 'sentry/locale';
1110
import type {Detector} from 'sentry/types/workflowEngine/detectors';
1211
import {useNavigate} from 'sentry/utils/useNavigate';
1312
import useOrganization from 'sentry/utils/useOrganization';
@@ -18,6 +17,10 @@ import {
1817
makeMonitorTypePathname,
1918
} from 'sentry/views/detectors/pathnames';
2019
import {detectorTypeIsUserCreateable} from 'sentry/views/detectors/utils/detectorTypeConfig';
20+
import {
21+
getManagedBySentryMonitorEditTooltip,
22+
getNoPermissionToEditMonitorTooltip,
23+
} from 'sentry/views/detectors/utils/monitorAccessMessages';
2124
import {useCanEditDetector} from 'sentry/views/detectors/utils/useCanEditDetector';
2225

2326
export function DisableDetectorAction({detector}: {detector: Detector}) {
@@ -54,30 +57,23 @@ export function DisableDetectorAction({detector}: {detector: Detector}) {
5457
);
5558
}
5659

57-
export function EditDetectorAction({detector}: {detector: Detector}) {
60+
export function EditDetectorAction({
61+
detector,
62+
canEdit: canEditOverride,
63+
}: {
64+
detector: Detector;
65+
canEdit?: boolean;
66+
}) {
5867
const organization = useOrganization();
59-
const canEdit = useCanEditDetector({
68+
const canEditDetectorType = useCanEditDetector({
6069
detectorType: detector.type,
6170
projectId: detector.projectId,
6271
});
72+
const canEdit = canEditOverride ?? canEditDetectorType;
6373

6474
const permissionTooltipText = detectorTypeIsUserCreateable(detector.type)
65-
? tct(
66-
'You do not have permission to edit this monitor. Ask your organization owner or manager to [settingsLink:enable monitor access] for you.',
67-
{
68-
settingsLink: (
69-
<Link
70-
to={{
71-
pathname: `/settings/${organization.slug}/`,
72-
hash: 'alertsMemberWrite',
73-
}}
74-
/>
75-
),
76-
}
77-
)
78-
: t(
79-
'This monitor is managed by Sentry. Only organization owners and managers can edit it.'
80-
);
75+
? getNoPermissionToEditMonitorTooltip()
76+
: getManagedBySentryMonitorEditTooltip();
8177

8278
return (
8379
<Tooltip

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

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,55 @@ type DetectorDetailsHeaderProps = {
2020
project: Project;
2121
};
2222

23-
export function DetectorDetailsHeader({detector, project}: DetectorDetailsHeaderProps) {
23+
function DetectorDetailsBreadcrumbs({detector}: {detector: Detector}) {
2424
const organization = useOrganization();
25+
return (
26+
<Breadcrumbs
27+
crumbs={[
28+
{
29+
label: t('Monitors'),
30+
to: makeMonitorBasePathname(organization.slug),
31+
},
32+
{
33+
label: getDetectorTypeLabel(detector.type),
34+
to: makeMonitorTypePathname(organization.slug, detector.type),
35+
},
36+
{label: detector.name},
37+
]}
38+
/>
39+
);
40+
}
2541

42+
export function DetectorDetailsDefaultHeaderContent({
43+
detector,
44+
project,
45+
}: {
46+
detector: Detector;
47+
project: Project;
48+
}) {
49+
return (
50+
<DetailLayout.HeaderContent>
51+
<DetectorDetailsBreadcrumbs detector={detector} />
52+
<DetailLayout.Title title={detector.name} project={project} />
53+
</DetailLayout.HeaderContent>
54+
);
55+
}
56+
57+
function DetectorDetailsDefaultActions({detector}: {detector: Detector}) {
58+
return (
59+
<DetailLayout.Actions>
60+
<MonitorFeedbackButton />
61+
<DisableDetectorAction detector={detector} />
62+
<EditDetectorAction detector={detector} />
63+
</DetailLayout.Actions>
64+
);
65+
}
66+
67+
export function DetectorDetailsHeader({detector, project}: DetectorDetailsHeaderProps) {
2668
return (
2769
<DetailLayout.Header>
28-
<DetailLayout.HeaderContent>
29-
<Breadcrumbs
30-
crumbs={[
31-
{
32-
label: t('Monitors'),
33-
to: makeMonitorBasePathname(organization.slug),
34-
},
35-
{
36-
label: getDetectorTypeLabel(detector.type),
37-
to: makeMonitorTypePathname(organization.slug, detector.type),
38-
},
39-
{label: detector.name},
40-
]}
41-
/>
42-
<DetailLayout.Title title={detector.name} project={project} />
43-
</DetailLayout.HeaderContent>
44-
<DetailLayout.Actions>
45-
<MonitorFeedbackButton />
46-
<DisableDetectorAction detector={detector} />
47-
<EditDetectorAction detector={detector} />
48-
</DetailLayout.Actions>
70+
<DetectorDetailsDefaultHeaderContent detector={detector} project={project} />
71+
<DetectorDetailsDefaultActions detector={detector} />
4972
</DetailLayout.Header>
5073
);
5174
}

static/app/views/detectors/components/details/error/index.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ import type {Project} from 'sentry/types/project';
99
import type {Detector} from 'sentry/types/workflowEngine/detectors';
1010
import {useDetailedProject} from 'sentry/utils/project/useDetailedProject';
1111
import useOrganization from 'sentry/utils/useOrganization';
12+
import {EditDetectorAction} from 'sentry/views/detectors/components/details/common/actions';
1213
import {DetectorDetailsAutomations} from 'sentry/views/detectors/components/details/common/automations';
1314
import {DisabledAlert} from 'sentry/views/detectors/components/details/common/disabledAlert';
1415
import {DetectorExtraDetails} from 'sentry/views/detectors/components/details/common/extraDetails';
15-
import {DetectorDetailsHeader} from 'sentry/views/detectors/components/details/common/header';
16+
import {DetectorDetailsDefaultHeaderContent} from 'sentry/views/detectors/components/details/common/header';
1617
import {DetectorDetailsOngoingIssues} from 'sentry/views/detectors/components/details/common/ongoingIssues';
18+
import {MonitorFeedbackButton} from 'sentry/views/detectors/components/monitorFeedbackButton';
19+
import {useCanEditDetectorWorkflowConnections} from 'sentry/views/detectors/utils/useCanEditDetector';
1720

1821
type ErrorDetectorDetailsProps = {
1922
detector: Detector;
@@ -65,10 +68,17 @@ function ResolveSection({project}: {project: Project}) {
6568

6669
export function ErrorDetectorDetails({detector, project}: ErrorDetectorDetailsProps) {
6770
const organization = useOrganization();
71+
const canEdit = useCanEditDetectorWorkflowConnections({projectId: project.id});
6872

6973
return (
7074
<DetailLayout>
71-
<DetectorDetailsHeader detector={detector} project={project} />
75+
<DetailLayout.Header>
76+
<DetectorDetailsDefaultHeaderContent detector={detector} project={project} />
77+
<DetailLayout.Actions>
78+
<MonitorFeedbackButton />
79+
<EditDetectorAction detector={detector} canEdit={canEdit} />
80+
</DetailLayout.Actions>
81+
</DetailLayout.Header>
7282
<DetailLayout.Body>
7383
<DetailLayout.Main>
7484
<DisabledAlert

static/app/views/detectors/components/forms/error/index.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {AutomationFeedbackButton} from 'sentry/views/automations/components/auto
1818
import {AutomateSection} from 'sentry/views/detectors/components/forms/automateSection';
1919
import {EditDetectorBreadcrumbs} from 'sentry/views/detectors/components/forms/common/breadcrumbs';
2020
import {useEditDetectorFormSubmit} from 'sentry/views/detectors/hooks/useEditDetectorFormSubmit';
21+
import {getNoPermissionToEditMonitorTooltip} from 'sentry/views/detectors/utils/monitorAccessMessages';
22+
import {useCanEditDetectorWorkflowConnections} from 'sentry/views/detectors/utils/useCanEditDetector';
2123

2224
type ErrorDetectorFormData = {
2325
workflowIds: string[];
@@ -114,6 +116,11 @@ export function EditExistingErrorDetectorForm({detector}: {detector: ErrorDetect
114116
const theme = useTheme();
115117
const maxWidth = theme.breakpoints.xl;
116118

119+
// Error monitors only allow editing workflow connections right now, so that's the only permission we need to check
120+
const canEditWorkflowConnections = useCanEditDetectorWorkflowConnections({
121+
projectId: detector.projectId,
122+
});
123+
117124
const handleFormSubmit = useEditDetectorFormSubmit({
118125
detector,
119126
formDataToEndpointPayload: (data: ErrorDetectorFormData) => ({
@@ -151,7 +158,15 @@ export function EditExistingErrorDetectorForm({detector}: {detector: ErrorDetect
151158
</EditLayout.Body>
152159

153160
<EditLayout.Footer maxWidth={maxWidth}>
154-
<Button type="submit" priority="primary" size="sm">
161+
<Button
162+
type="submit"
163+
priority="primary"
164+
size="sm"
165+
disabled={!canEditWorkflowConnections}
166+
title={
167+
canEditWorkflowConnections ? undefined : getNoPermissionToEditMonitorTooltip()
168+
}
169+
>
155170
{t('Save')}
156171
</Button>
157172
</EditLayout.Footer>

static/app/views/detectors/list/common/detectorListActions.tsx

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
import {Link} from '@sentry/scraps/link';
2-
31
import {LinkButton} from 'sentry/components/core/button/linkButton';
42
import {Flex} from 'sentry/components/core/layout';
53
import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters';
64
import {IconAdd} from 'sentry/icons';
7-
import {t, tct} from 'sentry/locale';
8-
import type {Organization} from 'sentry/types/organization';
5+
import {t} from 'sentry/locale';
96
import type {DetectorType} from 'sentry/types/workflowEngine/detectors';
107
import useOrganization from 'sentry/utils/useOrganization';
118
import usePageFilters from 'sentry/utils/usePageFilters';
@@ -15,33 +12,16 @@ import {
1512
makeMonitorCreateSettingsPathname,
1613
} from 'sentry/views/detectors/pathnames';
1714
import {detectorTypeIsUserCreateable} from 'sentry/views/detectors/utils/detectorTypeConfig';
15+
import {getNoPermissionToCreateMonitorsTooltip} from 'sentry/views/detectors/utils/monitorAccessMessages';
1816
import {useCanCreateDetector} from 'sentry/views/detectors/utils/useCanCreateDetector';
1917

2018
interface DetectorListActionsProps {
2119
detectorType: DetectorType | null;
2220
children?: React.ReactNode;
2321
}
2422

25-
function getPermissionTooltipText({
26-
organization,
27-
detectorType,
28-
}: {
29-
detectorType: DetectorType | null;
30-
organization: Organization;
31-
}) {
32-
const noPermissionText = tct(
33-
'You do not have permission to create monitors. Ask your organization owner or manager to [settingsLink:enable monitor access] for you.',
34-
{
35-
settingsLink: (
36-
<Link
37-
to={{
38-
pathname: `/settings/${organization.slug}/`,
39-
hash: 'alertsMemberWrite',
40-
}}
41-
/>
42-
),
43-
}
44-
);
23+
function getPermissionTooltipText({detectorType}: {detectorType: DetectorType | null}) {
24+
const noPermissionText = getNoPermissionToCreateMonitorsTooltip();
4525

4626
if (!detectorType || detectorTypeIsUserCreateable(detectorType)) {
4727
return noPermissionText;
@@ -78,7 +58,6 @@ export function DetectorListActions({detectorType, children}: DetectorListAction
7858
canCreateDetector
7959
? undefined
8060
: getPermissionTooltipText({
81-
organization,
8261
detectorType,
8362
})
8463
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {Link} from 'sentry/components/core/link';
2+
import {t, tct} from 'sentry/locale';
3+
import useOrganization from 'sentry/utils/useOrganization';
4+
5+
function AlertsMemberWriteSettingsLink() {
6+
const organization = useOrganization();
7+
8+
return (
9+
<Link
10+
to={{
11+
hash: 'alertsMemberWrite',
12+
pathname: `/settings/${organization.slug}/`,
13+
}}
14+
/>
15+
);
16+
}
17+
18+
export function getNoPermissionToEditMonitorTooltip() {
19+
return tct(
20+
'You do not have permission to edit this monitor. Ask your organization owner or manager to [settingsLink:enable monitor access] for you.',
21+
{settingsLink: <AlertsMemberWriteSettingsLink />}
22+
);
23+
}
24+
25+
export function getNoPermissionToCreateMonitorsTooltip() {
26+
return tct(
27+
'You do not have permission to create monitors. Ask your organization owner or manager to [settingsLink:enable monitor access] for you.',
28+
{settingsLink: <AlertsMemberWriteSettingsLink />}
29+
);
30+
}
31+
32+
export function getManagedBySentryMonitorEditTooltip() {
33+
return t(
34+
'This monitor is managed by Sentry. Only organization owners and managers can edit it.'
35+
);
36+
}

0 commit comments

Comments
 (0)