diff --git a/src/components/Dashboard/common/FilePreview.jsx b/src/components/Dashboard/common/FilePreview.jsx
index 78c2352f..39ca131d 100644
--- a/src/components/Dashboard/common/FilePreview.jsx
+++ b/src/components/Dashboard/common/FilePreview.jsx
@@ -1,4 +1,5 @@
import PropTypes from 'prop-types'
+import { Card, Flex } from 'antd'
import { ApiServerContext } from '../context/ApiServerContext'
import {
useCallback,
@@ -8,10 +9,10 @@ import {
memo,
useRef
} from 'react'
-import LoadingPlaceholder from './LoadingPlaceholder'
import GCodePreview from './GCodePreview'
import ThreeDPreview from './ThreeDPreview'
import PDFPreview from './PDFPreview'
+import ProgressDisplay from './ProgressDisplay'
import { AuthContext } from '../context/AuthContext'
const hasExplicitPreviewHeight = (height) =>
@@ -25,6 +26,10 @@ const FilePreview = ({ file, style = {} }) => {
const [fileObjectUrl, setFileObjectUrl] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
+ const [downloadProgress, setDownloadProgress] = useState({
+ progress: 0,
+ message: 'Loading file preview...'
+ })
const currentId = useRef(null)
@@ -39,78 +44,147 @@ const FilePreview = ({ file, style = {} }) => {
if (error != null) {
return
}
+ const requestId = file._id
setLoading(true)
- const objectUrl = await fetchFileContent(file, false)
+ setDownloadProgress({ progress: 0, message: 'Starting download...' })
+ const objectUrl = await fetchFileContent(file, false, (progress) => {
+ if (currentId.current !== requestId) {
+ return
+ }
+ setDownloadProgress(progress)
+ })
+ if (currentId.current !== requestId) {
+ return
+ }
if (objectUrl == null) {
setLoading(false)
+ setDownloadProgress(null)
console.error('Failed to fetch file content', file)
setError('Failed to fetch file content')
return
}
setFileObjectUrl(objectUrl)
+ setDownloadProgress(null)
setLoading(false)
}, [file, fetchFileContent, error])
useEffect(() => {
+ if (file._id !== currentId.current) {
+ setFileObjectUrl(null)
+ setError(null)
+ setLoading(true)
+ setDownloadProgress({
+ progress: 0,
+ message: 'Loading file preview...'
+ })
+ }
if (file?.type && token != null && file._id !== currentId.current) {
currentId.current = file._id
fetchPreview()
}
}, [file._id, file?.type, fetchPreview, token])
- if (isPdf) {
- if (error != null) {
- return
{error}
+ const showProgressOverlay = downloadProgress != null
+ const wrapperHeight = hasExplicitPreviewHeight(style.height)
+ ? style.height
+ : isPdf
+ ? '72vh'
+ : style.height
+
+ const renderPreview = () => {
+ if (isPdf) {
+ return (
+
+ )
}
- return (
-
- )
- }
+ if (loading == true || !file?.type) {
+ return null
+ }
- if (loading == true || !file?.type) {
- return
+ if (isGcode && fileObjectUrl) {
+ return (
+
+ )
+ }
+
+ if (is3DModel && fileObjectUrl) {
+ return (
+
+ )
+ }
+
+ if (isImage && fileObjectUrl) {
+ return
+ }
+
+ return null
}
if (error != null) {
return {error}
}
- if (isGcode && fileObjectUrl) {
- return (
-
- )
- }
-
- if (is3DModel && fileObjectUrl) {
- return (
-
- )
- }
-
- if (isImage && fileObjectUrl) {
- return
- }
- return null
+ return (
+
+
+ {showProgressOverlay ? (
+
+
+
+ {downloadProgress.message || 'Downloading...'}
+
+
+
+ ) : null}
+
+ {renderPreview()}
+
+ )
}
FilePreview.propTypes = {
@@ -122,6 +196,8 @@ FilePreview.propTypes = {
const areEqual = (prevProps, nextProps) => {
return (
prevProps.file?._id === nextProps.file?._id &&
+ prevProps.file?.type === nextProps.file?.type &&
+ prevProps.file?.size === nextProps.file?.size &&
JSON.stringify(prevProps.style) === JSON.stringify(nextProps.style)
)
}
diff --git a/src/components/Dashboard/context/ApiServerContext.jsx b/src/components/Dashboard/context/ApiServerContext.jsx
index 1109eeb9..3da2e239 100644
--- a/src/components/Dashboard/context/ApiServerContext.jsx
+++ b/src/components/Dashboard/context/ApiServerContext.jsx
@@ -1829,8 +1829,11 @@ const ApiServerProvider = ({ children }) => {
}
// Download GCode file content
- const fetchFileContent = async (file, download = false) => {
+ const fetchFileContent = async (file, download = false, onProgress = null) => {
try {
+ if (typeof onProgress === 'function') {
+ onProgress({ progress: 0, message: 'Starting download...' })
+ }
const response = await axios.get(
`${config.backendUrl}/files/${file._id}/content`,
{
@@ -1838,13 +1841,32 @@ const ApiServerProvider = ({ children }) => {
Accept: '*/*',
Authorization: `Bearer ${token}`
},
- responseType: 'blob'
+ responseType: 'blob',
+ onDownloadProgress: (progressEvent) => {
+ if (typeof onProgress !== 'function') {
+ return
+ }
+ const total =
+ progressEvent.total > 0
+ ? progressEvent.total
+ : typeof file.size === 'number' && file.size > 0
+ ? file.size
+ : 0
+ const progress = total > 0 ? progressEvent.loaded / total : 0
+ onProgress({
+ progress: Math.min(progress, 1),
+ message: 'Downloading...'
+ })
+ }
}
)
const blob = new Blob([response.data], {
type: response.headers['content-type']
})
const fileURL = window.URL.createObjectURL(blob)
+ if (typeof onProgress === 'function') {
+ onProgress({ progress: 1, message: 'Download complete' })
+ }
if (download == true) {
const fileLink = document.createElement('a')
fileLink.href = fileURL
@@ -1858,7 +1880,7 @@ const ApiServerProvider = ({ children }) => {
} catch (err) {
console.error(err)
showError(err, () => {
- fetchFileContent(file, download)
+ fetchFileContent(file, download, onProgress)
})
}
}