6a5052fcb442fafa62ef6800d34246a7ba631891 chmalee Thu Nov 14 12:55:15 2024 -0800 Make file type no longer selectable, just infer from the extension and warn (correctly now) if the file type is not supported. Remove the file type batch select. TODO: add a hub name batch change and make the batch change update correctly on change diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js index e4003ce..9c6ccb4 100644 --- src/hg/js/hgMyData.js +++ src/hg/js/hgMyData.js @@ -6,40 +6,48 @@ if (!num) {return "n/a";} if (num < (1000 * 1024)) { return `${(num/1000).toFixed(1)}kb`; } else if (num < (1000 * 1000 * 1024)) { return `${((num/1000)/1000).toFixed(1)}mb`; } else { return `${(((num/1000)/1000)/1000).toFixed(1)}gb`; } } // make our Uppy instance: const uppy = new Uppy.Uppy({ debug: true, onBeforeUpload: (files) => { // set all the fileTypes and genomes from their selects + let doUpload = true; for (let [key, file] of Object.entries(files)) { - if (!file.meta.genome || !file.meta.fileType) { - uppy.getPlugin("Dashboard").info("error!"); + if (!file.meta.genome) { + uppy.info(`Error: No genome selected for file ${file.name}!`, 'error', 2000); + doUpload = false; + continue; + } else if (!file.meta.fileType) { + uppy.info(`Error: File type not supported, please rename file: ${file.name}!`, 'error', 2000); + doUpload = false; + continue; } uppy.setFileMeta(file.id, { fileName: file.name, fileSize: file.size, lastModified: file.data.lastModified, }); } + return doUpload; }, }); var hubCreate = (function() { let uiState = { // our object for keeping track of the current UI and what to do toUpload: {}, // set of file objects keyed by name input: null, // the hidden input element pickedList: null, // the <div> for displaying files in toUpload pendingQueue: [], // our queue of pending [tus.Upload, file], kind of like the toUpload object fileList: [], // the files this user has uploaded, initially populated by the server // on page load, but gets updated as the user uploades/deletes files hubList: [], // the hubs this user has created/uploaded, initially populated by server // on page load, but gets updated as the user creates/deletes hubs userUrl: "", // the web accesible path where the uploads are stored for this user }; @@ -167,44 +175,49 @@ let extensionMap = { "bigBed": [".bb", ".bigbed"], "bam": [".bam"], "vcf": [".vcf"], "vcfTabix": [".vcf.gz", "vcf.bgz"], "bigWig": [".bw", ".bigwig"], "hic": [".hic"], "cram": [".cram"], "bigBarChart": [".bigbarchart"], "bigGenePred": [".bgp", ".biggenepred"], "bigMaf": [".bigmaf"], "bigInteract": [".biginteract"], "bigPsl": [".bigpsl"], "bigChain": [".bigchain"], + "bamIndex": [".bam.bai", ".bai"], + "tabixIndex": [".vcf.gz.tbi", "vcf.bgz.tbi"], }; function detectFileType(fileName) { let fileLower = fileName.toLowerCase(); for (let fileType in extensionMap) { for (let extIx in extensionMap[fileType]) { let ext = extensionMap[fileType][extIx]; if (fileLower.endsWith(ext)) { return fileType; } } } - //TODO: raise an error - alert(`file extension for ${fileName} not found, please explicitly select it`); + //we could alert here but instead just explicitly set the value to null + //and let the backend reject it instead, forcing the user to rename their + //file + //alert(`file extension for ${fileName} not found, please explicitly select it`); + return null; } /* function submitPickedFiles() { let tusdServer = getTusdEndpoint(); let onBeforeRequest = function(req) { let xhr = req.getUnderlyingObject(req); xhr.withCredentials = true; }; let onSuccess = function(req, metadata) { // remove the selected file from the input element and the ul list // FileList is a read only setting, so we have to make @@ -863,59 +876,61 @@ addSelectsForFile(file) { /* create two selects for the file object, to include the db and type */ const id = "uppy_" + file.id; let fileDiv = document.getElementById(id); // this might not exist yet depending on where we are in the render cycle if (fileDiv) { let dbSelectId = "db_select_" + file.id; if (!document.getElementById(dbSelectId)) { let dbSelect = document.createElement("select"); dbSelect.id = dbSelectId; let dbOpts = makeGenomeSelectOptions(); this.createOptsForSelect(dbSelect, dbOpts); fileDiv.appendChild(dbSelect); } + /* let typeSelectId = "type_select_" + file.id; if (!document.getElementById(typeSelectId)) { let typeSelect = document.createElement("select"); typeSelect.id = typeSelectId; let typeOpts = makeTypeSelectOptions(); this.createOptsForSelect(typeSelect, typeOpts); fileDiv.appendChild(typeSelect); } + */ } } removeBatchSelectsFromDashboard() { let batchSelectDiv = document.getElementById("batch-selector-div"); if (batchSelectDiv) { batchSelectDiv.remove(); } } addBatchSelectsToDashboard() { if (!document.getElementById("batch-selector-div")) { let batchSelectDiv = document.createElement("div"); batchSelectDiv.id = "batch-selector-div"; let batchDbSelect = document.createElement("select"); - let batchTypeSelect = document.createElement("select"); + //let batchTypeSelect = document.createElement("select"); this.createOptsForSelect(batchDbSelect, makeGenomeSelectOptions()); - this.createOptsForSelect(batchTypeSelect, makeTypeSelectOptions()); + //this.createOptsForSelect(batchTypeSelect, makeTypeSelectOptions()); batchSelectDiv.textContent = "Change options for all files"; batchSelectDiv.appendChild(batchDbSelect); - batchSelectDiv.appendChild(batchTypeSelect); + //batchSelectDiv.appendChild(batchTypeSelect); batchSelectDiv.style.display = "flex"; batchSelectDiv.style.justifyContent = "center"; if (window.matchMedia("(prefers-color-scheme: dark)").matches) { batchSelectDiv.style.color = "#eaeaea"; } // append the batch changes to the bottom of the file list, for some reason // I can't append to the actual Dashboard-files, it must be getting emptied // and re-rendered or something let uppyFilesDiv = document.querySelector(".uppy-Dashboard-progressindicators"); if (uppyFilesDiv) { uppyFilesDiv.insertBefore(batchSelectDiv, uppyFilesDiv.firstChild); } } } @@ -951,77 +966,95 @@ }); } uninstall() { // not really used because we aren't ever uninstalling the uppy instance this.uppy.off("file-added"); } } let uppyOptions = { //target: "#filePickerModal", // this seems nice but then the jquery css interferes with // the uppy css trigger: ".uploadButton", showProgressDetails: true, note: "Example text in the note field", meta: {"genome": null, "fileType": null}, metaFields: (file) => { - const fields = [{id: 'name', name: 'File name'}]; - fields.push({ + const fields = [{ + id: 'name', + name: 'File name', + render: ({value, onChange, required, form}, h) => { + return h('input', + {type: "text", + value: value, + onChange: e => { + onChange(e.target.value); + file.meta.fileType = detectFileType(e.target.value); + }, + required: required, + form: form, + } + ); + }, + }, + { id: 'genome', name: 'Genome', render: ({value, onChange}, h) => { return h('select', {onChange: e => onChange(e.target.value)}, makeGenomeSelectOptions().map( (genomeObj) => { return h('option', genomeObj, genomeObj.label); }) ); }, - }); + }, + /* fields.push({ id: 'fileType', name: 'File Type', render: ({value, onChange}, h) => { return h( 'select', {onChange: e => { if (e.target.value === "Auto-detect from extension") { onChange(detectFileType(file.name)); } else { onChange(e.target.value); } }}, makeTypeSelectOptions().map( (typeObj) => { return h('option', typeObj, typeObj.label); }) ); }, }); - fields.push({ + */ + { id: 'parentDir', name: 'Hub Name', render: ({value, onChange, required, form}, h) => { return h('input', {type: 'text', required: required, form: form, value: hubNameDefault, } ); }, - }); + }]; return fields; }, - restricted: {requiredMetaFields: ["genome", "fileType"]}, + restricted: {requiredMetaFields: ["genome"]}, closeModalOnClickOutside: true, closeAfterFinish: true, theme: 'auto', autoOpen: "metaEditor", }; let tusOptions = { endpoint: getTusdEndpoint(), withCredentials: true, retryDelays: null, }; uppy.use(Uppy.Dashboard, uppyOptions); uppy.use(Uppy.Tus, tusOptions); uppy.use(BatchChangePlugin, {target: Uppy.Dashboard}); uppy.on('upload-success', (file, response) => { const metadata = file.meta;