about summary refs log tree commit diff
path: root/uploader/templates/rqtl2/upload-rqtl2-bundle-step-01.html
diff options
context:
space:
mode:
Diffstat (limited to 'uploader/templates/rqtl2/upload-rqtl2-bundle-step-01.html')
-rw-r--r--uploader/templates/rqtl2/upload-rqtl2-bundle-step-01.html276
1 files changed, 276 insertions, 0 deletions
diff --git a/uploader/templates/rqtl2/upload-rqtl2-bundle-step-01.html b/uploader/templates/rqtl2/upload-rqtl2-bundle-step-01.html
new file mode 100644
index 0000000..07c240f
--- /dev/null
+++ b/uploader/templates/rqtl2/upload-rqtl2-bundle-step-01.html
@@ -0,0 +1,276 @@
+{%extends "base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
+{%from "upload_progress_indicator.html" import upload_progress_indicator%}
+
+{%block title%}Upload R/qtl2 Bundle{%endblock%}
+
+{%block contents%}
+{%macro rqtl2_file_help()%}
+<span class="form-text text-muted">
+  <p>
+    Provide a valid R/qtl2 zip file here. In particular, ensure your zip bundle
+    contains exactly one control file and the corresponding files mentioned in
+    the control file.
+  </p>
+  <p>
+    The control file can be either a YAML or JSON file. <em>ALL</em> other data
+    files in the zip bundle should be CSV files.
+  </p>
+  <p>See the
+    <a href="https://kbroman.org/qtl2/assets/vignettes/input_files.html"
+       target="_blank">
+      R/qtl2 file format specifications
+    </a>
+    for more details.
+  </p>
+</span>
+{%endmacro%}
+{{upload_progress_indicator()}}
+
+<div id="resumable-file-display-template"
+     class="panel panel-info"
+     style="display: none">
+  <div class="panel-heading"></div>
+  <div class="panel-body"></div>
+</div>
+
+
+<h2 class="heading">Upload R/qtl2 Bundle</h2>
+
+<div id="resumable-drop-area"
+     style="display:none;background:#eeeeee;min-height:12em;border-radius:0.5em;padding:1em;">
+  <p>
+    <a id="resumable-browse-button" href="#"
+       class="btn btn-info">Browse</a>
+  </p>
+  <p class="form-text text-muted">
+    You can drag and drop your file here, or click the browse button.
+    Click on the file to remove it.
+  </p>
+  {{rqtl2_file_help()}}
+  <div id="resumable-selected-files"
+       style="display:flex;flex-direction:row;flex-wrap: wrap;justify-content:space-around;gap:10px 20px;"></div>
+  <div id="resumable-class-buttons" style="text-align: right;">
+    <button id="resumable-upload-button"
+            class="btn btn-primary"
+            style="display: none">start upload</button>
+    <button id="resumable-cancel-upload-button"
+            class="btn btn-danger"
+            style="display: none">cancel upload</button>
+  </div>
+  <div id="resumable-progress-bar" class="progress" style="display: none">
+    <div class="progress-bar"
+         role="progress-bar"
+         aria-valuenow="60"
+         aria-valuemin="0"
+         aria-valuemax="100"
+         style="width: 0%;">
+      Uploading: 60%
+    </div>
+  </div>
+</div>
+
+<form id="frm-upload-rqtl2-bundle"
+      action="{{url_for('upload.rqtl2.upload_rqtl2_bundle',
+	      species_id=species.SpeciesId,
+	      population_id=population.InbredSetId)}}"
+      method="POST"
+      enctype="multipart/form-data"
+      data-resumable-target="{{url_for(
+                             'upload.rqtl2.upload_rqtl2_bundle_chunked_post',
+                             species_id=species.SpeciesId,
+                             population_id=population.InbredSetId)}}">
+  <input type="hidden" name="species_id" value="{{species.SpeciesId}}" />
+  <input type="hidden" name="population_id"
+	 value="{{population.InbredSetId}}" />
+
+  {{flash_all_messages()}}
+
+  <div class="form-group">
+    <legend class="heading">file upload</legend>
+    <label for="file-rqtl2-bundle" class="form-label">R/qtl2 bundle</label>
+    <input type="file" id="file-rqtl2-bundle" name="rqtl2_bundle_file"
+	   accept="application/zip, .zip"
+	   required="required"
+           class="form-control" />
+    {{rqtl2_file_help()}}
+  </div>
+
+  <button type="submit"
+          class="btn btn-primary"
+          data-toggle="modal"
+          data-target="#upload-progress-indicator">upload R/qtl2 bundle</button>
+</form>
+
+{%endblock%}
+
+{%block javascript%}
+<script src="{{url_for('base.node_modules',
+             filename='resumablejs/resumable.js')}}"></script>
+<script type="text/javascript" src="/static/js/upload_progress.js"></script>
+<script type="text/javascript">
+  function readBinaryFile(file) {
+      return new Promise((resolve, reject) => {
+          var _reader = new FileReader();
+          _reader.onload = (event) => {resolve(_reader.result);};
+          _reader.readAsArrayBuffer(file);
+      });
+  }
+
+  function computeFileChecksum(file) {
+      return readBinaryFile(file)
+          .then((content) => {
+              return window.crypto.subtle.digest(
+                  "SHA-256", new Uint8Array(content));
+          }).then((digest) => {
+              return Uint8ArrayToHex(new Uint8Array(digest))
+          });
+  }
+
+  function Uint8ArrayToHex(arr) {
+      var toHex = (val) => {
+          _hex = val.toString(16);
+          if(_hex.length < 2) {
+              return "0" + val;
+          }
+          return _hex;
+      };
+      _hexstr = ""
+      arr.forEach((val) => {_hexstr += toHex(val)});
+      return _hexstr
+  }
+
+  var r = Resumable({
+      target: $("#frm-upload-rqtl2-bundle").attr("data-resumable-target"),
+      fileType: ["zip"],
+      maxFiles: 1,
+      forceChunkSize: true,
+      generateUniqueIdentifier: (file, event) => {
+          return computeFileChecksum(file).then((checksum) => {
+              var _relativePath = (file.webkitRelativePath
+                                   || file.relativePath
+                                   || file.fileName
+                                   || file.name);
+              return checksum + "-" + _relativePath.replace(
+                  /[^a-zA-Z0-9_-]/img, "");
+          });
+      }
+  });
+
+  if(r.support) {
+      //Hide form and display drag&drop UI
+      $("#frm-upload-rqtl2-bundle").css("display", "none");
+      $("#resumable-drop-area").css("display", "block");
+
+      // Define UI elements for browse and drag&drop
+      r.assignDrop(document.getElementById("resumable-drop-area"));
+      r.assignBrowse(document.getElementById("resumable-browse-button"));
+
+      // Event handlers
+
+      function display_files(files) {
+          displayArea = $("#resumable-selected-files")
+          displayArea.empty();
+          files.forEach((file) => {
+              var displayElement = $(
+                  "#resumable-file-display-template").clone();
+              displayElement.removeAttr("id");
+              displayElement.css("display", "");
+              displayElement.find(".panel-heading").text(file.fileName);
+              list = $("<ul></ul>");
+              list.append($("<li><strong>Name</strong>: "
+                            + (file.name
+                               || file.fileName
+                               || file.relativePath
+                               || file.webkitRelativePath)
+                            + "</li>"));
+              list.append($("<li><strong>Size</strong>: "
+                            + (file.size / (1024*1024)).toFixed(2)
+                            + " MB</li>"));
+              list.append($("<li><strong>Unique Identifier</strong>: "
+                            + file.uniqueIdentifier + "</li>"));
+              list.append($("<li><strong>Mime</strong>: "
+                            + file.file.type
+                            + "</li>"));
+              displayElement.find(".panel-body").append(list);
+              displayElement.appendTo("#resumable-selected-files");
+          });
+      }
+
+      r.on("filesAdded", function(files) {
+          display_files(files);
+          $("#resumable-upload-button").css("display", "");
+          $("#resumable-upload-button").on("click", (event) => {
+              r.upload();
+          });
+      });
+
+      r.on("uploadStart", (event) => {
+          $("#resumable-upload-button").css("display", "none");
+          $("#resumable-cancel-upload-button").css("display", "");
+          $("#resumable-cancel-upload-button").on("click", (event) => {
+              r.files.forEach((file) => {
+                  if(file.isUploading()) {
+                      file.abort();
+                  }
+              });
+              $("#resumable-cancel-upload-button").css("display", "none");
+              $("#resumable-upload-button").on("click", (event) => {
+                  r.files.forEach((file) => {file.retry();});
+              });
+              $("#resumable-upload-button").css("display", "");
+          });
+      });
+
+      r.on("progress", () => {
+          var progress = (r.progress() * 100).toFixed(2);
+          var pbar = $("#resumable-progress-bar > .progress-bar");
+          $("#resumable-progress-bar").css("display", "");
+          pbar.css("width", progress+"%");
+          pbar.attr("aria-valuenow", progress);
+          pbar.text("Uploading: " + progress + "%");
+      })
+
+      r.on("fileSuccess", (file, message) => {
+          if(message != "OK") {
+              var uri = (window.location.protocol
+                         + "//"
+                         + window.location.host
+                         + message);
+              window.location.replace(uri);
+          }
+      });
+
+      r.on("error", (message, file) => {
+          filename = (file.webkitRelativePath
+                      || file.relativePath
+                      || file.fileName
+                      || file.name);
+          jsonmsg = JSON.parse(message);
+          alert("There was an error while uploading your file '"
+                + filename
+                + "'. The error message was:\n\n\t"
+                + jsonmsg.error
+                + " ("
+                + jsonmsg.statuscode
+                + "): " + jsonmsg.message);
+      })
+  } else {
+      setup_upload_handlers(
+          "frm-upload-rqtl2-bundle", make_data_uploader(
+	      function (form) {
+	          var formdata = new FormData();
+	          formdata.append(
+		      "species_id",
+		      form.querySelector('input[name="species_id"]').value);
+	          formdata.append(
+		      "population_id",
+		      form.querySelector('input[name="population_id"]').value);
+	          formdata.append(
+		      "rqtl2_bundle_file",
+		      form.querySelector("#file-rqtl2-bundle").files[0]);
+	          return formdata;
+	      }));
+  }
+</script>
+{%endblock%}