github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/webui/src/pages/auth/groups/group/policies.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 {Link} from "../../../../lib/components/nav"; 21 import {useRouter} from "../../../../lib/hooks/router"; 22 23 24 const GroupPoliciesList = ({ groupId, 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.listGroupPolicies(groupId, after); 31 }, [groupId, after, refresh]); 32 33 useEffect(() => { setAttachError(null); }, [refresh, after]); 34 35 let content; 36 if (loading) content = <Loading/>; 37 else if (error) content= <AlertError error={error}/>; 38 else content = ( 39 <> 40 {attachError && <AlertError error={attachError}/>} 41 42 <DataTable 43 keyFn={policy => policy.id} 44 rowFn={policy => [ 45 <Link href={{pathname: '/auth/policies/:policyId', params: {policyId: policy.id}}}>{policy.id}</Link>, 46 <FormattedDate dateValue={policy.creation_date}/> 47 ]} 48 headers={['Policy ID', 'Created At']} 49 actions={[{ 50 key: 'Detach', 51 buttonFn: policy => <ConfirmationButton 52 size="sm" 53 variant="outline-danger" 54 modalVariant="danger" 55 msg={<span>Are you sure you{'\''}d like to detach policy <strong>{policy.id}</strong>?</span>} 56 onConfirm={() => { 57 auth.detachPolicyFromGroup(groupId, policy.id) 58 .catch(error => alert(error)) 59 .then(() => { setRefresh(!refresh) }) 60 }}> 61 Remove 62 </ConfirmationButton> 63 }]} 64 results={results} 65 emptyState={'No policies found'} 66 /> 67 68 <Paginator onPaginate={onPaginate} after={after} nextPage={nextPage}/> 69 70 71 {showAddModal && <AttachModal 72 show={showAddModal} 73 emptyState={'No policies found'} 74 filterPlaceholder={'Find Policy...'} 75 modalTitle={'Attach Policies'} 76 addText={'Attach Policies'} 77 searchFn={prefix => auth.listPolicies(prefix, "", 5).then(res => res.results)} 78 onHide={() => setShowAddModal(false)} 79 onAttach={(selected) => { 80 Promise.all(selected.map(policy => auth.attachPolicyToGroup(groupId, policy.id))) 81 .then(() => { setRefresh(!refresh); setAttachError(null) }) 82 .catch(error => { setAttachError(error) }) 83 .finally(() => { setShowAddModal(false) }) 84 }}/> 85 } 86 </> 87 ); 88 89 return ( 90 <> 91 <GroupHeader groupId={groupId} page={'policies'}/> 92 93 <ActionsBar> 94 <ActionGroup orientation="left"> 95 <Button variant="success" onClick={() => setShowAddModal(true)}>Attach Policy</Button> 96 </ActionGroup> 97 98 <ActionGroup orientation="right"> 99 <RefreshButton onClick={() => setRefresh(!refresh)}/> 100 </ActionGroup> 101 </ActionsBar> 102 103 <div className="mt-2"> 104 {content} 105 </div> 106 </> 107 ); 108 }; 109 110 const GroupPoliciesContainer = () => { 111 const router = useRouter(); 112 const { after } = router.query; 113 const { groupId } = router.params; 114 return (!groupId) ? <></> : <GroupPoliciesList 115 groupId={groupId} 116 after={(after) ? after : ""} 117 onPaginate={after => router.push({pathname: '/auth/groups/:groupId/policies', params: {groupId}, query: {after}})} 118 />; 119 }; 120 121 const GroupPoliciesPage = () => { 122 const [setActiveTab] = useOutletContext(); 123 useEffect(() => setActiveTab('groups'), [setActiveTab]); 124 return <GroupPoliciesContainer/>; 125 }; 126 127 export default GroupPoliciesPage;