1
- import { useContext , useEffect , useMemo } from 'react' ;
2
- import groupBy from 'lodash/groupBy' ;
1
+ import { useContext , useMemo } from 'react' ;
3
2
4
- import Avatar from 'sentry/components/avatar' ;
5
3
import { t } from 'sentry/locale' ;
6
- import type { DetailedTeam , Team } from 'sentry/types' ;
7
- import { useMembers } from 'sentry/utils/useMembers' ;
8
- import { useTeams } from 'sentry/utils/useTeams' ;
9
- import { useTeamsById } from 'sentry/utils/useTeamsById' ;
4
+ import { useOwnerOptions } from 'sentry/utils/useOwnerOptions' ;
5
+ import { useOwners } from 'sentry/utils/useOwners' ;
10
6
11
7
import FormContext from '../formContext' ;
12
8
@@ -20,7 +16,7 @@ export interface RenderFieldProps extends SelectFieldProps<any> {
20
16
/**
21
17
* Ensures the only selectable teams are members of the given project.
22
18
*/
23
- memberOfProjectSlug ?: string ;
19
+ memberOfProjectSlugs ?: string [ ] ;
24
20
/**
25
21
* Use the slug as the select field value. Without setting this the numeric id
26
22
* of the project will be used.
@@ -31,7 +27,7 @@ export interface RenderFieldProps extends SelectFieldProps<any> {
31
27
function SentryMemberTeamSelectorField ( {
32
28
avatarSize = 20 ,
33
29
placeholder = t ( 'Choose Teams and Members' ) ,
34
- memberOfProjectSlug ,
30
+ memberOfProjectSlugs ,
35
31
...props
36
32
} : RenderFieldProps ) {
37
33
const { form} = useContext ( FormContext ) ;
@@ -45,89 +41,16 @@ function SentryMemberTeamSelectorField({
45
41
[ fieldValue ]
46
42
) ;
47
43
48
- // Ensure the current value of the fields members is loaded
49
- const ensureUserIds = useMemo (
50
- ( ) =>
51
- currentValue ?. filter ( item => item . startsWith ( 'user:' ) ) . map ( user => user . slice ( 7 ) ) ,
52
- [ currentValue ]
53
- ) ;
54
- useMembers ( { ids : ensureUserIds } ) ;
55
-
56
- const {
57
- members,
58
- fetching : fetchingMembers ,
59
- onSearch : onMemberSearch ,
60
- loadMore : loadMoreMembers ,
61
- } = useMembers ( ) ;
62
-
63
- // XXX(epurkhiser): It would be nice to use an object as the value, but
64
- // frustratingly that is difficult likely because we're recreating this
65
- // object on every re-render.
66
- const memberOptions = members ?. map ( member => ( {
67
- value : `user:${ member . id } ` ,
68
- label : member . name ,
69
- leadingItems : < Avatar user = { member } size = { avatarSize } /> ,
70
- } ) ) ;
71
-
72
- // Ensure the current value of the fields teams is loaded
73
- const ensureTeamIds = useMemo (
74
- ( ) =>
75
- currentValue ?. filter ( item => item . startsWith ( 'team:' ) ) . map ( user => user . slice ( 5 ) ) ,
76
- [ currentValue ]
77
- ) ;
78
- useTeamsById ( { ids : ensureTeamIds } ) ;
79
-
80
- const {
81
- teams,
82
- fetching : fetchingTeams ,
83
- onSearch : onTeamSearch ,
84
- loadMore : loadMoreTeams ,
85
- } = useTeams ( ) ;
86
-
87
- const makeTeamOption = ( team : Team ) => ( {
88
- value : `team:${ team . id } ` ,
89
- label : `#${ team . slug } ` ,
90
- leadingItems : < Avatar team = { team } size = { avatarSize } /> ,
44
+ const { teams, members, fetching, onTeamSearch, onMemberSearch} = useOwners ( {
45
+ currentValue,
91
46
} ) ;
92
-
93
- const makeDisabledTeamOption = ( team : Team ) => ( {
94
- ...makeTeamOption ( team ) ,
95
- disabled : true ,
96
- tooltip : t ( '%s is not a member of the selected project' , `#${ team . slug } ` ) ,
97
- tooltipOptions : { position : 'left' } ,
47
+ const options = useOwnerOptions ( {
48
+ teams,
49
+ members,
50
+ avatarProps : { size : avatarSize } ,
51
+ memberOfProjectSlugs,
98
52
} ) ;
99
53
100
- // TODO(davidenwang): Fix the team type here to avoid this type cast: `as DetailedTeam[]`
101
- const { disabledTeams, memberTeams, otherTeams} = groupBy (
102
- teams as DetailedTeam [ ] ,
103
- team =>
104
- memberOfProjectSlug && ! team . projects . some ( ( { slug} ) => memberOfProjectSlug === slug )
105
- ? 'disabledTeams'
106
- : team . isMember
107
- ? 'memberTeams'
108
- : 'otherTeams'
109
- ) ;
110
-
111
- const myTeamOptions = memberTeams ?. map ( makeTeamOption ) ?? [ ] ;
112
- const otherTeamOptions = otherTeams ?. map ( makeTeamOption ) ?? [ ] ;
113
- const disabledTeamOptions = disabledTeams ?. map ( makeDisabledTeamOption ) ?? [ ] ;
114
-
115
- // TODO(epurkhiser): This is an unfortunate hack right now since we don't
116
- // actually load members anywhere and the useMembers and useTeams hook don't
117
- // handle initial loading of data.
118
- //
119
- // In the future when these things use react query we should be able to clean
120
- // this up.
121
- useEffect (
122
- ( ) => {
123
- loadMoreMembers ( ) ;
124
- loadMoreTeams ( ) ;
125
- } ,
126
- // Only ensure things are loaded at mount
127
- // eslint-disable-next-line react-hooks/exhaustive-deps
128
- [ ]
129
- ) ;
130
-
131
54
return (
132
55
< SelectField
133
56
placeholder = { placeholder }
@@ -136,25 +59,8 @@ function SentryMemberTeamSelectorField({
136
59
onMemberSearch ( value ) ;
137
60
onTeamSearch ( value ) ;
138
61
} }
139
- isLoading = { fetchingMembers || fetchingTeams }
140
- options = { [
141
- {
142
- label : t ( 'Members' ) ,
143
- options : memberOptions ,
144
- } ,
145
- {
146
- label : t ( 'My Teams' ) ,
147
- options : myTeamOptions ,
148
- } ,
149
- {
150
- label : t ( 'Other Teams' ) ,
151
- options : otherTeamOptions ,
152
- } ,
153
- {
154
- label : t ( 'Disabled Teams' ) ,
155
- options : disabledTeamOptions ,
156
- } ,
157
- ] }
62
+ isLoading = { fetching }
63
+ options = { options }
158
64
{ ...props }
159
65
/>
160
66
) ;
0 commit comments