github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/webui/src/pages/repositories/services/import_data.jsx (about) 1 import {imports} from "../../../lib/api"; 2 import Row from "react-bootstrap/Row"; 3 import InputGroup from 'react-bootstrap/InputGroup'; 4 import Col from "react-bootstrap/Col"; 5 import {LinearProgress} from "@mui/material"; 6 import React, {useState} from "react"; 7 import Button from "react-bootstrap/Button"; 8 import Alert from "react-bootstrap/Alert"; 9 import Form from "react-bootstrap/Form"; 10 import {MetadataFields} from "../../../lib/components/repository/changes"; 11 12 const ImportPhase = { 13 NotStarted: 0, 14 InProgress: 1, 15 Completed: 2, 16 Failed: 3, 17 } 18 19 const startImport = async (setImportID, prependPath, commitMsg, sourceRef, repoId, refId, metadata = {}) => { 20 const response = await imports.create(repoId, refId, sourceRef, prependPath, commitMsg, metadata); 21 setImportID(response.id); 22 } 23 24 const ImportProgress = ({numObjects}) => { 25 return (<Row> 26 <Col> 27 <div className='import-text'> 28 Imported 29 <span className='import-num-objects'> {numObjects} </span> 30 objects so far... 31 </div> 32 <div> 33 <LinearProgress color="success"/> 34 </div> 35 <div> 36 <small><abbr><br/>Please leave this tab open while import is in progress...</abbr></small> 37 </div> 38 </Col> 39 </Row>); 40 } 41 42 const ImportDone = ({numObjects, branch = ''}) => { 43 return (<Row> 44 <Col> 45 <div className={"mt-10 mb-2 me-2 row mt-4 import-success"}> 46 <p><strong>Success!</strong></p> 47 </div> 48 <div className='import-text'> 49 <strong> 50 <span className='import-num-objects'> {numObjects} </span> 51 </strong> objects imported and committed into branch 52 <strong> 53 <span className='import-num-objects'> {branch} </span> 54 </strong>. 55 </div> 56 </Col> 57 </Row>); 58 } 59 const ExecuteImportButton = ({isEnabled, importPhase, importFunc, doneFunc}) => { 60 switch (importPhase) { 61 case ImportPhase.Completed: 62 return <Button 63 variant="success" 64 onClick={doneFunc} 65 disabled={!isEnabled}> 66 Close 67 </Button> 68 case ImportPhase.Failed: 69 case ImportPhase.NotStarted: 70 return <Button 71 variant="success" 72 disabled={!isEnabled} 73 onClick={importFunc}> 74 Import 75 </Button> 76 case ImportPhase.InProgress: 77 return <Button 78 variant="success" 79 disabled={true}> 80 Importing... 81 </Button> 82 } 83 } 84 85 const ImportForm = ({ 86 config, 87 pathStyle, 88 sourceRef, 89 destRef, 90 path, 91 commitMsgRef, 92 repo, 93 branch, 94 updateSrcValidity, 95 metadataFields, 96 setMetadataFields, 97 err = null, 98 ...rest 99 }) => { 100 const [isSourceValid, setIsSourceValid] = useState(true); 101 const importValidityRegexStr = config.import_validity_regex; 102 const storageNamespaceValidityRegex = RegExp(importValidityRegexStr); 103 const updateSourceURLValidity = () => { 104 if (!sourceRef.current.value) { 105 updateSrcValidity(true); 106 setIsSourceValid(true); 107 return 108 } 109 const isValid = storageNamespaceValidityRegex.test(sourceRef.current.value); 110 updateSrcValidity(isValid); 111 setIsSourceValid(isValid); 112 }; 113 const sourceURIExample = config ? config.blockstore_namespace_example : "s3://my-bucket/path/"; 114 return (<div {...rest}> 115 <Alert variant="info"> 116 This feature doesn't copy data. It only creates pointers in the lakeFS metadata.<br/> 117 lakeFS will never change objects in the import source. 118  <a href="https://docs.lakefs.io/howto/import.html" target="_blank" rel="noreferrer">Learn more</a> 119 </Alert> 120 <Form> 121 <Form.Group className='mt-4 form-group'> 122 <Form.Label>Import from</Form.Label> 123 <Form.Control type="text" name="import-from" style={pathStyle} ref={sourceRef} autoFocus 124 placeholder={sourceURIExample} 125 onChange={updateSourceURLValidity}/> 126 {isSourceValid === false && 127 <Form.Text className="text-danger"> 128 {`Import source should match the following pattern: "${importValidityRegexStr}"`} 129 </Form.Text> 130 } 131 {isSourceValid && 132 <Form.Text style={{color: 'grey', justifyContent: "space-between"}}> 133 A URI on the object store to import from.<br/> 134 </Form.Text> 135 } 136 </Form.Group> 137 <Form.Group className='mt-4 form-group'> 138 <Form.Label>Destination</Form.Label> 139 <InputGroup> 140 <div className={"input-group-prepend"}> 141 <InputGroup.Text className={"text-muted"}>lakefs://{repo}/{branch}/</InputGroup.Text> 142 </div> 143 <Form.Control type="text" name="destination" ref={destRef} defaultValue={path}/> 144 </InputGroup> 145 <Form.Text style={{color: 'grey'}} md={{offset: 2, span: 10000}}> 146 Leave empty to import to the repository's root. 147 </Form.Text> 148 </Form.Group> 149 150 <Form.Group className='mt-4 form-group'> 151 <Form.Label>Commit message</Form.Label> 152 <Form.Control type="text" ref={commitMsgRef} name="commit-message"/> 153 </Form.Group> 154 <MetadataFields className={"mt-4"} metadataFields={metadataFields} setMetadataFields={setMetadataFields}/> 155 {err && 156 <Alert className="mt-4 small" variant={"danger"}>{err.message}</Alert>} 157 </Form> 158 </div>) 159 } 160 161 export { 162 startImport, ImportProgress, ImportDone, ExecuteImportButton, ImportForm, ImportPhase, 163 }