github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/webui/src/pages/auth/users/user/groups.jsx (about) 1 import React, { useEffect } from "react"; 2 import { useOutletContext } from "react-router-dom"; 3 4 import { UserHeaderWithContext } from "./userHeaderWithContext"; 5 import { 6 ActionGroup, 7 ActionsBar, 8 DataTable, 9 FormattedDate, 10 Loading, 11 AlertError, 12 RefreshButton, 13 } from "../../../../lib/components/controls"; 14 import Button from "react-bootstrap/Button"; 15 import { useAPIWithPagination } from "../../../../lib/hooks/api"; 16 import { auth } from "../../../../lib/api"; 17 import { Paginator } from "../../../../lib/components/pagination"; 18 import { useState } from "react"; 19 import { AttachModal } from "../../../../lib/components/auth/forms"; 20 import { ConfirmationButton } from "../../../../lib/components/modals"; 21 import { useRouter } from "../../../../lib/hooks/router"; 22 import { Link } from "../../../../lib/components/nav"; 23 24 const UserGroupsList = ({ userId, after, onPaginate }) => { 25 const [refresh, setRefresh] = useState(false); 26 const [showAddModal, setShowAddModal] = useState(false); 27 const [attachError, setAttachError] = useState(null); 28 29 const { results, loading, error, nextPage } = useAPIWithPagination(() => { 30 return auth.listUserGroups(userId, after); 31 }, [userId, after, refresh]); 32 33 let content; 34 if (loading) content = <Loading />; 35 else if (error) content = <AlertError error={error} />; 36 else 37 content = ( 38 <> 39 {attachError && <AlertError error={attachError} />} 40 41 <DataTable 42 keyFn={(group) => group.id} 43 rowFn={(group) => [ 44 <Link 45 href={{ 46 pathname: "/auth/groups/:groupId", 47 params: { groupId: group.id }, 48 }} 49 > 50 {group.name} 51 </Link>, 52 <FormattedDate dateValue={group.creation_date} />, 53 ]} 54 headers={["Group Name", "Created At"]} 55 actions={[ 56 { 57 key: "Remove", 58 buttonFn: (group) => ( 59 <ConfirmationButton 60 size="sm" 61 variant="outline-danger" 62 msg={ 63 <span> 64 Are you sure you{"'"}d like to remove user{" "} 65 <strong>{userId}</strong> from group{" "} 66 <strong>{group.name}</strong>? 67 </span> 68 } 69 onConfirm={() => { 70 auth 71 .removeUserFromGroup(userId, group.id) 72 .catch((error) => alert(error)) 73 .then(() => { 74 setRefresh(!refresh); 75 }); 76 }} 77 > 78 Remove 79 </ConfirmationButton> 80 ), 81 }, 82 ]} 83 results={results} 84 emptyState={"No groups found"} 85 /> 86 87 <Paginator onPaginate={onPaginate} after={after} nextPage={nextPage} /> 88 89 {showAddModal && ( 90 <AttachModal 91 show={showAddModal} 92 emptyState={"No groups found"} 93 filterPlaceholder={"Find Group..."} 94 modalTitle={"Add to Groups"} 95 addText={"Add to Groups"} 96 headers={["Select", "Group Name"]} 97 searchFn={(prefix) => 98 auth.listGroups(prefix, "", 5).then((res) => res.results) 99 } 100 onHide={() => setShowAddModal(false)} 101 onAttach={(selected) => { 102 Promise.all( 103 selected.map((group) => auth.addUserToGroup(userId, group.id)) 104 ) 105 .then(() => { 106 setRefresh(!refresh); 107 setAttachError(null); 108 }) 109 .catch((error) => { 110 setAttachError(error); 111 }) 112 .finally(() => { 113 setShowAddModal(false); 114 }); 115 }} 116 /> 117 )} 118 </> 119 ); 120 121 return ( 122 <> 123 <UserHeaderWithContext userId={userId} page={"groups"} /> 124 125 <ActionsBar> 126 <ActionGroup orientation="left"> 127 <Button variant="success" onClick={() => setShowAddModal(true)}> 128 Add User to Group 129 </Button> 130 </ActionGroup> 131 132 <ActionGroup orientation="right"> 133 <RefreshButton onClick={() => setRefresh(!refresh)} /> 134 </ActionGroup> 135 </ActionsBar> 136 137 <div className="mt-2">{content}</div> 138 </> 139 ); 140 }; 141 142 const UserGroupsContainer = () => { 143 const router = useRouter(); 144 const { after } = router.query; 145 const { userId } = router.params; 146 return !userId ? ( 147 <></> 148 ) : ( 149 <UserGroupsList 150 userId={userId} 151 after={after ? after : ""} 152 onPaginate={(after) => 153 router.push({ 154 pathname: "/auth/users/:userId/groups", 155 params: { userId }, 156 query: { after }, 157 }) 158 } 159 /> 160 ); 161 }; 162 163 const UserGroupsPage = () => { 164 const { setActiveTab } = useOutletContext(); 165 useEffect(() => setActiveTab("users"), [setActiveTab]); 166 return <UserGroupsContainer />; 167 }; 168 169 export default UserGroupsPage;