From 067287b167c4710a8aa8c746024f61c30102f7c0 Mon Sep 17 00:00:00 2001 From: "lee.hsua" Date: Mon, 24 Jun 2024 18:57:52 -0400 Subject: [PATCH 1/9] Uploading Indicator 1st commit --- client/src/components/Dragger.js | 89 +++++++++++---------- client/src/contexts/GlobalContext.js | 3 + client/src/views/DataLoader.js | 114 ++++++++++++++------------- 3 files changed, 110 insertions(+), 96 deletions(-) diff --git a/client/src/components/Dragger.js b/client/src/components/Dragger.js index cb2483c..495a2c8 100644 --- a/client/src/components/Dragger.js +++ b/client/src/components/Dragger.js @@ -10,6 +10,7 @@ const path = require('path'); function Dragger() { const context = useContext(AppContext); const { Dragger } = Upload; + const [uploading, setUploading] = useState(false); //LI const getBase64 = (file) => new Promise((resolve, reject) => { @@ -28,6 +29,7 @@ function Dragger() { console.log(pathSegments) let pytcClientIndex = pathSegments.indexOf('pytc-client'); let relativePath = pathSegments.slice(pytcClientIndex).join(path.sep); + //setUploading(false); //LI // Check if 'pytc-client' was found in the path if (pytcClientIndex === -1) { // Handle the error: 'pytc-client' not found @@ -38,10 +40,10 @@ function Dragger() { message.success(`${info.file.name} file uploaded successfully.`); if (window.require) { - const modifiedFile = { ...info.file, path: relativePath }; - context.setFiles([...context.files, modifiedFile]); + const modifiedFile = { ...info.file, path: relativePath }; + context.setFiles([...context.files, modifiedFile]); } else { - context.setFiles([...info.fileList]); + context.setFiles([...info.fileList]); } console.log('done'); } else if (status === 'error') { @@ -50,7 +52,9 @@ function Dragger() { } else if (status === 'removed') { console.log(info.fileList); context.setFiles([...info.fileList]); - } + } /*else if (status === 'uploading') { + setUploading(true); //LI + }*/ }; const uploadImage = async (options) => { @@ -62,7 +66,7 @@ function Dragger() { } }; - + const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(""); const [previewTitle, setPreviewTitle] = useState(""); @@ -75,7 +79,7 @@ function Dragger() { setValue(event.target.value); }; - const handleDropdownChange = (event) => { + const handleDropdownChange = (event) => { setFileType(event.target.value); }; @@ -93,27 +97,27 @@ function Dragger() { const handleSubmit = (type) => { console.log("submitting path", previewFileFolderPath); - + const fileInContext = context.files.find((targetFile) => targetFile.uid === fileUID); const fileInFileList = context.fileList.find((targetFile) => targetFile.value === fileUID); - + if (previewFileFolderPath !== "" && fileInContext) { fileInContext.folderPath = previewFileFolderPath; setPreviewFileFolderPath(""); } - + if (value !== "" && fileInContext && fileInFileList) { fileInContext.name = value; fileInFileList.label = value; setValue(""); } - + if (fileInContext) { fetchFile(fileInContext); } else { message.error("Error: File selection error. Please try again."); } - + setPreviewOpen(false); }; @@ -137,34 +141,35 @@ function Dragger() { const handleCancel = () => setPreviewOpen(false); const handlePreview = async (file) => { + context.setLoading(true); //LI setFileUID(file.uid); if (!file.url && !file.preview) { - if (file.type !== 'image/tiff' || file.type !== 'image/tif') { - if (file.path) { // Use the local path for Electron environment - const fs = window.require('fs'); - const buffer = fs.readFileSync(file.path); - const base64 = buffer.toString('base64'); - file.preview = `data:${file.type};base64,${base64}`; - } else { - file.preview = await getBase64(file.originFileObj); - } + if (file.type !== 'image/tiff' || file.type !== 'image/tif') { + if (file.path) { // Use the local path for Electron environment + const fs = window.require('fs'); + const buffer = fs.readFileSync(file.path); + const base64 = buffer.toString('base64'); + file.preview = `data:${file.type};base64,${base64}`; } else { - file.preview = file.thumbUrl; + file.preview = await getBase64(file.originFileObj); } + } else { + file.preview = file.thumbUrl; + } } setPreviewImage(file.url || file.preview); setPreviewOpen(true); setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf(path.sep) + 1)); if ( - context.files.find(targetFile => targetFile.uid === file.uid) && - context.files.find(targetFile => targetFile.uid === file.uid).folderPath) - { - processAndSetPath( - context.files.find(targetFile => targetFile.uid === file.uid) - .folderPath) + context.files.find(targetFile => targetFile.uid === file.uid) && + context.files.find(targetFile => targetFile.uid === file.uid).folderPath) { + processAndSetPath( + context.files.find(targetFile => targetFile.uid === file.uid) + .folderPath) } else { processAndSetPath(path.dirname(file.originFileObj.path)); } + context.setLoading(false); //LI }; function processAndSetPath(info) { @@ -175,10 +180,10 @@ function Dragger() { // Check if 'pytc-client' was found in the path if (pytcClientIndex === -1) { - // Handle the error: 'sample' not found - console.error("Error: Please upload from the sample folder. File path: " + path); - message.error(`${info.name} file upload failed.`); - return false; + // Handle the error: 'sample' not found + console.error("Error: Please upload from the sample folder. File path: " + path); + message.error(`${info.name} file upload failed.`); + return false; } let relativePath = pathSegments.slice(pytcClientIndex).join(path.sep); @@ -233,16 +238,16 @@ function Dragger() { onCancel={handleCancel} > - - - - - - + + + + + + { const [inputLabel, setInputLabel] = usePersistedState('inputLabel', null); const [viewer, setViewer] = usePersistedState('viewer', null); const [tensorBoardURL, setTensorBoardURL] = usePersistedState('tensorBoardURL', null); + const [loading, setLoading] = useState(false); //LI return ( { setCheckpointPath, tensorBoardURL, setTensorBoardURL, + loading, + setLoading, }} > {props.children} diff --git a/client/src/views/DataLoader.js b/client/src/views/DataLoader.js index 5a3bc5f..cbfdeac 100644 --- a/client/src/views/DataLoader.js +++ b/client/src/views/DataLoader.js @@ -3,6 +3,7 @@ import Dragger from "../components/Dragger"; import { Button, Input, Select, Space, Typography } from "antd"; import { ArrowRightOutlined } from "@ant-design/icons"; import { AppContext } from "../contexts/GlobalContext"; +import LoadingIndicator from "../components/LoadingIndicator"; //LI import "./DataLoader.css"; const { Title } = Typography; @@ -16,13 +17,15 @@ function DataLoader(props) { const handleVisualizeButtonClick = async (event) => { event.preventDefault(); + context.setLoading(true); //LI //true context.setCurrentImage(currentImage); context.setCurrentLabel(currentLabel); - fetchNeuroglancerViewer( + await fetchNeuroglancerViewer( //LI await currentImage, currentLabel, scales.split(",").map(Number) ); + context.setLoading(false); //LI //false }; const handleImageChange = (value) => { console.log(`selected ${value}`); @@ -49,61 +52,64 @@ function DataLoader(props) { }, [context.files]); return ( - - - - Image - - ({ + label: file.name, + value: file.uid, + }))} + style={{ width: "185px" }} + placeholder="Select image" + size="middle" + allowClear={true} + /> - - Label - - ({ + label: file.name, + value: file.uid, + }))} + style={{ width: "185px" }} + placeholder="Select label" + size="middle" + allowClear={true} + /> - - Scales - - - - + + Scales + + + + + //LI div ); } From b1cd8be11ca45884693fe3397ac708ccd58338e3 Mon Sep 17 00:00:00 2001 From: "lee.hsua" Date: Mon, 24 Jun 2024 18:58:47 -0400 Subject: [PATCH 2/9] Uploading Indicator 1st commit Add New Files --- client/src/components/LoadingIndicator.css | 20 ++++++++++++++++++++ client/src/components/LoadingIndicator.js | 13 +++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 client/src/components/LoadingIndicator.css create mode 100644 client/src/components/LoadingIndicator.js diff --git a/client/src/components/LoadingIndicator.css b/client/src/components/LoadingIndicator.css new file mode 100644 index 0000000..c0644fd --- /dev/null +++ b/client/src/components/LoadingIndicator.css @@ -0,0 +1,20 @@ +.loading-indicator { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + background-color: rgba(255, 255, 255, 0.7); + z-index: 1000; +} + +/*.loading-indicator { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 1000; +}*/ \ No newline at end of file diff --git a/client/src/components/LoadingIndicator.js b/client/src/components/LoadingIndicator.js new file mode 100644 index 0000000..1ea599d --- /dev/null +++ b/client/src/components/LoadingIndicator.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { Spin } from 'antd'; +import './LoadingIndicator.css'; + +const LoadingIndicator = () => { + return ( +
+ +
+ ); +}; + +export default LoadingIndicator; \ No newline at end of file From af23814581905300c4c37a40f7310d294c375eda Mon Sep 17 00:00:00 2001 From: mansouralawi Date: Sat, 6 Jul 2024 19:18:43 +0800 Subject: [PATCH 3/9] update dragger.js --- client/src/components/Dragger.js | 283 ++++++++++++++++++------------- 1 file changed, 167 insertions(+), 116 deletions(-) diff --git a/client/src/components/Dragger.js b/client/src/components/Dragger.js index 3edef17..82148b5 100644 --- a/client/src/components/Dragger.js +++ b/client/src/components/Dragger.js @@ -1,142 +1,187 @@ -import React, { useContext, useState } from "react"; -import { Button, Input, message, Modal, Space, Upload } from "antd"; -import { InboxOutlined } from "@ant-design/icons"; -import { AppContext } from "../contexts/GlobalContext"; -import { DEFAULT_IMAGE } from "../utils/utils"; +// global FileReader +import React, { useContext, useState } from 'react' +import { Button, Input, message, Modal, Space, Upload } from 'antd' +import { InboxOutlined } from '@ant-design/icons' +import { AppContext } from '../contexts/GlobalContext' +import { DEFAULT_IMAGE } from '../utils/utils' +import UTIF from 'utif'; -const path = require('path'); +const path = require('path') -function Dragger() { - const context = useContext(AppContext); - const { Dragger } = Upload; - const [uploading, setUploading] = useState(false); //LI +export function Dragger () { + const context = useContext(AppContext) + const [uploading, setUploading] = useState(false) const getBase64 = (file) => new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => resolve(reader.result); - reader.onerror = (error) => reject(error); - }); + const reader = new FileReader() + reader.readAsDataURL(file) + reader.onload = () => resolve(reader.result) + reader.onerror = (error) => reject(error) + }) const onChange = (info) => { - const { status } = info.file; + const { status } = info.file if (status === 'done') { - console.log('file found at:', info.file.originFileObj.path); + console.log('file found at:', info.file.originFileObj.path) - message.success(`${info.file.name} file uploaded successfully.`); + message.success(`${info.file.name} file uploaded successfully.`) if (window.require) { - const modifiedFile = { ...info.file, path: info.file.originFileObj.path }; - context.setFiles([...context.files, modifiedFile]); + const modifiedFile = { ...info.file, path: info.file.originFileObj.path } + context.setFiles([...context.files, modifiedFile]) } else { - context.setFiles([...info.fileList]); + context.setFiles([...info.fileList]) } - console.log('done'); + console.log('done') } else if (status === 'error') { - console.log('error'); - message.error(`${info.file.name} file upload failed.`); + console.log('error') + message.error(`${info.file.name} file upload failed.`) } else if (status === 'removed') { - console.log(info.fileList); - context.setFiles([...info.fileList]); + console.log(info.fileList) + context.setFiles([...info.fileList]) } - }; + } const uploadImage = async (options) => { - const { onSuccess, onError } = options; + const { onSuccess, onError } = options try { - onSuccess("Ok"); + onSuccess('Ok') } catch (err) { - onError({ err }); + onError({ err }) } - }; + } - - const [previewOpen, setPreviewOpen] = useState(false); - const [previewImage, setPreviewImage] = useState(""); - const [previewTitle, setPreviewTitle] = useState(""); - const [value, setValue] = useState(""); - const [fileUID, setFileUID] = useState(null); - const [previewFileFolderPath, setPreviewFileFolderPath] = useState(""); - const [fileType, setFileType] = useState("Image"); + const [previewOpen, setPreviewOpen] = useState(false) + const [previewImage, setPreviewImage] = useState('') + const [previewTitle, setPreviewTitle] = useState('') + const [value, setValue] = useState('') + const [fileUID, setFileUID] = useState(null) + const [previewFileFolderPath, setPreviewFileFolderPath] = useState('') + const [fileType, setFileType] = useState('Image') const handleText = (event) => { - setValue(event.target.value); - }; + setValue(event.target.value) + } const handleDropdownChange = (event) => { - setFileType(event.target.value); - }; + setFileType(event.target.value) + } const fetchFile = async (file) => { try { - if (fileType === "Label") { - context.setLabelFileList((prevLabelList) => [...prevLabelList, file]); - } else if (fileType === "Image") { - context.setImageFileList((prevImageList) => [...prevImageList, file]); + if (fileType === 'Label') { + context.setLabelFileList((prevLabelList) => [...prevLabelList, file]) + } else if (fileType === 'Image') { + context.setImageFileList((prevImageList) => [...prevImageList, file]) } } catch (error) { - console.error(error); + console.error(error) } - }; + } const handleSubmit = (type) => { - console.log("submitting path", previewFileFolderPath) - if (previewFileFolderPath !== "") { + console.log('submitting path', previewFileFolderPath) + if (previewFileFolderPath !== '') { context.files.find( (targetFile) => targetFile.uid === fileUID - ).folderPath = previewFileFolderPath; - setPreviewFileFolderPath(""); + ).folderPath = previewFileFolderPath + setPreviewFileFolderPath('') } - if (value !== "") { + if (value !== '') { context.files.find((targetFile) => targetFile.uid === fileUID).name = - value; + value context.fileList.find( (targetFile) => targetFile.value === fileUID - ).label = value; - setValue(""); + ).label = value + setValue('') } - fetchFile(context.files.find((targetFile) => targetFile.uid === fileUID)); - setPreviewOpen(false); - }; + fetchFile(context.files.find((targetFile) => targetFile.uid === fileUID)) + setPreviewOpen(false) + } const handleClearCache = async () => { - context.setFileList([]); - context.setImageFileList([]); - context.setLabelFileList([]); - message.success("File list cleared successfully."); - }; + context.setFileList([]) + context.setImageFileList([]) + context.setLabelFileList([]) + message.success('File list cleared successfully.') + } const handleRevert = () => { - let oldName = context.files.find((targetFile) => targetFile.uid === fileUID) - .originFileObj.name; + const oldName = context.files.find((targetFile) => targetFile.uid === fileUID) + .originFileObj.name context.files.find((targetFile) => targetFile.uid === fileUID).name = - oldName; + oldName context.fileList.find((targetFile) => targetFile.value === fileUID).label = - oldName; - setPreviewOpen(false); - }; + oldName + setPreviewOpen(false) + } + + const handleCancel = () => setPreviewOpen(false) + // Function to generate preview for TIFF files + const generateTiffPreview = (file, callback) => { + const reader = new FileReader(); + reader.onload = function(event) { + try { + const buffer = new Uint8Array(event.target.result); + console.log('Buffer length: ', buffer.length); //Log buffer length in bytes + + const tiffPages = UTIF.decode(buffer); + + //Check if tiffPages array is not empty + if (tiffPages.length === 0) throw new Error('No TIFF pages found'); + + const firstPage = tiffPages[0]; + console.log('First page before decoding:', firstPage); // Log first page object before decoding + + // Ensure the firstPage has necessary tags before decoding + if (!firstPage.t256 || !firstPage.t257) throw new Error('First page is missing essential tags (width and height)'); + + UTIF.decodeImage(buffer, firstPage); // firstPage before and after decoding, the result is same. + console.log('TIFF first page after decoding: ', firstPage); //Log the first page object + + // Extract width and height from the TIFF tags + const width = firstPage.t256 ? firstPage.t256[0] : 0; + const height = firstPage.t257 ? firstPage.t257[0] : 0; + + // Check if width and height are valid + if (width > 0 && height > 0) { + const rgba = UTIF.toRGBA8(firstPage); // Uint8Array with RGBA pixels + + // Create a canvas to draw the TIFF image + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + canvas.width = width; + canvas.height = height; + const imageData = ctx.createImageData(width, height); + + imageData.data.set(rgba); + ctx.putImageData(imageData, 0, 0); - const handleCancel = () => setPreviewOpen(false); + const dataURL = canvas.toDataURL(); + console.log('Canvas data URL:', dataURL); + callback(dataURL); + + } else { + console.error('TIFF image has invalid dimensions:', { width, height }); + message.error('TIFF image has invalid dimensions.'); + setPreviewImage(DEFAULT_IMAGE); // Fallback to default image + } + } catch (error) { + console.error('Failed to generate TIFF preview:', error); + message.error('Failed to generate TIFF preview.'); + setPreviewImage(DEFAULT_IMAGE); // Fallback to default image + } + }; + reader.readAsArrayBuffer(file); + }; + + //When click preview eye icon, implement handlePreview function const handlePreview = async (file) => { - context.setLoading(true); //LI + context.setLoading(true) setFileUID(file.uid); - if (!file.url && !file.preview) { - if (file.type !== "image/tiff" || file.type !== "image/tif") { - if (file.path) { // Use the local path for Electron environment - const fs = window.require('fs'); - const buffer = fs.readFileSync(file.path); - const base64 = buffer.toString('base64'); - file.preview = `data:${file.type};base64,${base64}`; - } else { - file.preview = await getBase64(file.originFileObj); - } - } else { - file.preview = file.thumbUrl; - } - } - setPreviewImage(file.url || file.preview); setPreviewOpen(true); + setPreviewImage(file.thumbUrl); setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)); if ( context.files.find(targetFile => targetFile.uid === file.uid) && @@ -144,49 +189,57 @@ function Dragger() { setPreviewFileFolderPath( context.files.find(targetFile => targetFile.uid === file.uid) .folderPath - ); + ) } else { // Directory name with trailing slash - setPreviewFileFolderPath(path.dirname(file.originFileObj.path) + "/"); + setPreviewFileFolderPath(path.dirname(file.originFileObj.path) + '/') } - }; + } const listItemStyle = { - width: "185px", - }; + width: '185px' + } + // when click or drag file to this area to upload, below function will be deployed. const handleBeforeUpload = (file) => { // Create a URL for the thumbnail using object URL - if (file.type !== "image/tiff" || file.type !== "image/tif") { - file.thumbUrl = URL.createObjectURL(file); + if (file.type === "image/tiff" || file.type === "image/tif") { + return new Promise((resolve) => { + generateTiffPreview(file, (dataURL) => { + file.thumbUrl = dataURL; + console.log('file thumbUrl inside callback is', file.thumbUrl); + resolve(file) + }); + console.log('file thumbUrl is', file.thumbUrl); + }) } else { - file.thumbUrl = DEFAULT_IMAGE; + file.thumbUrl = URL.createObjectURL(file); } - return true; // Allow the upload - }; + return true // Allow the upload + } return ( <> - (
{originNode}
)} > -

