e07b87b45f9293c3f45337303886450c390b2585 hiram Tue May 12 13:10:56 2026 -0700 protect against duplicated pending entries in the ottoRequest table refs #31811 diff --git src/hg/js/liftRequest.js src/hg/js/liftRequest.js index 3154c58c304..9e7dcea3c79 100644 --- src/hg/js/liftRequest.js +++ src/hg/js/liftRequest.js @@ -1,21 +1,52 @@ /* jshint esnext: true */ var assembly1Value = ""; var assembly2Value = ""; var genome1 = ""; var genome2 = ""; +// matches the ottoRequest README.txt and ottoRequestView.cgi STATUS_NAMES +var STATUS_LABELS = { + 0: "received by API", + 1: "acknowledged, email sent", + 2: "galaxy job started", + 3: "galaxy done, download started", + 4: "downloaded, track files made", + 5: "symlinks ready, awaiting push", + 6: "push complete", + 7: "ERROR", + 8: "COMPLETE (final email sent)" +}; + +function pendingMessageFor(status, requestTime) { + var label = STATUS_LABELS[status] || ("status " + status); + if (status === 7) { + return "A previous request for these assemblies (submitted on " + + requestTime + ") encountered an error. " + + "Please contact genome-www@soe.ucsc.edu for help."; + } + if (status === 8) { + return "A request for these assemblies (submitted on " + + requestTime + ") has already completed. " + + "If the chain files are not yet available, please contact" + + " genome-www@soe.ucsc.edu."; + } + return "A request for these assemblies was submitted on " + + requestTime + " and is currently in progress (" + label + ")." + + " You will receive an email when it completes."; +} + /* check if a file exists at the specified URL */ function fileExists(url, callback) { fetch(url, { method: 'HEAD' }) .then(response => { callback(response.ok); }) .catch(() => { callback(false); }); } // Convert GCA_029289425.2 into the path: GCA/028/289/425/GCA_029289425.2 function gcPath(identifier) { var parts = identifier.split('_'); var prefix = parts[0]; @@ -70,60 +101,72 @@ fileExists(liftPath2, function(exists) { if (exists) { document.getElementById("genome2Link").href = browser2; document.getElementById("genome2Link").textContent = assembly2Value; document.getElementById("genome2LiftOver").href = liftPath2; document.getElementById("genome2LiftOver").textContent = asm2 + " to " + asm1; document.getElementById("liftExists").style.display = "block"; document.getElementById("emailForm").style.display = "none"; document.getElementById("commentsForm").style.display = "none"; document.getElementById("submitButton").style.display = "none"; } }); + } else if (response.pending) { + showPending(response.pendingStatus, response.pendingRequestTime); } }) .catch(error => { console.error("Error fetching liftOver list:", error); }); } // end of function checkAssemblyCompatibility(asm1, asm2) function checkBothAssembliesSelected() { if (genome1 && genome2) { // Both assemblies are now selected checkAssemblyCompatibility(genome1, genome2); } } function resetFormVisibility() { document.getElementById("liftExists").style.display = "none"; + document.getElementById("pendingRequest").style.display = "none"; document.getElementById("errorMessage").style.display = "none"; document.getElementById("emailForm").style.display = "block"; document.getElementById("commentsForm").style.display = "block"; document.getElementById("submitButton").style.display = "block"; } function showError(heading, errorMsg) { document.getElementById("errorHeading").textContent = heading; document.getElementById("errorText").textContent = errorMsg; document.getElementById("errorMessage").style.display = "block"; document.getElementById("emailForm").style.display = "none"; document.getElementById("commentsForm").style.display = "none"; document.getElementById("submitButton").style.display = "none"; } +function showPending(status, requestTime) { + document.getElementById("pendingMessage").textContent = + pendingMessageFor(status, requestTime); + document.getElementById("pendingRequest").style.display = "block"; + document.getElementById("emailForm").style.display = "none"; + document.getElementById("commentsForm").style.display = "none"; + document.getElementById("submitButton").style.display = "none"; +} + function assembly1Select(selectEle, item) { selectEle.innerHTML = item.label; assembly1Value = item.value || item.label; genome1 = item.genome; // console.log("asm1:", JSON.stringify(item, null, 2)); resetFormVisibility(); checkBothAssembliesSelected(); } function assembly2Select(selectEle, item) { selectEle.innerHTML = item.label; assembly2Value = item.value || item.label; genome2 = item.genome; // console.log("asm2:", JSON.stringify(item, null, 2)); resetFormVisibility(); @@ -187,30 +230,35 @@ var errorMsg = "Error submitting request"; var heading = "Error"; try { var parsed = JSON.parse(text); if (parsed.error) { errorMsg = parsed.error; } } catch(e) { errorMsg = text || response.statusText || errorMsg; } if (response.status === 429) { heading = "Daily limit reached"; errorMsg = "Thank you for your interest. " + errorMsg + " If you have an urgent need, please contact us at" + " genome-www@soe.ucsc.edu."; + } else if (response.status === 409) { + heading = "Already submitted"; + errorMsg = errorMsg + + " If you have not seen the completion email, please" + + " contact us at genome-www@soe.ucsc.edu."; } showError(heading, errorMsg); } }); }) .catch((error) => { // Network or other fetch errors var errorMsg = error.message || "Unknown error occurred"; showError("Error", errorMsg); }); } // end of function submitForm() function dismissLiftExists() { resetFormVisibility(); document.getElementById("genomeSearch1").value = ""; @@ -244,17 +292,18 @@ initSpeciesAutoCompleteDropdown('genomeSearch2', boundSelect2, "/cgi-bin/hubApi/findGenome?browser=mustExist;q=", null, null, onSearchError); let btn2 = document.getElementById("genomeSearchButton2"); btn2.addEventListener("click", () => { let val = document.getElementById("genomeSearch2").value; $("[id='genomeSearch2']").autocompleteCat("search", val); }); // restore saved email if it exists var savedEmail = localStorage.getItem('liftRequestEmail'); if (savedEmail) { document.getElementById("emailInput").value = savedEmail; } document.getElementById("dismissLiftExists").addEventListener("click", dismissLiftExists); + document.getElementById("dismissPending").addEventListener("click", resetFormVisibility); document.getElementById("dismissError").addEventListener("click", resetFormVisibility); });