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,33 @@ 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
+ memberOfProjectSlug && ! team . projects . some ( ( { slug} ) => memberOfProjectSlug === slug )
112
+ ? 'disabledTeams'
113
+ : team . isMember
114
+ ? 'memberTeams'
115
+ : 'otherTeams'
116
+ ) ;
117
+
118
+ const myTeamOptions = memberTeams ?. map ( makeTeamOption ) ?? [ ] ;
119
+ const otherTeamOptions = otherTeams ?. map ( makeTeamOption ) ?? [ ] ;
120
+ const disabledTeamOptions = disabledTeams ?. map ( makeDisabledTeamOption ) ?? [ ] ;
92
121
93
122
// TODO(epurkhiser): This is an unfortunate hack right now since we don't
94
123
// actually load members anywhere and the useMembers and useTeams hook don't
@@ -128,6 +157,10 @@ function SentryMemberTeamSelectorField({
128
157
label : t ( 'Other Teams' ) ,
129
158
options : otherTeamOptions ,
130
159
} ,
160
+ {
161
+ label : t ( 'Disabled Teams' ) ,
162
+ options : disabledTeamOptions ,
163
+ } ,
131
164
] }
132
165
{ ...props }
133
166
/>
0 commit comments