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