Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8b7185d

Browse files
committed
fix: filter add group member by organization
This is accomplished by using the members endpoint instead of the usersendpoint, and to that end the UserAutocomplete component has beenreworked to support either endpoint as separate components with a sharedbase.
1 parent9f4f88f commit8b7185d

File tree

4 files changed

+135
-47
lines changed

4 files changed

+135
-47
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
importtype{Meta,StoryObj}from"@storybook/react";
2+
import{MockOrganizationMember}from"testHelpers/entities";
3+
import{MemberAutocomplete}from"./UserAutocomplete";
4+
5+
constmeta:Meta<typeofMemberAutocomplete>={
6+
title:"components/MemberAutocomplete",
7+
component:MemberAutocomplete,
8+
};
9+
10+
exportdefaultmeta;
11+
typeStory=StoryObj<typeofMemberAutocomplete>;
12+
13+
exportconstWithLabel:Story={
14+
args:{
15+
value:MockOrganizationMember,
16+
organizationId:MockOrganizationMember.organization_id,
17+
label:"Member",
18+
},
19+
};
20+
21+
exportconstNoLabel:Story={
22+
args:{
23+
value:MockOrganizationMember,
24+
organizationId:MockOrganizationMember.organization_id,
25+
},
26+
};

‎site/src/components/UserAutocomplete/UserAutocomplete.stories.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const meta: Meta<typeof UserAutocomplete> = {
1010
exportdefaultmeta;
1111
typeStory=StoryObj<typeofUserAutocomplete>;
1212

13-
exportconstExample:Story={
13+
exportconstWithLabel:Story={
1414
args:{
1515
value:MockUser,
1616
label:"User",

‎site/src/components/UserAutocomplete/UserAutocomplete.tsx‎

Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { css } from "@emotion/css";
22
importAutocompletefrom"@mui/material/Autocomplete";
33
importCircularProgressfrom"@mui/material/CircularProgress";
44
importTextFieldfrom"@mui/material/TextField";
5+
import{organizationMembers}from"api/queries/organizations";
56
import{users}from"api/queries/users";
6-
importtype{User}from"api/typesGenerated";
7+
importtype{OrganizationMemberWithUserData,User}from"api/typesGenerated";
78
import{Avatar}from"components/Avatar/Avatar";
89
import{AvatarData}from"components/AvatarData/AvatarData";
910
import{useDebouncedFunction}from"hooks/debounce";
@@ -16,45 +17,99 @@ import {
1617
import{useQuery}from"react-query";
1718
import{prepareQuery}from"utils/filters";
1819

19-
exporttypeUserAutocompleteProps={
20-
value:User|null;
21-
onChange:(user:User|null)=>void;
22-
label?:string;
20+
// The common properties between users and org members that we need.
21+
exporttypeSelectedUser={
22+
avatar_url:string;
23+
email:string;
24+
username:string;
25+
};
26+
27+
exporttypeCommonAutocompleteProps<TextendsSelectedUser>={
2328
className?:string;
24-
size?:ComponentProps<typeofTextField>["size"];
29+
label?:string;
30+
onChange:(user:T|null)=>void;
2531
required?:boolean;
32+
size?:ComponentProps<typeofTextField>["size"];
33+
value:T|null;
2634
};
2735

36+
exporttypeUserAutocompleteProps=CommonAutocompleteProps<User>;
37+
2838
exportconstUserAutocomplete:FC<UserAutocompleteProps>=({
2939
value,
30-
onChange,
31-
label,
32-
className,
33-
size="small",
34-
required,
40+
...props
3541
})=>{
36-
const[autoComplete,setAutoComplete]=useState<{
37-
value:string;
38-
open:boolean;
39-
}>({
40-
value:value?.email??"",
41-
open:false,
42-
});
42+
const[filter,setFilter]=useState<string>();
43+
4344
constusersQuery=useQuery({
4445
...users({
45-
q:prepareQuery(encodeURI(autoComplete.value)),
46+
q:filter!==undefined ?prepareQuery(encodeURI(filter)) :"",
4647
limit:25,
4748
}),
48-
enabled:autoComplete.open,
49+
enabled:filter!==undefined,
4950
keepPreviousData:true,
5051
});
52+
return(
53+
<InnerAutocomplete<User>
54+
users={usersQuery.data?.users}
55+
value={value}
56+
setFilter={setFilter}
57+
{...props}
58+
/>
59+
);
60+
};
61+
62+
exporttypeMemberAutocompleteProps=
63+
CommonAutocompleteProps<OrganizationMemberWithUserData>&{
64+
organizationId:string;
65+
};
66+
67+
exportconstMemberAutocomplete:FC<MemberAutocompleteProps>=({
68+
value,
69+
organizationId,
70+
...props
71+
})=>{
72+
const[filter,setFilter]=useState<string>();
73+
74+
// Currently this queries all members, as there is no pagination.
75+
constmembersQuery=useQuery({
76+
...organizationMembers(organizationId),
77+
enabled:filter!==undefined,
78+
keepPreviousData:true,
79+
});
80+
return(
81+
<InnerAutocomplete<OrganizationMemberWithUserData>
82+
users={membersQuery.data}
83+
value={value}
84+
setFilter={setFilter}
85+
{...props}
86+
/>
87+
);
88+
};
89+
90+
typeInnerAutocompleteProps<TextendsSelectedUser>=
91+
CommonAutocompleteProps<T>&{
92+
/** Filter is undefined if the autocomplete is closed. */
93+
setFilter:(filter:string|undefined)=>void;
94+
/** Users are undefined if not loaded. */
95+
users:readonlyT[]|undefined;
96+
};
97+
98+
constInnerAutocomplete=<TextendsSelectedUser>({
99+
className,
100+
label,
101+
onChange,
102+
required,
103+
setFilter,
104+
size="small",
105+
users,
106+
value,
107+
}:InnerAutocompleteProps<T>)=>{
108+
const[open,setOpen]=useState(false);
51109

52110
const{debounced:debouncedInputOnChange}=useDebouncedFunction(
53111
(event:ChangeEvent<HTMLInputElement>)=>{
54-
setAutoComplete((state)=>({
55-
...state,
56-
value:event.target.value,
57-
}));
112+
setFilter(event.target.value??"");
58113
},
59114
750,
60115
);
@@ -63,24 +118,20 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
63118
<Autocomplete
64119
noOptionsText="No users found"
65120
className={className}
66-
options={usersQuery.data?.users??[]}
67-
loading={usersQuery.isLoading}
121+
options={users??[]}
122+
loading={users!==undefined}
68123
value={value}
69124
data-testid="user-autocomplete"
70-
open={autoComplete.open}
125+
open={open}
71126
isOptionEqualToValue={(a,b)=>a.username===b.username}
72127
getOptionLabel={(option)=>option.email}
73128
onOpen={()=>{
74-
setAutoComplete((state)=>({
75-
...state,
76-
open:true,
77-
}));
129+
setOpen(true);
130+
setFilter(value?.email??"");
78131
}}
79132
onClose={()=>{
80-
setAutoComplete({
81-
value:value?.email??"",
82-
open:false,
83-
});
133+
setOpen(false);
134+
setFilter(undefined);
84135
}}
85136
onChange={(_,newValue)=>{
86137
onChange(newValue);
@@ -117,9 +168,7 @@ export const UserAutocomplete: FC<UserAutocompleteProps> = ({
117168
),
118169
endAdornment:(
119170
<>
120-
{usersQuery.isFetching&&autoComplete.open&&(
121-
<CircularProgresssize={16}/>
122-
)}
171+
{users===undefined&&open&&<CircularProgresssize={16}/>}
123172
{params.InputProps.endAdornment}
124173
</>
125174
),

‎site/src/pages/ManagementSettingsPage/GroupsPage/GroupPage.tsx‎

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ import {
1818
groupPermissions,
1919
removeMember,
2020
}from"api/queries/groups";
21-
importtype{Group,ReducedUser,User}from"api/typesGenerated";
21+
importtype{
22+
OrganizationMemberWithUserData,
23+
Group,
24+
ReducedUser,
25+
User,
26+
}from"api/typesGenerated";
2227
import{ErrorAlert}from"components/Alert/ErrorAlert";
2328
import{AvatarData}from"components/AvatarData/AvatarData";
2429
import{DeleteDialog}from"components/Dialogs/DeleteDialog/DeleteDialog";
@@ -39,7 +44,7 @@ import {
3944
PaginationStatus,
4045
TableToolbar,
4146
}from"components/TableToolbar/TableToolbar";
42-
import{UserAutocomplete}from"components/UserAutocomplete/UserAutocomplete";
47+
import{MemberAutocomplete}from"components/UserAutocomplete/UserAutocomplete";
4348
import{UserAvatar}from"components/UserAvatar/UserAvatar";
4449
import{typeFC,useState}from"react";
4550
import{Helmet}from"react-helmet-async";
@@ -133,11 +138,12 @@ export const GroupPage: FC = () => {
133138
{canUpdateGroup&&groupData&&!isEveryoneGroup(groupData)&&(
134139
<AddGroupMember
135140
isLoading={addMemberMutation.isLoading}
136-
onSubmit={async(user,reset)=>{
141+
organizationId={groupData.organization_id}
142+
onSubmit={async(member,reset)=>{
137143
try{
138144
awaitaddMemberMutation.mutateAsync({
139145
groupId,
140-
userId:user.id,
146+
userId:member.user_id,
141147
});
142148
reset();
143149
awaitgroupQuery.refetch();
@@ -231,11 +237,17 @@ export const GroupPage: FC = () => {
231237

232238
interfaceAddGroupMemberProps{
233239
isLoading:boolean;
234-
onSubmit:(user:User,reset:()=>void)=>void;
240+
onSubmit:(user:OrganizationMemberWithUserData,reset:()=>void)=>void;
241+
organizationId:string;
235242
}
236243

237-
constAddGroupMember:FC<AddGroupMemberProps>=({ isLoading, onSubmit})=>{
238-
const[selectedUser,setSelectedUser]=useState<User|null>(null);
244+
constAddGroupMember:FC<AddGroupMemberProps>=({
245+
isLoading,
246+
onSubmit,
247+
organizationId,
248+
})=>{
249+
const[selectedUser,setSelectedUser]=
250+
useState<OrganizationMemberWithUserData|null>(null);
239251

240252
constresetValues=()=>{
241253
setSelectedUser(null);
@@ -252,9 +264,10 @@ const AddGroupMember: FC<AddGroupMemberProps> = ({ isLoading, onSubmit }) => {
252264
}}
253265
>
254266
<Stackdirection="row"alignItems="center"spacing={1}>
255-
<UserAutocomplete
267+
<MemberAutocomplete
256268
css={styles.autoComplete}
257269
value={selectedUser}
270+
organizationId={organizationId}
258271
onChange={(newValue)=>{
259272
setSelectedUser(newValue);
260273
}}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp