diff --git a/minerva_analysis/client/src/js/services/importFormValidation.js b/minerva_analysis/client/src/js/services/importFormValidation.js index 65709f51e..44dd04c6f 100644 --- a/minerva_analysis/client/src/js/services/importFormValidation.js +++ b/minerva_analysis/client/src/js/services/importFormValidation.js @@ -2,30 +2,30 @@ // Example starter JavaScript for disabling form submissions if there are invalid fields (function () { - 'use strict' - - // Fetch all the forms we want to apply custom Bootstrap validation styles to - var forms = document.querySelectorAll('.needs-validation') - // Loop over them and prevent submission - Array.prototype.slice.call(forms) - .forEach(function (form) { - form.addEventListener('submit', function (event) { - if (!form.checkValidity()) { - event.preventDefault() - event.stopPropagation() - }else{ - onupload(); - } - form.classList.add('was-validated') - }, true) - }) + 'use strict' + + // Fetch all the forms we want to apply custom Bootstrap validation styles to + var forms = document.querySelectorAll('.needs-validation') + // Loop over them and prevent submission + Array.prototype.slice.call(forms) + .forEach(function (form) { + form.addEventListener('submit', function (event) { + if (!form.checkValidity()) { + event.preventDefault() + event.stopPropagation() + } else { + onupload(); + } + form.classList.add('was-validated') + }, true) + }) })() //add listener -d3.select("#import_type").on("change",update); +d3.select("#import_type").on("change", update); -function update(){ - if(d3.select("#import_type").property("checked")){ +function update() { + if (d3.select("#import_type").property("checked")) { console.log('is checked'); d3.select('#mcmicro_form').style("display", 'inline'); d3.select('#custom_form').style("display", 'none'); @@ -36,15 +36,15 @@ function update(){ } //check if path and channel file exist in the specified MCMICRO output foder -async function checkMCOutputFolder(caller){ +async function checkMCOutputFolder(caller) { let path_res = await checkPathExistence(caller); - if (path_res == true){ + if (path_res == true) { let channel_res = await checkChannelExistence(caller) - if (channel_res == false){ - d3.select("#" + 'mcmicro_path_validation_text').html('No image channel file found under this path.') - } - }else{ - d3.select("#" + 'mcmicro_path_validation_text').html('Please provide a valid path.') + if (channel_res == false) { + d3.select("#" + 'mcmicro_path_validation_text').html('No image channel file found under this path.') + } + } else { + d3.select("#" + 'mcmicro_path_validation_text').html('Please provide a valid path.') } } @@ -53,11 +53,11 @@ async function checkCSVFileExistence(caller) { const self = this; //get folder path from the input text field - let maskSelectionField = d3.select('#'+ caller.id); + let maskSelectionField = d3.select('#' + caller.id); let mask = maskSelectionField.property("value"); //get selected mask type from the selection field - let pathInputField = d3.select('#'+ 'mcmicro_output_folder'); + let pathInputField = d3.select('#' + 'mcmicro_output_folder'); let path = pathInputField.property("value"); try { @@ -71,15 +71,15 @@ async function checkCSVFileExistence(caller) { body: JSON.stringify( { path: path, - mask : mask + mask: mask } ) }); let response_data = await response.json(); - if (response_data == true){ + if (response_data == true) { maskSelectionField.attr("class", "form-control is-valid"); maskSelectionField.node().setCustomValidity(''); - }else{ + } else { d3.select("#" + 'mcmicro_mask_validation_text').html('No corresponding csv file found.') maskSelectionField.attr("class", "form-control is-invalid"); maskSelectionField.node().setCustomValidity('Invalid'); @@ -95,9 +95,12 @@ async function checkChannelExistence(caller) { const self = this; //get folder path from the input text field - let pathInputField = d3.select('#'+ caller.id); + let pathInputField = d3.select('#' + caller.id); let path = pathInputField.property("value"); + let imageSelectionField = d3.select('#' + caller.id); + let image = imageSelectionField.property("value"); + try { //check if corresponsindg csv file exists let response = await fetch('/check_mc_channel_file_existence', { @@ -109,14 +112,15 @@ async function checkChannelExistence(caller) { body: JSON.stringify( { path: path, + image: image } ) }); let response_data = await response.json(); - if (response_data == true){ + if (response_data == true) { pathInputField.attr("class", "form-control is-valid"); pathInputField.node().setCustomValidity(''); - }else{ + } else { // d3.select("#" + 'mcmicro_path_validation_text').html('No image channel file found under this path.') pathInputField.attr("class", "form-control is-invalid"); pathInputField.node().setCustomValidity('No image channel file found under this path.'); @@ -132,11 +136,11 @@ async function checkChannelExistence(caller) { //check if path exists (mcmicro naming specific) async function checkFileExistence(caller) { const self = this; - let inputField = d3.select('#'+ caller.id); + let inputField = d3.select('#' + caller.id); //get segmentation folder path from the input text field let path = inputField.property("value"); -try { + try { //get available segmentation masks in mcmicro directory from server let response = await fetch('/check_file_existence', { method: 'POST', @@ -151,12 +155,12 @@ try { ) }); let response_data = await response.json(); - if (response_data == true){ + if (response_data == true) { inputField.attr("class", "form-control is-valid"); inputField.node().setCustomValidity(''); - }else{ - inputField.attr("class", "form-control is-invalid"); - inputField.node().setCustomValidity('Invalid'); + } else { + inputField.attr("class", "form-control is-invalid"); + inputField.node().setCustomValidity('Invalid'); } return response_data; } catch (e) { @@ -169,11 +173,11 @@ try { //check if path exists (mcmicro naming specific) async function checkDatasetExistence(caller) { const self = this; - let inputField = d3.select('#'+ caller.id); + let inputField = d3.select('#' + caller.id); //get segmentation folder path from the input text field let datasetName = inputField.property("value"); -try { + try { //get available segmentation masks in mcmicro directory from server let response = await fetch('/dataset_existence', { method: 'POST', @@ -188,12 +192,12 @@ try { ) }); let response_data = await response.json(); - if (response_data == false){ + if (response_data == false) { inputField.attr("class", "form-control is-valid"); inputField.node().setCustomValidity(''); - }else{ - inputField.attr("class", "form-control is-invalid"); - inputField.node().setCustomValidity('Dataset name already exists. Choose a different name.'); + } else { + inputField.attr("class", "form-control is-invalid"); + inputField.node().setCustomValidity('Dataset name already exists. Choose a different name.'); } // inputField.node().reportValidity(); return response_data; @@ -205,11 +209,11 @@ try { //check if path exists (mcmicro naming specific) async function checkPathExistence(caller) { const self = this; - let inputField = d3.select('#'+ caller.id); + let inputField = d3.select('#' + caller.id); //get segmentation folder path from the input text field let path = inputField.property("value"); -try { + try { //get available segmentation masks in mcmicro directory from server let response = await fetch('/check_path_existence', { method: 'POST', @@ -224,12 +228,12 @@ try { ) }); let response_data = await response.json(); - if (response_data == true){ + if (response_data == true) { inputField.attr("class", "form-control is-valid"); inputField.node().setCustomValidity(''); - }else{ - inputField.attr("class", "form-control is-invalid"); - inputField.node().setCustomValidity('Path does not exist.'); + } else { + inputField.attr("class", "form-control is-invalid"); + inputField.node().setCustomValidity('Path does not exist.'); } // inputField.node().reportValidity(); return response_data; @@ -239,17 +243,56 @@ try { } //get a list of available files in a folder (mcmicro naming specific) -async function fillSegFileList() { +async function fillCSVFileList() { const self = this; //get segmentation folder path from the input text field let path = d3.select('#mcmicro_output_folder').property("value"); //remove old selection options as soon as path changes - var select_field = document.getElementById("mcmicro_masks"); - while (select_field.length > 0) { - select_field.remove(0); + + + try { + //get available segmentation masks in mcmicro directory from server + let response = await fetch('/get_mc_csv_file_list', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify( + { + path: path, + } + ) + }); + let response_data = await response.json(); + var select_field = document.getElementById("mcmicro_masks"); + select_field.innerHTML = ""; + //fill select form field with new options + response_data.forEach(function (option_value) { + var option = document.createElement("option"); + option.text = option_value; + option.value = option_value; + select_field.add(option); + }) + + //return the filled field + return response_data; + } catch (e) { + console.log("Error Getting Segmentation File List", e); } +} + +//get a list of available files in a folder (mcmicro naming specific) +async function fillImgFileList() { + const self = this; + + //get segmentation folder path from the input text field + let path = d3.select('#mcmicro_output_folder').property("value"); + + + try { //get available segmentation masks in mcmicro directory from server @@ -266,9 +309,53 @@ async function fillSegFileList() { ) }); let response_data = await response.json(); + //remove old selection options as soon as path changes + var select_field = document.getElementById("mcmicro_images"); + select_field.innerHTML = ""; + //fill select form field with new options + response_data.forEach(function (option_value) { + var option = document.createElement("option"); + option.text = option_value; + option.value = option_value; + select_field.add(option); + }) + + //return the filled field + return response_data; + } catch (e) { + console.log("Error Getting Channel File List", e); + } +} + +//get a list of available files in a folder (mcmicro naming specific) +async function fillSegFileList() { + const self = this; + //get segmentation folder path from the input text field + let path = d3.select('#mcmicro_output_folder').property("value"); + + //remove old selection options as soon as path changes + + + try { + //get available segmentation masks in mcmicro directory from server + let response = await fetch('/get_mc_segmentation_file_list', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify( + { + path: path, + } + ) + }); + let response_data = await response.json(); + var select_field = document.getElementById("mcmicro_seg"); + select_field.innerHTML = ""; //fill select form field with new options - response_data.forEach(function(option_value){ + response_data.forEach(function (option_value) { var option = document.createElement("option"); option.text = option_value; option.value = option_value; @@ -282,6 +369,7 @@ async function fillSegFileList() { } } + let uploadPercentage = 0; let ajaxForm = $('form').ajaxForm({ uploadProgress: function (event, position, total, percentComplete) { diff --git a/minerva_analysis/client/templates/upload.html b/minerva_analysis/client/templates/upload.html index d745b872d..8a21464f7 100644 --- a/minerva_analysis/client/templates/upload.html +++ b/minerva_analysis/client/templates/upload.html @@ -96,7 +96,7 @@
- +
Valid.
Please provide a valid path. @@ -106,7 +106,7 @@
- +
+ +
Valid.
+
+ No image files found under this path. +
+
+
+
+
+ +
+
+ +
Valid.
+
+ No image files found under this path. +
+
+
diff --git a/minerva_analysis/server/routes/import_routes.py b/minerva_analysis/server/routes/import_routes.py index c8216ee79..ad2c4d23b 100644 --- a/minerva_analysis/server/routes/import_routes.py +++ b/minerva_analysis/server/routes/import_routes.py @@ -1,5 +1,7 @@ # CRUD for Datasources +# import sys +# sys.path.append('/c/Users/Sophie/minerva_analysis/') from minerva_analysis import app, get_config_names, config_json_path, data_path, cwd_path from minerva_analysis.server.utils import mostFrequentLongestSubstring, pre_normalization from minerva_analysis.server.models import data_model @@ -19,6 +21,7 @@ from os import walk import io + total_tasks = 100 completed_task = 0 current_task = '' @@ -211,26 +214,27 @@ def upload_file_page(): if request.form.get('mcmicro_name') != '': datasetName = request.form['mcmicro_name'] - # get label file from user specified path - labelName = request.form['masks'] - labelFolder = str(PurePath('unmicst-' + mcmicroDirName, labelName + '.ome.tif')) - labelFile = PurePath(directory, 'segmentation', labelFolder) - - # also check for older seg file format (.tif) - if not Path(directory, 'segmentation', labelFolder).is_file(): - labelFolder = str(PurePath('unmicst-' + mcmicroDirName, labelName + '.tif')) - labelFile = PurePath(directory, 'segmentation', labelFolder) + #label file + labelFile = request.form.get('segs') + labelFile = labelFile.replace('"', '') # remove " characters + labelFile = Path(labelFile) + labelName = os.path.splitext(labelFile.name)[0] - # get csv file from user specified path - csvName = mcmicroDirName + '--unmicst_' + labelName + '.csv' # could use labelName to have dynamic csv but usually only cell available. - csvPath = str(PurePath(directory, 'quantification', csvName)) + #csv file + csvPath = request.form.get('masks'); + csvPath = csvPath.replace('"', '') # remove " characters + csvPath = Path(csvPath) + pathsSplit = PurePath(csvPath).parts + csvName = pathsSplit[len(pathsSplit) - 1] - # get channel file from user specified path - channelFile = PurePath(directory, 'registration', mcmicroDirName + '.ome.tif') + #channel file + channelFile = request.form.get('images') + channelFile = channelFile.replace('"', '') # remove " characters + channelFile = Path(channelFile) - #further processing + # Creates file path using name input; should change this so that it just takes directory name? file_path = str(PurePath(Path.cwd(), data_path, datasetName)) - if not Path(file_path).exists(): + if not Path(file_path).exists(): # If no directory for existing name for dataset input will create one Path(file_path).mkdir() total_tasks = 2 @@ -510,22 +514,55 @@ def list_tif_files_in_dir(): #path and type information from upload post_data = json.loads(request.data) if 'path' in post_data: - path = Path(post_data['path'], "segmentation"); + # path = Path(post_data['path'], "segmentation"); + path = Path(post_data['path']) #for segmentation, mcmicro specifics - mask_types = ["cell", "cellRing", "cyto", "cytoRing", "nuclei", "nucleiRing"] + # mask_types = ["cell", "cellRing", "cyto", "cytoRing", "nuclei", "nucleiRing"] if path.is_dir(): for (dirpath, dirnames, filenames) in walk(path): for (file) in filenames: - file = file.split('.') - if file[0] in mask_types: - files.append(file[0]) + file_split = file.split('.') + # if file[0] in mask_types: + # files.append(file[0]) + if (file_split[-1] == 'tif' and file_split[-2] == 'ome') or (file_split[-1] == 'tiff' and file_split[-2] == 'ome'): + file_path = os.path.join(dirpath, file) + files.append(file_path) print(files) else: print('error in segmentation path'); return serialize_and_submit_json(files) +@app.route('/get_mc_csv_file_list', methods=['POST']) +def list_csv_files_in_dir(): + # return all seg files found in the seg subfolder (mc micro specific) + files = [] + files.append('') + + #path and type information from upload + post_data = json.loads(request.data) + if 'path' in post_data: + # path = Path(post_data['path'], "segmentation"); + path = Path(post_data['path']) + + #for segmentation, mcmicro specifics + # mask_types = ["cell", "cellRing", "cyto", "cytoRing", "nuclei", "nucleiRing"] + + if path.is_dir(): + for (dirpath, dirnames, filenames) in walk(path): + for (file) in filenames: + file_split = file.split('.') + # if file[0] in mask_types: + # files.append(file[0]) + if file_split[-1] == 'csv': + file_path = os.path.join(dirpath, file) + files.append(file_path) + print(files) + else: + print('error in csv path'); + return serialize_and_submit_json(files) + @app.route('/check_mc_csv_file_existence', methods=['POST']) def check_mc_csv_file_existence(): # path and type information from upload @@ -537,14 +574,11 @@ def check_mc_csv_file_existence(): directory = Path(post_data['path']) pathsSplit = PurePath(directory).parts mcmicroDirName = pathsSplit[len(pathsSplit) - 1] - - # check if csv file exists - # csvName = 'nmicst-' + mcmicroDirName + '_' + mask + '.csv' - csvName = mcmicroDirName + '--unmicst_' + mask + '.csv' - csvPath = Path(directory, 'quantification', csvName) - - if csvPath.is_file(): + + path = Path(post_data['mask']) + if path.suffix.lower() == '.csv': return serialize_and_submit_json(True) + return serialize_and_submit_json(False) @app.route('/check_mc_channel_file_existence', methods=['POST']) @@ -552,19 +586,12 @@ def check_mc_channel_file_existence(): # path and type information from upload post_data = json.loads(request.data) if 'path' in post_data: - #get path and last bit which defines the dirname - directory = Path(post_data['path']) - try: - pathsSplit = PurePath(directory).parts - mcmicroDirName = pathsSplit[len(pathsSplit) - 1] - # check if channel file exists - channelFile = Path(directory, 'registration', mcmicroDirName + '.ome.tif') or Path(directory, 'registration', mcmicroDirName + '.ome.tiff') + if 'image' in post_data: + path = Path(post_data['image']) + if path.suffix.lower() == '.tif' or '.tiff': + return serialize_and_submit_json(True) - if channelFile.is_file(): - return serialize_and_submit_json(True) - except Exception as e: - return serialize_and_submit_json(False) return serialize_and_submit_json(False) @app.route('/check_file_existence', methods=['POST'])