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