Skip to content

Commit 5a07a4a

Browse files
author
davidenwang
committed
feat(crons): Disallow teams not part of project to be selected for alerts
commit-id:3863ee1e
1 parent e849a2a commit 5a07a4a

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

static/app/components/forms/fields/sentryMemberTeamSelectorField.tsx

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import {useContext, useEffect, useMemo} from 'react';
2-
import partition from 'lodash/partition';
2+
import groupBy from 'lodash/groupBy';
33

44
import Avatar from 'sentry/components/avatar';
5+
import {Tooltip} from 'sentry/components/tooltip';
56
import {t} from 'sentry/locale';
6-
import type {Team} from 'sentry/types';
7+
import type {DetailedTeam, Team} from 'sentry/types';
78
import {useMembers} from 'sentry/utils/useMembers';
89
import {useTeams} from 'sentry/utils/useTeams';
910
import {useTeamsById} from 'sentry/utils/useTeamsById';
@@ -17,6 +18,10 @@ import SelectField from './selectField';
1718
// projects can be passed as a direct prop as well
1819
export interface RenderFieldProps extends SelectFieldProps<any> {
1920
avatarSize?: number;
21+
/**
22+
* Ensures the only selectable teams and members are members of the given project
23+
*/
24+
memberOfProjectSlug?: string;
2025
/**
2126
* Use the slug as the select field value. Without setting this the numeric id
2227
* of the project will be used.
@@ -27,6 +32,7 @@ export interface RenderFieldProps extends SelectFieldProps<any> {
2732
function SentryMemberTeamSelectorField({
2833
avatarSize = 20,
2934
placeholder = t('Choose Teams and Members'),
35+
memberOfProjectSlug,
3036
...props
3137
}: RenderFieldProps) {
3238
const {form} = useContext(FormContext);
@@ -85,10 +91,36 @@ function SentryMemberTeamSelectorField({
8591
leadingItems: <Avatar team={team} size={avatarSize} />,
8692
});
8793

88-
const [myTeams, otherTeams] = partition(teams, team => team.isMember);
94+
const makeDisabledTeamOption = (team: Team) => ({
95+
...makeTeamOption(team),
96+
disabled: true,
97+
label: (
98+
<Tooltip
99+
position="left"
100+
title={t('%s is not a member of the selected project', `#${team.slug}`)}
101+
>
102+
#{team.slug}
103+
</Tooltip>
104+
),
105+
});
89106

90-
const myTeamOptions = myTeams.map(makeTeamOption);
107+
// TODO(davidenwang): Fix the team type here to avoid this type cast: `as DetailedTeam[]`
108+
const {disabledTeams, memberTeams, otherTeams} = groupBy(
109+
teams as DetailedTeam[],
110+
team => {
111+
const isDisabled =
112+
memberOfProjectSlug &&
113+
!team.projects.some(({slug}) => memberOfProjectSlug === slug);
114+
if (isDisabled) {
115+
return 'disabledTeams';
116+
}
117+
return team.isMember ? 'memberTeams' : 'otherTeams';
118+
}
119+
);
120+
121+
const myTeamOptions = memberTeams.map(makeTeamOption);
91122
const otherTeamOptions = otherTeams.map(makeTeamOption);
123+
const disabledTeamOptions = disabledTeams.map(makeDisabledTeamOption);
92124

93125
// TODO(epurkhiser): This is an unfortunate hack right now since we don't
94126
// actually load members anywhere and the useMembers and useTeams hook don't
@@ -128,6 +160,10 @@ function SentryMemberTeamSelectorField({
128160
label: t('Other Teams'),
129161
options: otherTeamOptions,
130162
},
163+
{
164+
label: t('Disabled Teams'),
165+
options: disabledTeamOptions,
166+
},
131167
]}
132168
{...props}
133169
/>

static/app/views/monitors/components/monitorForm.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -504,13 +504,18 @@ function MonitorForm({
504504
{t('Customize this monitors notification configuration in Alerts')}
505505
</AlertLink>
506506
)}
507-
<SentryMemberTeamSelectorField
508-
label={t('Notify')}
509-
help={t('Send notifications to a member or team.')}
510-
name="alertRule.targets"
511-
multiple
512-
menuPlacement="auto"
513-
/>
507+
<Observer>
508+
{() => (
509+
<SentryMemberTeamSelectorField
510+
label={t('Notify')}
511+
help={t('Send notifications to a member or team.')}
512+
name="alertRule.targets"
513+
memberOfProjectSlug={form.current.getValue('project')?.toString()}
514+
multiple
515+
menuPlacement="auto"
516+
/>
517+
)}
518+
</Observer>
514519
<Observer>
515520
{() => {
516521
const selectedAssignee = form.current.getValue('alertRule.targets');

0 commit comments

Comments
 (0)