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">&times;</span>
   168              </button>
   169              <b>{this.props.record.filename}</b><br />
   170                {this.props.record.message}
   171            </div>
   172          </div>
   173      );
   174    }
   175  });