github.com/aitjcize/Overlord@v0.0.0-20240314041920-104a804cf5e8/overlord/app/common/js/UploadProgressWidget.jsx (about) 1 // Copyright 2016 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // View for TerminalWindow: 6 // - UploadProgressWidget 7 // - [(ProgressBar|ProgressBar) ...] 8 9 var UploadProgressWidget = React.createClass({ 10 getInitialState: function () { 11 return {records: []}; 12 }, 13 // Perform upload 14 // Args: 15 // uploadRequestPath: the upload HTTP request path 16 // file: the javascript File object 17 // dest: destination filename, set to "undefined" if sid is set 18 // sid: terminal session ID, use to identify upload destionation 19 // done: callback to execute when upload is completed 20 upload: function (uploadRequestPath, file, dest, sid, done) { 21 var $this = this; 22 var query = "?"; 23 24 if (typeof(sid) != "undefined") { 25 query += "terminal_sid=" + sid; 26 } 27 28 if (typeof(dest) != "undefined") { 29 query += "&dest=" + dest; 30 } 31 32 function postFile(file) { 33 var id = randomID(); 34 var formData = new FormData(); 35 formData.append("file", file); 36 37 $this.addRecord({filename: file.name, id: id}); 38 $.ajax({ 39 xhr: function () { 40 var xhr = new window.XMLHttpRequest(); 41 xhr.upload.addEventListener("progress", function (event) { 42 if (event.lengthComputable) { 43 var percentComplete = Math.round(event.loaded * 100 / 44 event.total); 45 $("#" + id).css("width", percentComplete + "%"); 46 $("#" + id + " > .percent").text(percentComplete + "%"); 47 } 48 }, false); 49 return xhr; 50 }, 51 url: uploadRequestPath + query, 52 data: formData, 53 cache: false, 54 contentType: false, 55 processData: false, 56 type: "POST", 57 success: function (data) { 58 $("#" + id).css("width", "100%"); 59 // Display the progressbar for 1 more seconds after complete. 60 setTimeout(function () { 61 $this.removeRecord(id); 62 }.bind(this), 1000); 63 }, 64 complete: function () { 65 // Execute done callback 66 if (typeof(done) != "undefined") { 67 done(); 68 } 69 }, 70 error: function (data) { 71 var response = JSON.parse(data.responseText); 72 $this.addRecord( 73 {error: true, filename: file.name, id: id, 74 message: response.error}); 75 setTimeout(function () { 76 $this.removeRecord(id); 77 }.bind(this), 1000); 78 } 79 }); 80 }; 81 82 // Send GET to the API to do pre-check 83 $.ajax({ 84 url: uploadRequestPath + query + "&filename=" + file.name, 85 success: function (file) { 86 return function (data) { 87 // Actually upload the file 88 postFile(file); 89 }; 90 }(file), 91 error: function (file) { 92 return function (data) { 93 var id = randomID(); 94 var response = JSON.parse(data.responseText); 95 96 $this.addRecord( 97 {error: true, filename: file.name, id: id, 98 message: response.error}); 99 } 100 }(file), 101 type: "GET" 102 }); 103 }, 104 addRecord: function (record) { 105 this.setState(function (state, props) { 106 state.records.push(record); 107 }); 108 }, 109 removeRecord: function (id) { 110 this.setState(function (state, props) { 111 var index = state.records.findIndex(function (el, index, array) { 112 return el.id == id; 113 }); 114 if (index !== -1) { 115 state.records.splice(index, 1); 116 } 117 }); 118 }, 119 render: function () { 120 var display = ""; 121 if (this.state.records.length == 0) { 122 display = "upload-progress-bars-hidden"; 123 } 124 return ( 125 <div className={"upload-progress-bars panel panel-warning " + display}> 126 <div className="panel-heading">Upload Progress</div> 127 <div className="panel-body upload-progress-panel-body"> 128 { 129 this.state.records.map(function (record) { 130 if (record.error) { 131 return <ErrorBar progress={this} record={record} />; 132 } else { 133 return <ProgressBar record={record} />; 134 } 135 }.bind(this)) 136 } 137 </div> 138 </div> 139 ); 140 } 141 }); 142 143 var ProgressBar = React.createClass({ 144 render: function () { 145 return ( 146 <div className="progress"> 147 <div className="progress-bar upload-progress-bar" 148 id={this.props.record.id} role="progressbar" 149 aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"> 150 <span className="percent">0%</span> - {this.props.record.filename} 151 </div> 152 </div> 153 ); 154 } 155 }); 156 157 var ErrorBar = React.createClass({ 158 onCloseClicked: function () { 159 this.props.progress.removeRecord(this.props.record.id); 160 }, 161 render: function () { 162 return ( 163 <div className="progress-error"> 164 <div className="alert alert-danger upload-alert"> 165 <button type="button" className="close" aria-label="Close" 166 onClick={this.onCloseClicked}> 167 <span aria-hidden="true">×</span> 168 </button> 169 <b>{this.props.record.filename}</b><br /> 170 {this.props.record.message} 171 </div> 172 </div> 173 ); 174 } 175 });