+

-

+

Click or drag file to this area to upload

-
- - + @@ -209,21 +262,19 @@ function Dragger() { example - ); + ) } - -export default Dragger; \ No newline at end of file From 120045adeffb9acf23983337d8b99cdde7e1ad0f Mon Sep 17 00:00:00 2001 From: mansouralawi Date: Sat, 6 Jul 2024 19:41:08 +0800 Subject: [PATCH 4/9] format fix linter --- client/src/views/DataLoader.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/views/DataLoader.js b/client/src/views/DataLoader.js index 5dc0832..5d6cfc4 100644 --- a/client/src/views/DataLoader.js +++ b/client/src/views/DataLoader.js @@ -24,9 +24,9 @@ function DataLoader (props) { currentImage, currentLabel, scales.split(',').map(Number) - ); + ) context.setLoading(false) - }; + } const handleImageChange = (value) => { console.log(`selected ${value}`) setCurrentImage(context.files.find((image) => image.uid === value)) From 320e102e3642d2923f952357f3f31a7640c45f55 Mon Sep 17 00:00:00 2001 From: mansouralawi Date: Sat, 6 Jul 2024 20:31:43 +0800 Subject: [PATCH 5/9] update npm for test fix --- .github/workflows/app-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/app-build.yml b/.github/workflows/app-build.yml index 574999d..e329180 100644 --- a/.github/workflows/app-build.yml +++ b/.github/workflows/app-build.yml @@ -28,6 +28,7 @@ jobs: - name: Install Dependencies run: | cd client + npm install -g npm@latest npm install - name: Install and start Xvfb From 35fd2646a0f0c7158c769926251b87087979cdbc Mon Sep 17 00:00:00 2001 From: mansouralawi Date: Sat, 6 Jul 2024 20:50:26 +0800 Subject: [PATCH 6/9] linter fixes --- client/src/components/Dragger.js | 100 ++++++++++----------- client/src/components/LoadingIndicator.css | 9 +- client/src/components/LoadingIndicator.js | 16 ++-- client/src/contexts/GlobalContext.js | 2 +- client/src/views/DataLoader.js | 2 +- 5 files changed, 64 insertions(+), 65 deletions(-) diff --git a/client/src/components/Dragger.js b/client/src/components/Dragger.js index 0cd4f6e..0b5742e 100644 --- a/client/src/components/Dragger.js +++ b/client/src/components/Dragger.js @@ -4,7 +4,7 @@ import { Button, Input, message, Modal, Space, Upload } from 'antd' import { InboxOutlined } from '@ant-design/icons' import { AppContext } from '../contexts/GlobalContext' import { DEFAULT_IMAGE } from '../utils/utils' -import UTIF from 'utif'; +import UTIF from 'utif' const path = require('path') @@ -118,70 +118,66 @@ export function Dragger () { const handleCancel = () => setPreviewOpen(false) // Function to generate preview for TIFF files const generateTiffPreview = (file, callback) => { - const reader = new FileReader(); - reader.onload = function(event) { + const reader = new FileReader() + reader.onload = function (event) { try { - const buffer = new Uint8Array(event.target.result); - console.log('Buffer length: ', buffer.length); //Log buffer length in bytes + const buffer = new Uint8Array(event.target.result) + console.log('Buffer length: ', buffer.length)// Log buffer length in bytes + const tiffPages = UTIF.decode(buffer) + // Check if tiffPages array is not empty + if (tiffPages.length === 0) throw new Error('No TIFF pages found') - const tiffPages = UTIF.decode(buffer); - - //Check if tiffPages array is not empty - if (tiffPages.length === 0) throw new Error('No TIFF pages found'); - - const firstPage = tiffPages[0]; - console.log('First page before decoding:', firstPage); // Log first page object before decoding + const firstPage = tiffPages[0] + console.log('First page before decoding:', firstPage) // Log first page object before decoding // Ensure the firstPage has necessary tags before decoding - if (!firstPage.t256 || !firstPage.t257) throw new Error('First page is missing essential tags (width and height)'); - - UTIF.decodeImage(buffer, firstPage); // firstPage before and after decoding, the result is same. - console.log('TIFF first page after decoding: ', firstPage); //Log the first page object + if (!firstPage.t256 || !firstPage.t257) throw new Error('First page is missing essential tags (width and height)') + UTIF.decodeImage(buffer, firstPage) // firstPage before and after decoding, the result is same. + console.log('TIFF first page after decoding: ', firstPage) // Log the first page object // Extract width and height from the TIFF tags - const width = firstPage.t256 ? firstPage.t256[0] : 0; - const height = firstPage.t257 ? firstPage.t257[0] : 0; + const width = firstPage.t256 ? firstPage.t256[0] : 0 + const height = firstPage.t257 ? firstPage.t257[0] : 0 // Check if width and height are valid if (width > 0 && height > 0) { - const rgba = UTIF.toRGBA8(firstPage); // Uint8Array with RGBA pixels + const rgba = UTIF.toRGBA8(firstPage) // Uint8Array with RGBA pixels // Create a canvas to draw the TIFF image - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); - canvas.width = width; - canvas.height = height; - const imageData = ctx.createImageData(width, height); - - imageData.data.set(rgba); - ctx.putImageData(imageData, 0, 0); + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d') + canvas.width = width + canvas.height = height + const imageData = ctx.createImageData(width, height) - const dataURL = canvas.toDataURL(); - console.log('Canvas data URL:', dataURL); + imageData.data.set(rgba) + ctx.putImageData(imageData, 0, 0) - callback(dataURL); + const dataURL = canvas.toDataURL() + console.log('Canvas data URL:', dataURL) + callback(dataURL) } else { - console.error('TIFF image has invalid dimensions:', { width, height }); - message.error('TIFF image has invalid dimensions.'); - setPreviewImage(DEFAULT_IMAGE); // Fallback to default image - } + console.error('TIFF image has invalid dimensions:', { width, height }) + message.error('TIFF image has invalid dimensions.') + setPreviewImage(DEFAULT_IMAGE) // Fallback to default image + } } catch (error) { - console.error('Failed to generate TIFF preview:', error); - message.error('Failed to generate TIFF preview.'); - setPreviewImage(DEFAULT_IMAGE); // Fallback to default image - } - }; - reader.readAsArrayBuffer(file); - }; + console.error('Failed to generate TIFF preview:', error) + message.error('Failed to generate TIFF preview.') + setPreviewImage(DEFAULT_IMAGE) // Fallback to default image + } + } + reader.readAsArrayBuffer(file) + } //When click preview eye icon, implement handlePreview function const handlePreview = async (file) => { context.setLoading(true) - setFileUID(file.uid); - setPreviewOpen(true); - setPreviewImage(file.thumbUrl); - setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)); + setFileUID(file.uid) + setPreviewOpen(true) + setPreviewImage(file.thumbUrl) + setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)) if ( context.files.find(targetFile => targetFile.uid === file.uid) && context.files.find(targetFile => targetFile.uid === file.uid).folderPath) { @@ -205,21 +201,21 @@ export function Dragger () { if (file.type === "image/tiff" || file.type === "image/tif") { return new Promise((resolve) => { generateTiffPreview(file, (dataURL) => { - file.thumbUrl = dataURL; - console.log('file thumbUrl inside callback is', file.thumbUrl); + file.thumbUrl = dataURL + console.log('file thumbUrl inside callback is', file.thumbUrl) resolve(file) - }); - console.log('file thumbUrl is', file.thumbUrl); + }) + console.log('file thumbUrl is', file.thumbUrl) }) } else { - file.thumbUrl = URL.createObjectURL(file); + file.thumbUrl = URL.createObjectURL(file) } return true // Allow the upload } return ( <> - ) -} \ No newline at end of file +} diff --git a/client/src/components/LoadingIndicator.css b/client/src/components/LoadingIndicator.css index c0644fd..3d9f6ee 100644 --- a/client/src/components/LoadingIndicator.css +++ b/client/src/components/LoadingIndicator.css @@ -7,14 +7,17 @@ position: absolute; top: 0; left: 0; - background-color: rgba(255, 255, 255, 0.7); + background-color: rgb(255 255 255 / 70%); z-index: 1000; } -/*.loading-indicator { + +/* +.loading-indicator { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1000; -}*/ \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/client/src/components/LoadingIndicator.js b/client/src/components/LoadingIndicator.js index 1ea599d..774d4f3 100644 --- a/client/src/components/LoadingIndicator.js +++ b/client/src/components/LoadingIndicator.js @@ -1,13 +1,13 @@ -import React from 'react'; -import { Spin } from 'antd'; -import './LoadingIndicator.css'; +import React from 'react' +import { Spin } from 'antd' +import './LoadingIndicator.css' const LoadingIndicator = () => { return ( -
- +
+
- ); -}; + ) +} -export default LoadingIndicator; \ No newline at end of file +export default LoadingIndicator diff --git a/client/src/contexts/GlobalContext.js b/client/src/contexts/GlobalContext.js index ed3843b..097a0b6 100644 --- a/client/src/contexts/GlobalContext.js +++ b/client/src/contexts/GlobalContext.js @@ -97,7 +97,7 @@ export const ContextWrapper = (props) => { tensorBoardURL, setTensorBoardURL, loading, - setLoading, + setLoading }} > {props.children} diff --git a/client/src/views/DataLoader.js b/client/src/views/DataLoader.js index 5d6cfc4..0cc2451 100644 --- a/client/src/views/DataLoader.js +++ b/client/src/views/DataLoader.js @@ -1,5 +1,5 @@ import React, { useContext, useEffect, useState } from 'react' -import {Dragger} from '../components/Dragger' +import { Dragger } from '../components/Dragger' import { Button, Input, Select, Space, Typography } from 'antd' import { ArrowRightOutlined } from '@ant-design/icons' import { AppContext } from '../contexts/GlobalContext' From 807ad7cae003729fe47b50382c84f6bfa1de8bfc Mon Sep 17 00:00:00 2001 From: mansouralawi Date: Sat, 6 Jul 2024 21:04:36 +0800 Subject: [PATCH 7/9] linter fix --- client/src/components/LoadingIndicator.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/components/LoadingIndicator.css b/client/src/components/LoadingIndicator.css index 3d9f6ee..4a7d142 100644 --- a/client/src/components/LoadingIndicator.css +++ b/client/src/components/LoadingIndicator.css @@ -11,7 +11,6 @@ z-index: 1000; } - /* .loading-indicator { position: absolute; @@ -20,4 +19,4 @@ transform: translate(-50%, -50%); z-index: 1000; } -*/ \ No newline at end of file +*/ From fee1fff1e631c6a9f1d7a28870609673aa58ea66 Mon Sep 17 00:00:00 2001 From: mansouralawi Date: Sat, 6 Jul 2024 21:07:32 +0800 Subject: [PATCH 8/9] js linter --- client/src/components/Dragger.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/client/src/components/Dragger.js b/client/src/components/Dragger.js index 0b5742e..51ee617 100644 --- a/client/src/components/Dragger.js +++ b/client/src/components/Dragger.js @@ -125,38 +125,30 @@ export function Dragger () { console.log('Buffer length: ', buffer.length)// Log buffer length in bytes const tiffPages = UTIF.decode(buffer) // Check if tiffPages array is not empty - if (tiffPages.length === 0) throw new Error('No TIFF pages found') - + if (tiffPages.length === 0) throw new Error('No TIFF pages found') const firstPage = tiffPages[0] console.log('First page before decoding:', firstPage) // Log first page object before decoding - // Ensure the firstPage has necessary tags before decoding if (!firstPage.t256 || !firstPage.t257) throw new Error('First page is missing essential tags (width and height)') UTIF.decodeImage(buffer, firstPage) // firstPage before and after decoding, the result is same. console.log('TIFF first page after decoding: ', firstPage) // Log the first page object - // Extract width and height from the TIFF tags const width = firstPage.t256 ? firstPage.t256[0] : 0 const height = firstPage.t257 ? firstPage.t257[0] : 0 - // Check if width and height are valid if (width > 0 && height > 0) { const rgba = UTIF.toRGBA8(firstPage) // Uint8Array with RGBA pixels - // Create a canvas to draw the TIFF image const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') canvas.width = width canvas.height = height const imageData = ctx.createImageData(width, height) - imageData.data.set(rgba) ctx.putImageData(imageData, 0, 0) - const dataURL = canvas.toDataURL() console.log('Canvas data URL:', dataURL) callback(dataURL) - } else { console.error('TIFF image has invalid dimensions:', { width, height }) message.error('TIFF image has invalid dimensions.') @@ -171,7 +163,7 @@ export function Dragger () { reader.readAsArrayBuffer(file) } - //When click preview eye icon, implement handlePreview function + // When click preview eye icon, implement handlePreview function const handlePreview = async (file) => { context.setLoading(true) setFileUID(file.uid) @@ -198,7 +190,7 @@ export function Dragger () { // when click or drag file to this area to upload, below function will be deployed. const handleBeforeUpload = (file) => { // Create a URL for the thumbnail using object URL - if (file.type === "image/tiff" || file.type === "image/tif") { + if (file.type === 'image/tiff' || file.type === 'image/tif') { return new Promise((resolve) => { generateTiffPreview(file, (dataURL) => { file.thumbUrl = dataURL From fcb8508614c679919986d9bd2ee8071ffc5445dd Mon Sep 17 00:00:00 2001 From: ensenginbaieer Date: Mon, 12 Aug 2024 10:44:39 -0400 Subject: [PATCH 9/9] Uploading Indicator 2nd commit --- client/src/components/Dragger.js | 32 ++++++++++++++++++---- client/src/components/LoadingIndicator.css | 4 +-- client/src/components/LoadingIndicator.js | 16 +++++------ client/src/contexts/GlobalContext.js | 2 +- client/src/views/DataLoader.js | 18 +++++++++--- 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/client/src/components/Dragger.js b/client/src/components/Dragger.js index 51ee617..733713b 100644 --- a/client/src/components/Dragger.js +++ b/client/src/components/Dragger.js @@ -8,7 +8,7 @@ import UTIF from 'utif' const path = require('path') -export function Dragger () { +export function Dragger() { const context = useContext(AppContext) const [uploading, setUploading] = useState(false) const getBase64 = (file) => @@ -21,6 +21,7 @@ export function Dragger () { const onChange = (info) => { const { status } = info.file + console.log("onChange called with file status:", status); //LI if (status === 'done') { console.log('file found at:', info.file.originFileObj.path) @@ -58,6 +59,7 @@ export function Dragger () { const [previewFileFolderPath, setPreviewFileFolderPath] = useState('') const [fileType, setFileType] = useState('Image') + const handleText = (event) => { setValue(event.target.value) } @@ -125,7 +127,7 @@ export function Dragger () { console.log('Buffer length: ', buffer.length)// Log buffer length in bytes const tiffPages = UTIF.decode(buffer) // Check if tiffPages array is not empty - if (tiffPages.length === 0) throw new Error('No TIFF pages found') + if (tiffPages.length === 0) throw new Error('No TIFF pages found') const firstPage = tiffPages[0] console.log('First page before decoding:', firstPage) // Log first page object before decoding // Ensure the firstPage has necessary tags before decoding @@ -153,11 +155,15 @@ export function Dragger () { console.error('TIFF image has invalid dimensions:', { width, height }) message.error('TIFF image has invalid dimensions.') setPreviewImage(DEFAULT_IMAGE) // Fallback to default image + context.setLoading(false) + console.log("Current loading state1:", context.loading); } } catch (error) { console.error('Failed to generate TIFF preview:', error) message.error('Failed to generate TIFF preview.') setPreviewImage(DEFAULT_IMAGE) // Fallback to default image + context.setLoading(false) + console.log("Current loading state2:", context.loading); } } reader.readAsArrayBuffer(file) @@ -165,10 +171,9 @@ export function Dragger () { // When click preview eye icon, implement handlePreview function const handlePreview = async (file) => { - context.setLoading(true) + context.setLoading(true); + console.log("Current loading state3:", context.loading); setFileUID(file.uid) - setPreviewOpen(true) - setPreviewImage(file.thumbUrl) setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)) if ( context.files.find(targetFile => targetFile.uid === file.uid) && @@ -181,6 +186,21 @@ export function Dragger () { // Directory name with trailing slash setPreviewFileFolderPath(path.dirname(file.originFileObj.path) + '/') } + setPreviewOpen(true) + setPreviewImage(file.thumbUrl) + console.log("File type:", file.type); + + if (file.type === 'image/tiff' || file.type === 'image/tif' + || file.type.includes("tiff") || file.type.includes("tif")) { + generateTiffPreview(file, (dataURL) => { + setPreviewImage(dataURL) + context.setLoading(false) // LI(tiff files) + console.log("Current loading state4:", context.loading); + }) + } else { + context.setLoading(false) // LI(other types of files) + console.log("Current loading state5:", context.loading); + } } const listItemStyle = { @@ -258,7 +278,7 @@ export function Dragger () { style={{ width: '100%' }} - src={previewImage} + src={previewImage || DEFAULT_IMAGE} /> diff --git a/client/src/components/LoadingIndicator.css b/client/src/components/LoadingIndicator.css index 4a7d142..f864187 100644 --- a/client/src/components/LoadingIndicator.css +++ b/client/src/components/LoadingIndicator.css @@ -7,7 +7,7 @@ position: absolute; top: 0; left: 0; - background-color: rgb(255 255 255 / 70%); + background-color: rgba(255, 255, 255, 0.7); z-index: 1000; } @@ -19,4 +19,4 @@ transform: translate(-50%, -50%); z-index: 1000; } -*/ +*/ \ No newline at end of file diff --git a/client/src/components/LoadingIndicator.js b/client/src/components/LoadingIndicator.js index 774d4f3..ec315e6 100644 --- a/client/src/components/LoadingIndicator.js +++ b/client/src/components/LoadingIndicator.js @@ -1,13 +1,13 @@ -import React from 'react' -import { Spin } from 'antd' -import './LoadingIndicator.css' +import React from 'react'; +import { Spin } from 'antd'; +import './LoadingIndicator.css'; const LoadingIndicator = () => { return ( -
- +
+
- ) -} + ); +}; -export default LoadingIndicator +export default LoadingIndicator; diff --git a/client/src/contexts/GlobalContext.js b/client/src/contexts/GlobalContext.js index 097a0b6..c7890d3 100644 --- a/client/src/contexts/GlobalContext.js +++ b/client/src/contexts/GlobalContext.js @@ -4,7 +4,7 @@ import localforage from 'localforage' export const AppContext = createContext(null) // Solve delete button error issue -function usePersistedState (key, defaultValue) { +function usePersistedState(key, defaultValue) { const [state, setState] = useState(defaultValue) const [isLoaded, setIsLoaded] = useState(false) diff --git a/client/src/views/DataLoader.js b/client/src/views/DataLoader.js index 0cc2451..19b4f5f 100644 --- a/client/src/views/DataLoader.js +++ b/client/src/views/DataLoader.js @@ -8,7 +8,7 @@ import './DataLoader.css' const { Title } = Typography -function DataLoader (props) { +function DataLoader(props) { const context = useContext(AppContext) const [currentImage, setCurrentImage] = useState(null) const [currentLabel, setCurrentLabel] = useState(null) @@ -18,14 +18,23 @@ function DataLoader (props) { const handleVisualizeButtonClick = async (event) => { event.preventDefault() context.setLoading(true) - context.setCurrentImage(currentImage) - context.setCurrentLabel(currentLabel) + console.log("Current loading state6:", context.loading); + console.log("Loading set to true"); + //context.setCurrentImage(currentImage) + //context.setCurrentLabel(currentLabel) + setCurrentImage(currentImage); + setCurrentLabel(currentLabel); await fetchNeuroglancerViewer( currentImage, currentLabel, scales.split(',').map(Number) ) - context.setLoading(false) + /*setTimeout(() => { //LI + context.setLoading(false); + }, 2000);*/ + context.setLoading(false); + console.log("Loading set to false"); + console.log("Current loading state7:", context.loading); } const handleImageChange = (value) => { console.log(`selected ${value}`) @@ -59,6 +68,7 @@ function DataLoader (props) { align='start' style={{ margin: '7px', display: 'flex' }} > + {context.loading && } Image