1
1
import { useContext , useEffect , useMemo } from 'react' ;
2
- import partition from 'lodash/partition ' ;
2
+ import groupBy from 'lodash/groupBy ' ;
3
3
4
4
import Avatar from 'sentry/components/avatar' ;
5
+ import { Tooltip } from 'sentry/components/tooltip' ;
5
6
import { t } from 'sentry/locale' ;
6
- import type { Team } from 'sentry/types' ;
7
+ import type { DetailedTeam , Team } from 'sentry/types' ;
7
8
import { useMembers } from 'sentry/utils/useMembers' ;
8
9
import { useTeams } from 'sentry/utils/useTeams' ;
9
10
import { useTeamsById } from 'sentry/utils/useTeamsById' ;
@@ -17,6 +18,10 @@ import SelectField from './selectField';
17
18
// projects can be passed as a direct prop as well
18
19
export interface RenderFieldProps extends SelectFieldProps < any > {
19
20
avatarSize ?: number ;
21
+ /**
22
+ * Ensures the only selectable teams and members are members of the given project
23
+ */
24
+ memberOfProjectSlug ?: string ;
20
25
/**
21
26
* Use the slug as the select field value. Without setting this the numeric id
22
27
* of the project will be used.
@@ -27,6 +32,7 @@ export interface RenderFieldProps extends SelectFieldProps<any> {
27
32
function SentryMemberTeamSelectorField ( {
28
33
avatarSize = 20 ,
29
34
placeholder = t ( 'Choose Teams and Members' ) ,
35
+ memberOfProjectSlug,
30
36
...props
31
37
} : RenderFieldProps ) {
32
38
const { form} = useContext ( FormContext ) ;
@@ -85,10 +91,36 @@ function SentryMemberTeamSelectorField({
85
91
leadingItems : < Avatar team = { team } size = { avatarSize } /> ,
86
92
} ) ;
87
93
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
+ } ) ;
89
106
90
- const myTeamOptions = myTeams . map ( makeTeamOption ) ;
91
- const otherTeamOptions = otherTeams . 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 ) ?? [ ] ;
122
+ const otherTeamOptions = otherTeams ?. map ( makeTeamOption ) ?? [ ] ;
123
+ const disabledTeamOptions = disabledTeams ?. map ( makeDisabledTeamOption ) ?? [ ] ;
92
124
93
125
// TODO(epurkhiser): This is an unfortunate hack right now since we don't
94
126
// actually load members anywhere and the useMembers and useTeams hook don't
@@ -128,6 +160,10 @@ function SentryMemberTeamSelectorField({
128
160
label : t ( 'Other Teams' ) ,
129
161
options : otherTeamOptions ,
130
162
} ,
163
+ {
164
+ label : t ( 'Disabled Teams' ) ,
165
+ options : disabledTeamOptions ,
166
+ } ,
131
167
] }
132
168
{ ...props }
133
169
/>
0 commit comments