diff --git a/.eslintignore b/.eslintignore index 964c7135b..79ea1a305 100644 --- a/.eslintignore +++ b/.eslintignore @@ -12,3 +12,4 @@ apps/landing/jquery.min.js apps/landing/jquery.scrollex.min.js apps/segment/opencv.js common/bootstrap-tour-standalone/bootstrap-tour-standalone.min.js +apps/viewer/turf.min.js \ No newline at end of file diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f96f03cf9..f6b206019 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -12,16 +12,15 @@ jobs: strategy: matrix: - node-version: [14.x, 16.x, 18.x] + node-version: [16.x, 18.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - run: npm ci - run: npm install - run: npm install jsdom - run: npm install -g http-server diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 276e8de32..000000000 --- a/.travis.yml +++ /dev/null @@ -1,38 +0,0 @@ -os: linux -dist: xenial -language: node_js -node_js: - - "12" -install: - - npm install - - npm install jsdom - - npm install -g http-server - - npm install -g mocha - - npm install eslint - - npm install eslint-config-google - -stages: - - name: lintjs - - name: tests - -before_script: - - http-server -s & # start a Web server - -jobs: - include: - - stage: lintjs - name: "JS Code Style Check" - script: - - ./node_modules/.bin/eslint core/*.js --quiet - - ./node_modules/.bin/eslint components/**/*.js --quiet - - ./node_modules/.bin/eslint apps/heatmap/*.js --quiet - - ./node_modules/.bin/eslint apps/labeling/*.js --quiet - - ./node_modules/.bin/eslint apps/loader/*.js --quiet - - ./node_modules/.bin/eslint apps/model/*.js --quiet - - ./node_modules/.bin/eslint apps/segment/*.js --quiet - - ./node_modules/.bin/eslint apps/model/**/*.js --quiet - - ./node_modules/.bin/eslint apps/segment/**/*.js --quiet - - ./node_modules/.bin/eslint apps/viewer/*.js --quiet - - stage: tests - name: Unit Tests - script: mocha test --recursive --exit diff --git a/Caracal b/Caracal deleted file mode 160000 index 945e448e8..000000000 --- a/Caracal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 945e448e8e03ac72c26a7b4eee2b6f2b41f7d725 diff --git a/Distro b/Distro deleted file mode 160000 index 4f107ac10..000000000 --- a/Distro +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4f107ac106b8ebd0422de32b6e9d69d00d0f517d diff --git a/HISTORY.md b/HISTORY.md index 3bba70c98..ba2ca3302 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,29 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## Index -* **Version 3** - * [3.10.x](#camicroscope-3100) - * [3.9.x](#camicroscope-390) - * [3.8.x](#camicroscope-380) - * [3.7.x](#camicroscope-377) - * [3.7.x](#camicroscope-375) - * [3.6.x](#camicroscope-362) - * [3.5.x](#camicroscope-3510) - * [3.4.x](#camicroscope-343) - * [3.3.x](#camicroscope-334) - * [3.2.x](#camicroscope-322) - * [3.1.x](#camicroscope-311) - * [3.0.x](#camicroscope-300) -* **Version 2** - * [2.0.x](#camicroscope-201) -* **Version 1** - * [1.0.x](#camicroscope-10) - -### caMicroscope [Unreleased](https://github.com/camicroscope/camicroscope/compare/v3.10.2...camicroscope:develop) +### caMicroscope [Unreleased](https://github.com/camicroscope/camicroscope/compare/v3.11.0...camicroscope:develop) ###### TBD +### caMicroscope [3.11.0](https://github.com/camicroscope/camicroscope/compare/v3.10.2...camicroscope:v3.11.0) +###### 2023-11-17 +* Dicom and Bioformats Intergration (#647, #653, #655) +* Improved Machine Learning Toolkit (#658) + ### caMicroscope [3.10.2](https://github.com/camicroscope/camicroscope/compare/v3.10.1...camicroscope:v3.10.2) ###### 2023-06-16 * point to point diff --git a/LICENSE b/LICENSE index 93513746c..59f5f49a3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2012-2021, caMicroscope +Copyright (c) 2012-2023, caMicroscope All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/apps/batchloader/batchLoader.js b/apps/batchloader/batchLoader.js index 2e15cb803..64ac34dd9 100644 --- a/apps/batchloader/batchLoader.js +++ b/apps/batchloader/batchLoader.js @@ -11,7 +11,7 @@ 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']; +const allowedExtensions = ["svs", "tif", "tiff", "vms", "vmu", "ndpi", "scn", "mrxs", "bif", "svslide", "jpg", "png", "dcm", "v3draw", "ano", "cfg", "csv", "htm", "rec", "tim", "zpo", "dic", "dicom", "jp2", "j2ki", "j2kr", "raw", "ima", "cr2", "crw", "thm", "wav", "dv", "r3d", "r3d_d3d", "log", "mvd2", "aisf", "aiix", "dat", "atsf", "tf2", "tf8", "btf", "pbm", "pgm", "ppm", "xdce", "xml", "xlog", "apl", "tnb", "mtb", "im", "mea", "res", "aim", "arf", "psd", "al3d", "gel", "am", "amiramesh", "grey", "hx", "labels", "img", "hdr", "sif", "afi", "exp", "h5", "1sc", "pic", "ims", "ch5", "vsi", "ets", "pnl", "htd", "c01", "dib", "cxd", "v", "eps", "epsi", "ps", "flex", "xlef", "fits", "fts", "dm2", "dm3", "dm4", "naf", "his", "ndpis", "txt", "i2i", "hed", "mod", "inr", "ipl", "ipm", "fff", "ics", "ids", "seq", "ips", "ipw", "frm", "par", "j2k", "jpf", "jpk", "jpx", "klb", "xv", "bip", "sxm", "fli", "lim", "msr", "lif", "lof", "lei", "l2d", "mnc", "stk", "nd", "scan", "vff", "mrw", "stp", "mng", "nii", "nrrd", "nhdr", "nd2", "nef", "obf", "omp2info", "oib", "oif", "pty", "lut", "oir", "sld", "spl", "liff", "top", "pcoraw", "pcx", "pict", "pct", "df3", "im3", "qptiff", "bin", "env", "spe", "afm", "sm2", "sm3", "spc", "set", "sdt", "spi", "xqd", "xqf", "db", "vws", "pst", "inf", "tfr", "ffr", "zfr", "zfp", "2fl", "tga", "pr3", "dti", "fdf", "hdf", "xys", "html", "acff", "wat", "bmp", "wpi", "czi", "lms", "lsm", "mdb", "zvi", "mrc", "st", "ali", "map", "mrcs", "jpeg", "gif", "ptif"]; // call on document ready $(document).ready(function() { @@ -21,8 +21,12 @@ $(document).ready(function() { store.findSlide().then((response) => { for (i=0; i { console.log(error); @@ -198,7 +202,7 @@ function checkNames() { } numErrors++; } else if (!allowedExtensions.includes(fileNames[i].substring(fileNames[i].lastIndexOf('.')+1, - fileNames[i].length))) { + fileNames[i].length).toLowerCase())) { let errorIcon = `   `; if ($('.fileNameEdit:eq('+i+')').prev().prev('#fileNameError').length == 0) { $('.fileNameEdit:eq('+i+')').parent().prepend(errorIcon); @@ -346,8 +350,11 @@ function finishBatch() { } async function handleUpload(selectedFile, filename, i) { - const token = await startUpload(filename); + const uploadMetadata = await startUpload(filename); + const token = uploadMetadata.upload_token; tokens.push(token); + fileNames[i] = uploadMetadata.filename; + $('tr:eq('+(i+1)+') td:nth-child(2) span')[0].innerText = uploadMetadata.filename; let j = 0; $('.token').each(function() { $(this).html(tokens[j++]); @@ -371,7 +378,7 @@ async function startUpload(filename) { }}).then((x)=>x.json()); try { const a = await token; - return a['upload_token']; + return { upload_token: a['upload_token'], filename: a['filename'] }; } catch (e) { console.log(e); } @@ -395,6 +402,14 @@ function finishUpload(token, filename, i) { }}); regReq.then((x)=>x.json()).then((a)=>{ // changeStatus('UPLOAD | Finished', a, reset); reset = false; + if (a.filepath) { + const newName = a.filepath.slice(a.filepath.lastIndexOf('/')+1); + fileNames[i] = newName; + $('tr:eq('+(i+1)+') td:nth-child(2) span')[0].innerText = newName; + } + if (a.relpath) { + fileNames[i] = a.relpath; + } if (typeof a === 'object' && a.error) { finishUploadSuccess = false; // $('#check_btn').hide(); diff --git a/apps/batchloader/batchloader.html b/apps/batchloader/batchloader.html index d6d7d4660..bd329b73d 100644 --- a/apps/batchloader/batchloader.html +++ b/apps/batchloader/batchloader.html @@ -70,7 +70,7 @@ type="file" class="custom-file-input" id="filesInput" - accept=".svs, .tif, .tiff, .vms, .vmu, .ndpi, .scn, .mrxs, .bif, .svslide" + accept=".svs, .tif, .tiff, .vms, .vmu, .ndpi, .scn, .mrxs, .bif, .svslide, .jpg, .png, .dcm, .v3draw, .ano, .cfg, .csv, .htm, .rec, .tim, .zpo, .dic, .dicom, .jp2, .j2ki, .j2kr, .raw, .ima, .cr2, .crw, .thm, .wav, .dv, .r3d, .r3d_d3d, .log, .mvd2, .aisf, .aiix, .dat, .atsf, .tf2, .tf8, .btf, .pbm, .pgm, .ppm, .xdce, .xml, .xlog, .apl, .tnb, .mtb, .im, .mea, .res, .aim, .arf, .psd, .al3d, .gel, .am, .amiramesh, .grey, .hx, .labels, .img, .hdr, .sif, .afi, .exp, .h5, .1sc, .pic, .ims, .ch5, .vsi, .ets, .pnl, .htd, .c01, .dib, .cxd, .v, .eps, .epsi, .ps, .flex, .xlef, .fits, .fts, .dm2, .dm3, .dm4, .naf, .his, .ndpis, .txt, .i2i, .hed, .mod, .inr, .ipl, .ipm, .fff, .ics, .ids, .seq, .ips, .ipw, .frm, .par, .j2k, .jpf, .jpk, .jpx, .klb, .xv, .bip, .sxm, .fli, .lim, .msr, .lif, .lof, .lei, .l2d, .mnc, .stk, .nd, .scan, .vff, .mrw, .stp, .mng, .nii, .nrrd, .nhdr, .nd2, .nef, .obf, .omp2info, .oib, .oif, .pty, .lut, .oir, .sld, .spl, .liff, .top, .pcoraw, .pcx, .pict, .pct, .df3, .im3, .qptiff, .bin, .env, .spe, .afm, .sm2, .sm3, .spc, .set, .sdt, .spi, .xqd, .xqf, .db, .vws, .pst, .inf, .tfr, .ffr, .zfr, .zfp, .2fl, .tga, .pr3, .dti, .fdf, .hdf, .xys, .html, .acff, .wat, .bmp, .wpi, .czi, .lms, .lsm, .mdb, .zvi, .mrc, .st, .ali, .map, .mrcs, .jpeg, .gif, .ptif" multiple required /> diff --git a/apps/loader/chunked_upload.js b/apps/loader/chunked_upload.js index 8c9c16ccf..64268e91c 100644 --- a/apps/loader/chunked_upload.js +++ b/apps/loader/chunked_upload.js @@ -59,12 +59,13 @@ async function readFileChunks(file, token) { async function handleUpload(selectedFiles) { selectedFile = selectedFiles[0]; const filename = selectedFiles[0]['name']; - const token = await startUpload(filename); + const uploadMetadata = await startUpload(filename); + const token = uploadMetadata.upload_token; $('#tokenRow').show(300); const callback = continueUpload(token); readFileChunks(selectedFile, token); // parseFile(selectedFile, callback, 0, x=>(changeStatus("UPLOAD", "Finished Reading File"))) - updateFormOnUpload(selectedFiles[0]['name'], token); + updateFormOnUpload(uploadMetadata.filename, token); document.getElementById('fileUploadInput').colSpan = selectedFiles.length; document.getElementById('controlButtons').colSpan = selectedFiles.length+1; @@ -78,7 +79,7 @@ async function startUpload(filename) { try { const a = await token; changeStatus('UPLOAD', 'Begun upload - Token:' + a['upload_token']); - return a['upload_token']; + return {upload_token: a['upload_token'], filename: a['filename']}; ; } catch (e) { changeStatus('UPLOAD | ERROR;', e); } @@ -130,6 +131,13 @@ function finishUpload() { regReq.then((x)=>x.json()).then((a)=>{ changeStatus('UPLOAD | Finished', a, reset); reset = false; console.log(a); + if (a.relpath) { + document.getElementById('filename'+0).value = a.relpath; + } else if (a.filename) { + document.getElementById('filename'+0).value = a.filename; + } else if (a.filepath) { + document.getElementById('filename'+0).value = a.filepath.slice(a.filepath.lastIndexOf('/')+1); + } if (typeof a === 'object' && a.error) { finishUploadSuccess = false; $('#check_btn').hide(); @@ -143,6 +151,7 @@ function finishUpload() { $('#check_btn').show(); $('#post_btn').hide(); } + validateForm(CheckBtn); } }); regReq.then((e)=> { @@ -153,8 +162,6 @@ function finishUpload() { changeStatus('UPLOAD | ERROR;', e); reset = true; console.log(e); - } else { - validateForm(CheckBtn); } }, ); @@ -163,7 +170,7 @@ function finishUpload() { async function handleUrlUpload(url) { $('#uploadLoading').css('display', 'block'); - const token = await startUpload(url); + const token = (await startUpload(url)).upload_token; await continueUrlUpload(token, url); } diff --git a/apps/loader/loader.js b/apps/loader/loader.js index 39ca66153..f41fb9bc0 100644 --- a/apps/loader/loader.js +++ b/apps/loader/loader.js @@ -59,7 +59,20 @@ function changeStatus(step, text, reset=true) { } } if (step == 'CHECK') { - // During check, thumbnail needs to be fetched & added to the table + // show post button + if (text['location']) { + // indicating successful check + checkSuccess = true; + if (finishUploadSuccess === true) { + $('#post_btn').show(); + } else { + $('#post_btn').hide(); + } + } else { + checkSuccess = false; + $('#post_btn').hide(); + } + // fetch thumbnail and add to table as we can // In this case, text[col[col.length - 1]] is the filename fetch(thumbUrl + text[col[col.length - 1]], {credentials: 'same-origin'}).then( (response) => response.json(), // if the response is a JSON object @@ -69,18 +82,6 @@ function changeStatus(step, text, reset=true) { const img = new Image(); img.src = x.slide; tabCell.appendChild(img); - if (text['location']) { - // indicating successful check - checkSuccess = true; - if (finishUploadSuccess === true) { - $('#post_btn').show(); - } else { - $('#post_btn').hide(); - } - } else { - checkSuccess = false; - $('#post_btn').hide(); - } }); } } @@ -121,12 +122,15 @@ function handleDownload(id) { store.getSlide(id) .then((response) => { if (response[0]) { - return response[0]['location']; + if (response[0]['filepath']) { + return response[0]['filepath']; + } + let location = response[0]['location']; + return location.substring(location.lastIndexOf('/')+1, location.length); } else { throw new Error('Slide not found'); } - }).then((location) => { - fileName = location.substring(location.lastIndexOf('/')+1, location.length); + }).then((fileName) => { console.log(fileName); return fileName; }).then((fileName) =>{ diff --git a/apps/model/model.js b/apps/model/model.js index 02315e996..58584a0b2 100644 --- a/apps/model/model.js +++ b/apps/model/model.js @@ -408,15 +408,17 @@ function initCore() { $CAMIC.store.getSlide($D.params.slideId).then((response) => { if (response[0]) { - return response[0]['location']; + if (response[0]['filepath']) { + return response[0]['filepath']; + } + return location.substring( + location.lastIndexOf('/') + 1, + location.length, + ); } else { throw new Error('Slide not found'); } - }).then((location) => { - fileName = location.substring( - location.lastIndexOf('/') + 1, - location.length, - ); + }).then((fileName) => { console.log(fileName); }); diff --git a/apps/redir.js b/apps/redir.js index 968dd7656..68a9cc611 100644 --- a/apps/redir.js +++ b/apps/redir.js @@ -1,31 +1,33 @@ -let params = getUrlVars(); -let isPathdb = false; +document.addEventListener('DOMContentLoaded', async function() { + let params = getUrlVars(); + let isPathdb = false; -if (params.hasOwnProperty('mode') && params.mode == 'pathdb') { - PathDbMods(); - isPathdb = true; -} + if (params.hasOwnProperty('mode') && params.mode == 'pathdb') { + await PathDbMods(); + isPathdb = true; + } -const store = new Store('../data/'); + const store = new Store('../data/'); -if (params.hasOwnProperty('slide')) { - store.findSlide(params.slide, params.specimen, params.study, 0, 0, params.collection).then((x)=>{ - console.info(x); - if (x.length <=0) { - throw new Error('No Matches found'); - } - if (isPathdb) { - // get the pathdb url - window.location = './viewer/viewer.html?slideId=' + x[0]['_id']['$oid'] + '&mode=pathdb'; - } else { - // get the normal url - window.location = './viewer/viewer.html?slideId=' + x[0]['_id']['$oid']; - } - }).catch((e)=>{ - console.error(e); + if (params.hasOwnProperty('slide')) { + store.findSlide(params.slide, params.specimen, params.study, 0, 0, params.collection).then((x)=>{ + console.info(x); + if (x.length <=0) { + throw new Error('No Matches found'); + } + if (isPathdb) { + // get the pathdb url + window.location = './viewer/viewer.html?slideId=' + x[0]['_id']['$oid'] + '&mode=pathdb'; + } else { + // get the normal url + window.location = './viewer/viewer.html?slideId=' + x[0]['_id']['$oid']; + } + }).catch((e)=>{ + console.error(e); + alert('ERROR!'); + }); + } else { + console.error('no slide passed?'); alert('ERROR!'); - }); -} else { - console.error('no slide passed?'); - alert('ERROR!'); -} + } +}); diff --git a/apps/table.html b/apps/table.html index 38b8b71ee..0ad2b8cb1 100644 --- a/apps/table.html +++ b/apps/table.html @@ -133,7 +133,13 @@

caMicroscope

-
+
+
+ +
+