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

Commite4a06f8

Browse files
authored
feat: add workspace share button and dialog (#21299)
resolvescoder/internal#1074<img width="621" height="421" alt="Screenshot 2025-12-16 at 20 31 33"src="https://github.com/user-attachments/assets/c886d261-1e98-444b-9346-5f30055772ae"/><img width="648" height="483" alt="Screenshot 2025-12-16 at 20 31 16"src="https://github.com/user-attachments/assets/c247cef2-38b0-4255-b41b-cc91de2cdf2b"/>
1 parentf1b930b commite4a06f8

File tree

6 files changed

+301
-199
lines changed

6 files changed

+301
-199
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
importtype{
2+
Group,
3+
User,
4+
WorkspaceACL,
5+
WorkspaceRole,
6+
WorkspaceUser,
7+
}from"api/typesGenerated";
8+
import{
9+
UserOrGroupAutocomplete,
10+
typeUserOrGroupAutocompleteValue,
11+
}from"modules/workspaces/WorkspaceSharingForm/UserOrGroupAutocomplete";
12+
import{
13+
AddWorkspaceMemberForm,
14+
RoleSelectField,
15+
}from"modules/workspaces/WorkspaceSharingForm/WorkspaceSharingForm";
16+
import{typeFC,useState}from"react";
17+
18+
typeAddWorkspaceUserOrGroupProps={
19+
organizationID:string;
20+
isLoading:boolean;
21+
workspaceACL:WorkspaceACL|undefined;
22+
onSubmit:(
23+
value:WorkspaceUser|Group|({role:WorkspaceRole}&User),
24+
role:WorkspaceRole,
25+
reset:()=>void,
26+
)=>void;
27+
};
28+
29+
exportconstAddWorkspaceUserOrGroup:FC<AddWorkspaceUserOrGroupProps>=({
30+
organizationID,
31+
isLoading,
32+
workspaceACL,
33+
onSubmit,
34+
})=>{
35+
const[selectedOption,setSelectedOption]=
36+
useState<UserOrGroupAutocompleteValue>(null);
37+
const[selectedRole,setSelectedRole]=useState<WorkspaceRole>("use");
38+
constexcludeFromAutocomplete=workspaceACL
39+
?[...workspaceACL.group, ...workspaceACL.users]
40+
:[];
41+
42+
constresetValues=()=>{
43+
setSelectedOption(null);
44+
setSelectedRole("use");
45+
};
46+
47+
return(
48+
<AddWorkspaceMemberForm
49+
isLoading={isLoading}
50+
disabled={!selectedRole||!selectedOption}
51+
onSubmit={()=>{
52+
if(selectedOption&&selectedRole){
53+
onSubmit(
54+
{
55+
...selectedOption,
56+
role:selectedRole,
57+
},
58+
selectedRole,
59+
resetValues,
60+
);
61+
}
62+
}}
63+
>
64+
<UserOrGroupAutocomplete
65+
organizationId={organizationID}
66+
value={selectedOption}
67+
exclude={excludeFromAutocomplete}
68+
onChange={(newValue)=>{
69+
setSelectedOption(newValue);
70+
}}
71+
/>
72+
73+
<RoleSelectField
74+
value={selectedRole}
75+
onChange={setSelectedRole}
76+
disabled={isLoading}
77+
/>
78+
</AddWorkspaceMemberForm>
79+
);
80+
};

site/src/pages/WorkspaceSettingsPage/WorkspaceSharingPage/UserOrGroupAutocomplete.tsx renamed to site/src/modules/workspaces/WorkspaceSharingForm/UserOrGroupAutocomplete.tsx

File renamed without changes.

‎site/src/modules/workspaces/WorkspaceSharingForm/WorkspaceSharingForm.tsx‎

Lines changed: 150 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ interface WorkspaceSharingFormProps {
148148
updatingGroupId?:WorkspaceGroup["id"]|undefined;
149149
onRemoveGroup:(group:Group)=>void;
150150
addMemberForm?:ReactNode;
151+
isCompact?:boolean;
151152
}
152153

153154
exportconstWorkspaceSharingForm:FC<WorkspaceSharingFormProps>=({
@@ -161,143 +162,168 @@ export const WorkspaceSharingForm: FC<WorkspaceSharingFormProps> = ({
161162
onUpdateGroup,
162163
onRemoveGroup,
163164
addMemberForm,
165+
isCompact,
164166
})=>{
165167
constisEmpty=Boolean(
166168
workspaceACL&&
167169
workspaceACL.users.length===0&&
168170
workspaceACL.group.length===0,
169171
);
170172

171-
return(
172-
<divclassName="flex flex-col gap-4">
173-
{Boolean(error)&&<ErrorAlerterror={error}/>}
174-
{canUpdatePermissions&&addMemberForm}
175-
<Table>
176-
<TableHeader>
177-
<TableRow>
178-
<TableHeadclassName="w-[60%] py-2">Member</TableHead>
179-
<TableHeadclassName="w-[40%] py-2">Role</TableHead>
180-
<TableHeadclassName="w-[1%] py-2"/>
181-
</TableRow>
182-
</TableHeader>
183-
<TableBody>
184-
{!workspaceACL ?(
185-
<TableLoader/>
186-
) :isEmpty ?(
187-
<TableRow>
188-
<TableCellcolSpan={999}>
189-
<EmptyState
190-
message="No shared members or groups yet"
191-
description="Add a member or group using the controls above"
173+
consttableHeader=(
174+
<TableHeader>
175+
<TableRow>
176+
<TableHeadclassName="w-[50%] py-2">Member</TableHead>
177+
<TableHeadclassName="w-[40%] py-2">Role</TableHead>
178+
<TableHeadclassName="w-[10%] py-2"/>
179+
</TableRow>
180+
</TableHeader>
181+
);
182+
183+
consttableBody=(
184+
<TableBody>
185+
{!workspaceACL ?(
186+
<TableLoader/>
187+
) :isEmpty ?(
188+
<TableRow>
189+
<TableCellcolSpan={999}>
190+
<EmptyState
191+
message="No shared members or groups yet"
192+
description="Add a member or group using the controls above"
193+
isCompact={isCompact}
194+
/>
195+
</TableCell>
196+
</TableRow>
197+
) :(
198+
<>
199+
{workspaceACL.group.map((group)=>(
200+
<TableRowkey={group.id}>
201+
<TableCellclassName="py-2 w-[50%]">
202+
<AvatarData
203+
avatar={
204+
<Avatar
205+
size="lg"
206+
fallback={group.display_name||group.name}
207+
src={group.avatar_url}
208+
/>
209+
}
210+
title={group.display_name||group.name}
211+
subtitle={getGroupSubtitle(group)}
192212
/>
193213
</TableCell>
214+
<TableCellclassName="py-2 w-[40%]">
215+
{canUpdatePermissions ?(
216+
<RoleSelect
217+
value={group.role}
218+
disabled={updatingGroupId===group.id}
219+
onValueChange={(value)=>onUpdateGroup(group,value)}
220+
/>
221+
) :(
222+
<divclassName="capitalize">{group.role}</div>
223+
)}
224+
</TableCell>
225+
226+
<TableCellclassName="py-2 w-[10%]">
227+
{canUpdatePermissions&&(
228+
<DropdownMenu>
229+
<DropdownMenuTriggerasChild>
230+
<Button
231+
size="icon-lg"
232+
variant="subtle"
233+
aria-label="Open menu"
234+
>
235+
<EllipsisVerticalaria-hidden="true"/>
236+
<spanclassName="sr-only">Open menu</span>
237+
</Button>
238+
</DropdownMenuTrigger>
239+
<DropdownMenuContentalign="end">
240+
<DropdownMenuItem
241+
className="text-content-destructive focus:text-content-destructive"
242+
onClick={()=>onRemoveGroup(group)}
243+
>
244+
Remove
245+
</DropdownMenuItem>
246+
</DropdownMenuContent>
247+
</DropdownMenu>
248+
)}
249+
</TableCell>
194250
</TableRow>
195-
) :(
196-
<>
197-
{workspaceACL.group.map((group)=>(
198-
<TableRowkey={group.id}>
199-
<TableCellclassName="py-2">
200-
<AvatarData
201-
avatar={
202-
<Avatar
203-
size="lg"
204-
fallback={group.display_name||group.name}
205-
src={group.avatar_url}
206-
/>
207-
}
208-
title={group.display_name||group.name}
209-
subtitle={getGroupSubtitle(group)}
210-
/>
211-
</TableCell>
212-
<TableCellclassName="py-2">
213-
{canUpdatePermissions ?(
214-
<RoleSelect
215-
value={group.role}
216-
disabled={updatingGroupId===group.id}
217-
onValueChange={(value)=>onUpdateGroup(group,value)}
218-
/>
219-
) :(
220-
<divclassName="capitalize">{group.role}</div>
221-
)}
222-
</TableCell>
251+
))}
223252

224-
<TableCellclassName="py-2">
225-
{canUpdatePermissions&&(
226-
<DropdownMenu>
227-
<DropdownMenuTriggerasChild>
228-
<Button
229-
size="icon-lg"
230-
variant="subtle"
231-
aria-label="Open menu"
232-
>
233-
<EllipsisVerticalaria-hidden="true"/>
234-
<spanclassName="sr-only">Open menu</span>
235-
</Button>
236-
</DropdownMenuTrigger>
237-
<DropdownMenuContentalign="end">
238-
<DropdownMenuItem
239-
className="text-content-destructive focus:text-content-destructive"
240-
onClick={()=>onRemoveGroup(group)}
241-
>
242-
Remove
243-
</DropdownMenuItem>
244-
</DropdownMenuContent>
245-
</DropdownMenu>
246-
)}
247-
</TableCell>
248-
</TableRow>
249-
))}
253+
{workspaceACL.users.map((user)=>(
254+
<TableRowkey={user.id}>
255+
<TableCellclassName="py-2 w-[50%]">
256+
<AvatarData
257+
title={user.username}
258+
subtitle={user.name}
259+
src={user.avatar_url}
260+
/>
261+
</TableCell>
262+
<TableCellclassName="py-2 w-[40%]">
263+
{canUpdatePermissions ?(
264+
<RoleSelect
265+
value={user.role}
266+
disabled={updatingUserId===user.id}
267+
onValueChange={(value)=>onUpdateUser(user,value)}
268+
/>
269+
) :(
270+
<divclassName="capitalize">{user.role}</div>
271+
)}
272+
</TableCell>
250273

251-
{workspaceACL.users.map((user)=>(
252-
<TableRowkey={user.id}>
253-
<TableCellclassName="py-2">
254-
<AvatarData
255-
title={user.username}
256-
subtitle={user.name}
257-
src={user.avatar_url}
258-
/>
259-
</TableCell>
260-
<TableCellclassName="py-2">
261-
{canUpdatePermissions ?(
262-
<RoleSelect
263-
value={user.role}
264-
disabled={updatingUserId===user.id}
265-
onValueChange={(value)=>onUpdateUser(user,value)}
266-
/>
267-
) :(
268-
<divclassName="capitalize">{user.role}</div>
269-
)}
270-
</TableCell>
274+
<TableCellclassName="py-2 w-[10%]">
275+
{canUpdatePermissions&&(
276+
<DropdownMenu>
277+
<DropdownMenuTriggerasChild>
278+
<Button
279+
size="icon-lg"
280+
variant="subtle"
281+
aria-label="Open menu"
282+
>
283+
<EllipsisVerticalaria-hidden="true"/>
284+
<spanclassName="sr-only">Open menu</span>
285+
</Button>
286+
</DropdownMenuTrigger>
287+
<DropdownMenuContentalign="end">
288+
<DropdownMenuItem
289+
className="text-content-destructive focus:text-content-destructive"
290+
onClick={()=>onRemoveUser(user)}
291+
>
292+
Remove
293+
</DropdownMenuItem>
294+
</DropdownMenuContent>
295+
</DropdownMenu>
296+
)}
297+
</TableCell>
298+
</TableRow>
299+
))}
300+
</>
301+
)}
302+
</TableBody>
303+
);
271304

272-
<TableCellclassName="py-2">
273-
{canUpdatePermissions&&(
274-
<DropdownMenu>
275-
<DropdownMenuTriggerasChild>
276-
<Button
277-
size="icon-lg"
278-
variant="subtle"
279-
aria-label="Open menu"
280-
>
281-
<EllipsisVerticalaria-hidden="true"/>
282-
<spanclassName="sr-only">Open menu</span>
283-
</Button>
284-
</DropdownMenuTrigger>
285-
<DropdownMenuContentalign="end">
286-
<DropdownMenuItem
287-
className="text-content-destructive focus:text-content-destructive"
288-
onClick={()=>onRemoveUser(user)}
289-
>
290-
Remove
291-
</DropdownMenuItem>
292-
</DropdownMenuContent>
293-
</DropdownMenu>
294-
)}
295-
</TableCell>
296-
</TableRow>
297-
))}
298-
</>
299-
)}
300-
</TableBody>
305+
if(isCompact){
306+
return(
307+
<divclassName="flex flex-col gap-4">
308+
{Boolean(error)&&<ErrorAlerterror={error}/>}
309+
{canUpdatePermissions&&addMemberForm}
310+
<div>
311+
<Table>{tableHeader}</Table>
312+
<divclassName="max-h-60 overflow-y-auto">
313+
<Table>{tableBody}</Table>
314+
</div>
315+
</div>
316+
</div>
317+
);
318+
}
319+
320+
return(
321+
<divclassName="flex flex-col gap-4">
322+
{Boolean(error)&&<ErrorAlerterror={error}/>}
323+
{canUpdatePermissions&&addMemberForm}
324+
<Table>
325+
{tableHeader}
326+
{tableBody}
301327
</Table>
302328
</div>
303329
);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp