github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/webui/src/lib/components/policy.jsx (about) 1 import React, {useEffect, useRef, useState} from "react"; 2 3 import Table from "react-bootstrap/Table"; 4 import Modal from "react-bootstrap/Modal"; 5 import Form from "react-bootstrap/Form"; 6 import {FormControl} from "react-bootstrap"; 7 import Button from "react-bootstrap/Button"; 8 import {AlertError, FormattedDate} from "./controls"; 9 10 export const PolicyEditor = ({ show, onHide, onSubmit, policy = null, noID = false, isCreate = false, validationFunction = null, externalError = null }) => { 11 const [error, setError] = useState(null); 12 const idField = useRef(null); 13 const bodyField = useRef(null); 14 15 useEffect(() => { 16 if (policy === null && !!idField.current && idField.current.value === "") 17 idField.current.focus(); 18 }); 19 20 const [body, setBody] = useState('') 21 useEffect(() => { 22 if (policy !== null) { 23 const newBody = JSON.stringify(policy, null, 4); 24 setBody(newBody); 25 setSavedBody(newBody); 26 } 27 }, [policy]); 28 29 const [savedBody, setSavedBody] = useState(null); 30 31 const submit = () => { 32 if (validationFunction) { 33 const validationResult = validationFunction(idField.current.value); 34 if (!validationResult.isValid) { 35 setError(validationResult.errorMessage); 36 return; 37 } 38 } 39 const statement = bodyField.current.value; 40 try { 41 JSON.parse(statement); 42 } catch (error) { 43 setError(error); 44 return false; 45 } 46 const promise = (policy === null) ? onSubmit(idField.current.value, statement) : onSubmit(statement) 47 return promise 48 .then((res) => { 49 setSavedBody(statement); 50 setError(null); 51 return res; 52 }) 53 .catch((err) => { 54 setError(err); 55 return null; 56 }); 57 }; 58 59 const hide = () => { 60 setError(null); 61 if (savedBody !== null) { 62 setBody(savedBody); 63 } 64 onHide(); 65 }; 66 const actionName = policy === null || isCreate ? 'Create' : 'Edit' 67 return ( 68 <Modal show={show} onHide={hide}> 69 <Modal.Header closeButton> 70 <Modal.Title>{actionName} Policy</Modal.Title> 71 </Modal.Header> 72 73 <Modal.Body> 74 <Form onSubmit={e => { 75 e.preventDefault(); 76 submit(); 77 }}> 78 {(policy === null) && !noID && ( 79 <Form.Group className="mb-3"> 80 <FormControl ref={idField} autoFocus placeholder="Policy ID (e.g. 'MyRepoReadWrite')" type="text"/> 81 </Form.Group> 82 )} 83 <Form.Group className="mb-3"> 84 <FormControl 85 className="policy-document" 86 ref={bodyField} 87 placeholder="Policy JSON Document" 88 rows={15} 89 as="textarea" 90 type="text" 91 onChange={e => setBody(e.target.value)} 92 value={body}/> 93 </Form.Group> 94 </Form> 95 96 {(!!error) && <AlertError className="mt-3" error={error}/>} 97 {(!!externalError) && <AlertError className="mt-3" error={externalError}/>} 98 99 </Modal.Body> 100 101 <Modal.Footer> 102 <Button onClick={submit} variant="success">Save</Button> 103 <Button onClick={hide} variant="secondary">Cancel</Button> 104 </Modal.Footer> 105 </Modal> 106 ); 107 }; 108 109 export const PolicyDisplay = ({ policy, asJSON }) => { 110 let childComponent; 111 if (asJSON) { 112 childComponent = (<pre className={"policy-body"}>{JSON.stringify({statement: policy.statement}, null, 4)}</pre>); 113 } else { 114 childComponent = ( 115 <Table> 116 <thead> 117 <tr> 118 <th>Actions</th> 119 <th>Resource</th> 120 <th>Effect</th> 121 </tr> 122 </thead> 123 <tbody> 124 {policy.statement.map((statement, i) => { 125 return ( 126 <tr key={`statement-${i}`}> 127 <td><code>{statement.action.join(", ")}</code></td> 128 <td><code>{statement.resource}</code></td> 129 <td><strong style={{'color': (statement.effect === "allow") ? 'green':'red'}}>{statement.effect}</strong></td> 130 </tr> 131 ); 132 })} 133 </tbody> 134 </Table> 135 136 ); 137 } 138 139 return ( 140 <div> 141 <p> 142 <strong>Created At: </strong> 143 <FormattedDate dateValue={policy.creation_date}/> 144 </p> 145 {childComponent} 146 </div> 147 ); 148 };