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

Commit0b9ed57

Browse files
authored
feat: add delete custom role context menu button and modal (#14228)
* feat: delete custom role* fix: add doc comment
1 parentc648c54 commit0b9ed57

File tree

4 files changed

+93
-38
lines changed

4 files changed

+93
-38
lines changed

‎site/src/api/api.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -600,21 +600,27 @@ class ApiMethods {
600600
returnresponse.data;
601601
};
602602

603+
/**
604+
*@param organization Can be the organization's ID or name
605+
*/
603606
patchOrganizationRole=async(
604-
organizationId:string,
607+
organization:string,
605608
role:TypesGen.Role,
606609
):Promise<TypesGen.Role>=>{
607610
constresponse=awaitthis.axios.patch<TypesGen.Role>(
608-
`/api/v2/organizations/${organizationId}/members/roles`,
611+
`/api/v2/organizations/${organization}/members/roles`,
609612
role,
610613
);
611614

612615
returnresponse.data;
613616
};
614617

615-
deleteOrganizationRole=async(organizationId:string,roleName:string)=>{
618+
/**
619+
*@param organization Can be the organization's ID or name
620+
*/
621+
deleteOrganizationRole=async(organization:string,roleName:string)=>{
616622
awaitthis.axios.delete(
617-
`/api/v2/organizations/${organizationId}/members/roles/${roleName}`,
623+
`/api/v2/organizations/${organization}/members/roles/${roleName}`,
618624
);
619625
};
620626

‎site/src/api/queries/roles.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,37 @@ export const roles = () => {
1616
};
1717
};
1818

19-
exportconstorganizationRoles=(organizationId:string)=>{
19+
exportconstorganizationRoles=(organization:string)=>{
2020
return{
21-
queryKey:["organization",organizationId,"roles"],
22-
queryFn:()=>API.getOrganizationRoles(organizationId),
21+
queryKey:["organization",organization,"roles"],
22+
queryFn:()=>API.getOrganizationRoles(organization),
2323
};
2424
};
2525

2626
exportconstpatchOrganizationRole=(
2727
queryClient:QueryClient,
28-
organizationId:string,
28+
organization:string,
2929
)=>{
3030
return{
3131
mutationFn:(request:Role)=>
32-
API.patchOrganizationRole(organizationId,request),
32+
API.patchOrganizationRole(organization,request),
3333
onSuccess:async(updatedRole:Role)=>
3434
awaitqueryClient.invalidateQueries(
35-
getRoleQueryKey(organizationId,updatedRole.name),
35+
getRoleQueryKey(organization,updatedRole.name),
3636
),
3737
};
3838
};
3939

40-
exportconstdeleteRole=(
40+
exportconstdeleteOrganizationRole=(
4141
queryClient:QueryClient,
42-
organizationId:string,
42+
organization:string,
4343
)=>{
4444
return{
45-
mutationFn:API.deleteOrganizationRole,
45+
mutationFn:(roleName:string)=>
46+
API.deleteOrganizationRole(organization,roleName),
4647
onSuccess:async(_:void,roleName:string)=>
4748
awaitqueryClient.invalidateQueries(
48-
getRoleQueryKey(organizationId,roleName),
49+
getRoleQueryKey(organization,roleName),
4950
),
5051
};
5152
};

‎site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
importAddIconfrom"@mui/icons-material/AddOutlined";
22
importButtonfrom"@mui/material/Button";
3-
import{typeFC,useEffect}from"react";
3+
import{typeFC,useEffect,useState}from"react";
44
import{Helmet}from"react-helmet-async";
5-
import{useQuery}from"react-query";
5+
import{useMutation,useQuery,useQueryClient}from"react-query";
66
import{LinkasRouterLink,useParams}from"react-router-dom";
77
import{getErrorMessage}from"api/errors";
88
import{organizationPermissions}from"api/queries/organizations";
9-
import{organizationRoles}from"api/queries/roles";
10-
import{displayError}from"components/GlobalSnackbar/utils";
9+
import{deleteOrganizationRole,organizationRoles}from"api/queries/roles";
10+
importtype{Role}from"api/typesGenerated";
11+
import{DeleteDialog}from"components/Dialogs/DeleteDialog/DeleteDialog";
12+
import{displayError,displaySuccess}from"components/GlobalSnackbar/utils";
1113
import{Loader}from"components/Loader/Loader";
1214
import{SettingsHeader}from"components/SettingsHeader/SettingsHeader";
1315
import{Stack}from"components/Stack/Stack";
@@ -17,13 +19,18 @@ import { useOrganizationSettings } from "../ManagementSettingsLayout";
1719
importCustomRolesPageViewfrom"./CustomRolesPageView";
1820

1921
exportconstCustomRolesPage:FC=()=>{
22+
constqueryClient=useQueryClient();
2023
const{custom_roles:isCustomRolesEnabled}=useFeatureVisibility();
2124
const{organization:organizationName}=useParams()as{
2225
organization:string;
2326
};
2427
const{ organizations}=useOrganizationSettings();
2528
constorganization=organizations?.find((o)=>o.name===organizationName);
2629
constpermissionsQuery=useQuery(organizationPermissions(organization?.id));
30+
constdeleteRoleMutation=useMutation(
31+
deleteOrganizationRole(queryClient,organizationName),
32+
);
33+
const[roleToDelete,setRoleToDelete]=useState<Role>();
2734
constorganizationRolesQuery=useQuery(organizationRoles(organizationName));
2835
constfilteredRoleData=organizationRolesQuery.data?.filter(
2936
(role)=>role.built_in===false,
@@ -69,9 +76,31 @@ export const CustomRolesPage: FC = () => {
6976

7077
<CustomRolesPageView
7178
roles={filteredRoleData}
79+
onDeleteRole={setRoleToDelete}
7280
canAssignOrgRole={permissions.assignOrgRole}
7381
isCustomRolesEnabled={isCustomRolesEnabled}
7482
/>
83+
84+
<DeleteDialog
85+
key={roleToDelete?.name}
86+
isOpen={roleToDelete!==undefined}
87+
confirmLoading={deleteRoleMutation.isLoading}
88+
name={roleToDelete?.name??""}
89+
entity="role"
90+
onCancel={()=>setRoleToDelete(undefined)}
91+
onConfirm={async()=>{
92+
try{
93+
awaitdeleteRoleMutation.mutateAsync(roleToDelete!.name);
94+
setRoleToDelete(undefined);
95+
awaitorganizationRolesQuery.refetch();
96+
displaySuccess("Custom role deleted successfully!");
97+
}catch(error){
98+
displayError(
99+
getErrorMessage(error,"Failed to delete custom role"),
100+
);
101+
}
102+
}}
103+
/>
75104
</>
76105
);
77106
};

‎site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPageView.tsx

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
importtype{Interpolation,Theme}from"@emotion/react";
22
importAddOutlinedfrom"@mui/icons-material/AddOutlined";
3-
importKeyboardArrowRightfrom"@mui/icons-material/KeyboardArrowRight";
43
importButtonfrom"@mui/material/Button";
54
importSkeletonfrom"@mui/material/Skeleton";
65
importTablefrom"@mui/material/Table";
@@ -14,22 +13,30 @@ import { Link as RouterLink, useNavigate } from "react-router-dom";
1413
importtype{Role}from"api/typesGenerated";
1514
import{ChooseOne,Cond}from"components/Conditionals/ChooseOne";
1615
import{EmptyState}from"components/EmptyState/EmptyState";
16+
import{
17+
MoreMenu,
18+
MoreMenuContent,
19+
MoreMenuItem,
20+
MoreMenuTrigger,
21+
ThreeDotsButton,
22+
}from"components/MoreMenu/MoreMenu";
1723
import{Paywall}from"components/Paywall/Paywall";
1824
import{
1925
TableLoaderSkeleton,
2026
TableRowSkeleton,
2127
}from"components/TableLoader/TableLoader";
22-
import{useClickableTableRow}from"hooks";
2328
import{docs}from"utils/docs";
2429

2530
exporttypeCustomRolesPageViewProps={
2631
roles:Role[]|undefined;
32+
onDeleteRole:(role:Role)=>void;
2733
canAssignOrgRole:boolean;
2834
isCustomRolesEnabled:boolean;
2935
};
3036

3137
exportconstCustomRolesPageView:FC<CustomRolesPageViewProps>=({
3238
roles,
39+
onDeleteRole,
3340
canAssignOrgRole,
3441
isCustomRolesEnabled,
3542
})=>{
@@ -53,7 +60,7 @@ export const CustomRolesPageView: FC<CustomRolesPageViewProps> = ({
5360
<TableRow>
5461
<TableCellwidth="50%">Name</TableCell>
5562
<TableCellwidth="49%">Permissions</TableCell>
56-
<TableCellwidth="1%"></TableCell>
63+
<TableCellwidth="1%"/>
5764
</TableRow>
5865
</TableHead>
5966
<TableBody>
@@ -91,7 +98,12 @@ export const CustomRolesPageView: FC<CustomRolesPageViewProps> = ({
9198

9299
<Cond>
93100
{roles?.map((role)=>(
94-
<RoleRowkey={role.name}role={role}/>
101+
<RoleRow
102+
key={role.name}
103+
role={role}
104+
canAssignOrgRole={canAssignOrgRole}
105+
onDelete={()=>onDeleteRole(role)}
106+
/>
95107
))}
96108
</Cond>
97109
</ChooseOne>
@@ -106,26 +118,41 @@ export const CustomRolesPageView: FC<CustomRolesPageViewProps> = ({
106118

107119
interfaceRoleRowProps{
108120
role:Role;
121+
onDelete:()=>void;
122+
canAssignOrgRole:boolean;
109123
}
110124

111-
constRoleRow:FC<RoleRowProps>=({ role})=>{
125+
constRoleRow:FC<RoleRowProps>=({ role, onDelete, canAssignOrgRole})=>{
112126
constnavigate=useNavigate();
113-
constrowProps=useClickableTableRow({
114-
onClick:()=>navigate(role.name),
115-
});
116127

117128
return(
118-
<TableRowdata-testid={`role-${role.name}`}{...rowProps}>
129+
<TableRowdata-testid={`role-${role.name}`}>
119130
<TableCell>{role.display_name||role.name}</TableCell>
120131

121132
<TableCellcss={styles.secondary}>
122133
{role.organization_permissions.length}
123134
</TableCell>
124135

125136
<TableCell>
126-
<divcss={styles.arrowCell}>
127-
<KeyboardArrowRightcss={styles.arrowRight}/>
128-
</div>
137+
<MoreMenu>
138+
<MoreMenuTrigger>
139+
<ThreeDotsButton/>
140+
</MoreMenuTrigger>
141+
<MoreMenuContent>
142+
<MoreMenuItem
143+
onClick={()=>{
144+
navigate(role.name);
145+
}}
146+
>
147+
Edit
148+
</MoreMenuItem>
149+
{canAssignOrgRole&&(
150+
<MoreMenuItemdangeronClick={onDelete}>
151+
Delete&hellip;
152+
</MoreMenuItem>
153+
)}
154+
</MoreMenuContent>
155+
</MoreMenu>
129156
</TableCell>
130157
</TableRow>
131158
);
@@ -150,14 +177,6 @@ const TableLoader = () => {
150177
};
151178

152179
conststyles={
153-
arrowRight:(theme)=>({
154-
color:theme.palette.text.secondary,
155-
width:20,
156-
height:20,
157-
}),
158-
arrowCell:{
159-
display:"flex",
160-
},
161180
secondary:(theme)=>({
162181
color:theme.palette.text.secondary,
163182
}),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp