From 6d193ba6e8bd42d2b9ec8680bd2a882472e1a52f Mon Sep 17 00:00:00 2001 From: Akhil Rana Date: Wed, 22 Apr 2020 07:23:16 +0530 Subject: [PATCH] Batch Loader Enhancements (#389) * batchLoader_enhance * Better_ErrorHandling_and_Improvemets * edge_case_file_Extension --- apps/batchloader/batchLoader.js | 389 +++++++++++++++++++++++++----- apps/batchloader/batchloader.html | 155 +++++++++++- apps/table.html | 15 +- 3 files changed, 480 insertions(+), 79 deletions(-) diff --git a/apps/batchloader/batchLoader.js b/apps/batchloader/batchLoader.js index d53c78def..ca9bc29a9 100644 --- a/apps/batchloader/batchLoader.js +++ b/apps/batchloader/batchLoader.js @@ -1,77 +1,122 @@ -$(document).ready(function() { -// console.log('hi'); -}); +let existingFiles = []; +let existingSlides = []; +let tokens = null; +let files= null; +let fileNames = null; +let slideNames = null; +let originalFileNames = null; +let startUrl = '../../loader/upload/start'; +let continueUrl = '../../loader/upload/continue/'; +let finishUrl = '../../loader/upload/finish/'; +let checkUrl = '../../loader/data/one/'; +let chunkSize = 5*1024*1024; +let finishUploadSuccess = false; +const allowedExtensions = ['svs', 'tif', 'tiff', 'vms', 'vmu', 'ndpi', 'scn', 'mrxs', 'bif', 'svslide']; + -$('#filesInput').change(function() { - let files = $(this).prop('files'); - let fileNames = $.map(files, function(val) { - return val.name; +$(document).ready(function() { + $('#files').show(400); + let store = new Store('../../data/'); + store.findSlide().then((response) => { + for (i=0; i { + console.log(error); }); - $('#filesInputLabel').html(fileNames.length + ' files selected'); - if (fileNames.length>0) { - $('#filesDetails').css('display', 'block'); - } else { - $('#filesDetails').css('display', 'none'); + + $('#filesInput').change(function() { + let files = $(this).prop('files'); + let fileNames = $.map(files, function(val) { + return val.name; + }); + $('#filesInputLabel').html(fileNames.length + ' files selected'); + if (fileNames.length>0) { + $('#filesDetails').show(500); + } else { + $('#filesDetails').css('display', 'none'); + $('#table').css('display', 'none'); + } + $('#start').css('display', 'none'); + $('#finish').css('display', 'none'); + $('#check').css('display', 'none'); + $('#post').css('display', 'none'); + $('#complete').css('display', 'none'); $('#table').css('display', 'none'); - } - $('#start').css('display', 'none'); - $('#finish').css('display', 'none'); - $('#check').css('display', 'none'); - $('#post').css('display', 'none'); - $('#complete').css('display', 'none'); - $('#table').css('display', 'none'); -}); + }); -$('#fileNameSwitch').change(function() { - if ($(this).is(':checked')) { - $('.fileName').css('opacity', '1'); - $('#fileNamesInput').prop('disabled', false); - $('#fileNamesInput').prop('required', true); - $('#fswitch').prop('title', 'Toggle to keep original file names'); - } else { - $('#fileNamesInput').prop('disabled', true); - $('#fswitch').prop('title', 'Toggle to select a generalised file name'); - $('#fileNamesInput').prop('required', false); - $('.fileName').css('opacity', '0.4'); - } + $('#fileNameSwitch').change(function() { + if ($(this).is(':checked')) { + $('.fileName').css('opacity', '1'); + $('#fileNamesInput').prop('disabled', false); + $('#fileNamesInput').prop('required', true); + $('#fswitch').prop('title', 'Toggle to keep original file names'); + } else { + $('#fileNamesInput').prop('disabled', true); + $('#fswitch').prop('title', 'Toggle to select a generalised file name'); + $('#fileNamesInput').prop('required', false); + $('.fileName').css('opacity', '0.4'); + } + }); + + $('.modal').on('shown.bs.modal', function() { + let input = $(this).find('input:text:visible:first'); + input.focus(); + }); + + $('#fileNamesInput').change(function() { + $(this).val($(this).val().split(' ').join('_')); + }); }); function addbody(rowData) { let table = $('table tbody'); - let markup = ''+rowData.serial+''+rowData.fileName+ - ''+rowData.slideName+''+rowData.token+ + let markup = ''+rowData.serial+''+rowData.fileName+ + '   '+rowData.slideName+ + '   '+ + ''+rowData.token+ ''+ - ' '; + ' '+ + ''+ + ''; + table.append(markup); } -let files= null; -let fileNames = null; -let slideNames = []; function startTable() { slideNames = []; fileNames = []; + originalFileNames = []; + tokens = []; let genSlideName = $('#slideNamesInput').val(); let genFileName=$('#fileNamesInput').val(); $('table tbody').html(''); if (genSlideName!='') { files = $('#filesInput').prop('files'); let slidesNum = files.length; + originalFileNames = $.map(files, function(val) { + return val.name; + }); if ($('#fileNameSwitch').is(':checked') && genFileName!='') { for (i=0; i   `; + if ($('.fileNameEdit:eq('+i+')').prev().prev('#fileNameError').length == 0) { + $('.fileNameEdit:eq('+i+')').parent().prepend(errorIcon); + } + numErrors++; + } else if (!allowedExtensions.includes(fileNames[i].substring(fileNames[i].lastIndexOf('.')+1, + fileNames[i].length))) { + let errorIcon = `   `; + if ($('.fileNameEdit:eq('+i+')').prev().prev('#fileNameError').length == 0) { + $('.fileNameEdit:eq('+i+')').parent().prepend(errorIcon); + } + numErrors++; + } else { + $('.fileNameEdit:eq('+i+')').parent().find('#fileNameError').remove(); + } + if (existingSlides.includes(slideNames[i])) { + let errorIcon = `   `; + if ($('.slideNameEdit:eq('+i+')').prev().prev('#slideNameError').length == 0) { + $('.slideNameEdit:eq('+i+')').parent().prepend(errorIcon); + } + numErrors++; + } else { + $('.slideNameEdit:eq('+i+')').parent().find('#slideNameError').remove(); + } + } + if (numErrors > 0) { + $('#start').hide(); + } else { + $('#start').show(300); + } +} + +function showSlideInfo1(index) { + $('#slideInfoContent').html(`Original Filename: `+originalFileNames[index]+`
Filename: `+fileNames[index]+ + `
Slide name: `+slideNames[index]+`
Status: Pending Initial Upload`); +} +function showSlideInfo2(index) { + $('#slideInfoContent').html(`Original Filename: `+originalFileNames[index]+`
Filename: `+fileNames[index]+ + `
Slide name: `+slideNames[index]+`
Token: `+ + tokens[index]+`
Status: Initial Upload done | Token Generated | Final Upload Pending`); +} +function showSlideInfo3(index) { + $('#slideInfoContent').html(`Original Filename: `+originalFileNames[index]+`
Filename: `+fileNames[index]+ + `
Slide name: `+slideNames[index]+`
Token: `+ + tokens[index]+`
Status: Final Upload Done | Check Pending | Post Pending`); +} +function showSlideInfo4(index) { + $('#slideInfoContent').html(`Original Filename: `+originalFileNames[index]+`
Filename: `+fileNames[index]+ + `
Slide name: `+slideNames[index]+`
Token: `+ + tokens[index]+`
Status: Check successfull | Post Pending`); +} +function showSlideInfo5(index) { + $('#slideInfoContent').html(`Original Filename: `+originalFileNames[index]+`
Filename: `+fileNames[index]+ + `
Slide name: `+slideNames[index]+`
Token: `+ + tokens[index]+`
Status: Posted Successfully`); +} + +function updateSlideName(oldSlideName) { + $('#confirmUpdateSlideContent').html('Enter the new name for:
'+oldSlideName+ + '

'); + let input = document.getElementById('newSlideName'); + input.select(); + $('#confirmUpdateSlide').unbind('click'); + $('#confirmUpdateSlide').click(function() { + let newSlideName = $('#newSlideName'); + let newName = newSlideName.val(); + + if (newName!='') { + if (slideNames.includes(newName) || existingSlides.includes(newName)) { + newSlideName.addClass('is-invalid'); + if (newSlideName.parent().children().length === 1) { + newSlideName.parent().append(`
+ Slide with given name already exists.
`); + } + } else { + newSlideName.removeClass('is-invalid'); + let index = slideNames.indexOf(oldSlideName); + slideNames[index] = newName; + $('tr:eq('+(index+1)+') td:nth-child(3) span').html(newName); + $('#slideNameChangeModal').modal('hide'); + checkNames(); + } + } + }); +} + +function updateFileName(oldfileName) { + $('#confirmUpdateFileContent').html('Enter the new name for:
'+oldfileName+ + '

'); + let input = document.getElementById('newFileName'); + let value = input.value; + input.setSelectionRange(0, value.lastIndexOf('.')); + + $('#newFileName').change(function() { + $(this).val($(this).val().split(' ').join('_')); + }); + $('#confirmUpdateFile').unbind('click'); + $('#confirmUpdateFile').click(function() { + let newFileName = $('#newFileName'); + let newName = newFileName.val(); + let fileExtension = newName.toLowerCase().split('.').reverse()[0]; + + if (newName!='') { + if (fileNames.includes(newName) || existingFiles.includes(newName)) { + newFileName.addClass('is-invalid'); + if (newFileName.parent().children().length === 1) { + newFileName.parent().append(`
+ File with given name already exists
`); + } else { + $('#filename-feedback0').html(`File with given name already exists`); + } + } else if (!allowedExtensions.includes(fileExtension)) { + newFileName.addClass('is-invalid'); + if (newFileName.parent().children().length === 1) { + newFileName.parent().append(`
+ .${fileExtension} files are not compatible
`); + } else { + $('#filename-feedback0').html(`.${fileExtension} files are not compatible`); + } + } else { + newFileName.removeClass('is-invalid'); + let index = fileNames.indexOf(oldfileName); + fileNames[index] = newName; + $('tr:eq('+(index+1)+') td:nth-child(2) span').html(newName); + $('#fileNameChangeModal').modal('hide'); + checkNames(); + } + } + }); +} + function startBatch() { tokens = []; for (i=0; i'); + $('.slideInfo:eq('+i+')').unbind('click'); + $('.slideInfo:eq('+i+')').click(function() { + showSlideInfo2(i); + }); continueUpload(token); readFileChunks(selectedFile, token); @@ -154,7 +382,7 @@ function continueUpload(token) { } function finishUpload(token, filename, i) { -// var reset = true; +// let reset = true; const body = {filename: filename}; // changeStatus('UPLOAD', 'Finished Reading File, Posting'); @@ -170,12 +398,21 @@ function finishUpload(token, filename, i) { // $('#post_btn').hide(); } else { finishUploadSuccess=true; - $('#check').css('display', 'inline-block'); + $('#check').show(); $('#finish').css('display', 'none'); let status = $('.status:eq('+i+')'); $('i:nth-child(2)', status).after(''); $('i:nth-child(2)', status).remove(); + + $('table').find('tr').each(function() { + $('td:nth-child(2)', this).unbind('mouseenter mouseleave'); + }); + + $('.slideInfo:eq('+i+')').unbind('click'); + $('.slideInfo:eq('+i+')').click(function() { + showSlideInfo3(i); + }); } }); regReq.then((e)=> { @@ -192,8 +429,8 @@ function finishUpload(token, filename, i) { async function readFileChunks(file, token) { - var part = 0; - var complete = false; + let part = 0; + let complete = false; while (!complete) { try { const data = await promiseChunkFileReader(file, part); @@ -211,7 +448,7 @@ async function readFileChunks(file, token) { // read a chunk of the file function promiseChunkFileReader(file, part) { return new Promise((resolve, reject)=>{ - var fr = new FileReader(); + let fr = new FileReader(); fr.onload = (evt)=>{ if (evt.target.error == null) { const d = evt.target.result.split(',')[1]; @@ -224,7 +461,7 @@ function promiseChunkFileReader(file, part) { reject(evt.target.error); } }; - var blob = file.slice(part*chunkSize, (part+1)*chunkSize); + let blob = file.slice(part*chunkSize, (part+1)*chunkSize); fr.readAsDataURL(blob); }); } @@ -240,10 +477,14 @@ function handleCheck(filename, i) { (response) => response.json(), // if the response is a JSON object ).then( (success) => { - $('#post').css('display', 'inline-block'); + $('#post').show(300); let status = $('.status:eq('+i+')'); $('i:nth-child(3)', status).remove(); $(status).append(''); + $('.slideInfo:eq('+i+')').unbind('click'); + $('.slideInfo:eq('+i+')').click(function() { + showSlideInfo4(i); + }); // Add the filename, to be able to fetch the thumbnail. success['preview'] = filename; }, // Handle the success response object @@ -271,12 +512,12 @@ function handlePost(filename, slidename, i) { data.mpp = parseFloat(data['mpp-x']) || parseFloat(data['mpp-y']) || 0; data.mpp_x = parseFloat(data['mpp-x']); data.mpp_y = parseFloat(data['mpp-y']); - var store = new Store('../../data/'); + let store = new Store('../../data/'); store.post('Slide', data).then( (success) => { $('#post').css('display', 'none'); $('#check').css('display', 'none'); - $('#complete').css('display', 'block'); + $('#complete').show(400); $('form').trigger('reset'); $('#fileNameSwitch').trigger('change'); $('#filesInputLabel').html('Choose Files'); @@ -284,6 +525,15 @@ function handlePost(filename, slidename, i) { let status = $('.status:eq('+i+')'); $(status).append(' '); console.log(success); + + $('table').find('tr').each(function() { + $('td:nth-child(3)', this).unbind('mouseenter mouseleave'); + }); + $('.slideInfo:eq('+i+')').unbind('click'); + $('.slideInfo:eq('+i+')').click(function() { + showSlideInfo5(i); + }); + $('.slideDelete').css('display', 'none'); // initialize(); // $('#upload-dialog').modal('hide'); // showSuccessPopup('Slide uploaded successfully'); @@ -297,3 +547,18 @@ function handlePost(filename, slidename, i) { (error) => console.log(error), // Handle the error response object ); } + +function sanitize(string) { + const map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + // eslint-disable-next-line quotes + "'": ''', + // eslint-disable-next-line quotes + "/": '/', + }; + const reg = /[&<>"'/]/ig; + return string.replace(reg, (match)=>(map[match])); +} diff --git a/apps/batchloader/batchloader.html b/apps/batchloader/batchloader.html index 795cfd58c..d6d7d4660 100644 --- a/apps/batchloader/batchloader.html +++ b/apps/batchloader/batchloader.html @@ -17,11 +17,7 @@ - + diff --git a/apps/table.html b/apps/table.html index 1113f7206..c95733bd7 100644 --- a/apps/table.html +++ b/apps/table.html @@ -199,9 +199,9 @@

caMicroscope

-
- +
+ @@ -505,14 +505,14 @@