changed frontend to download export file in chunks

This commit is contained in:
juhanikat
2025-07-03 15:54:19 +03:00
parent c3682e44c8
commit d71fa27ced
3 changed files with 49 additions and 29 deletions
@@ -9,46 +9,65 @@ import { currentDateAsString } from '@/shared/currentDateAsString'
export const CrossSearchExportMenuItem = ({ handleClose }: { handleClose: () => void }) => {
const [loading, setLoading] = useState(false)
const { sqlColumnFilters, sqlOrderBy } = usePageContext()
const notify = useNotify()
const { notify, setMessage } = useNotify()
const token = useUser().token
const fetchOptions = token ? { headers: { Authorization: `Bearer ${token}` } } : {}
const filename = `cross_search${currentDateAsString()}.csv`
const fetchCSVFile = () => {
const fetchCSVFile = async () => {
setLoading(true)
notify('Downloading CSV file, please wait...', 'info', null)
const URIColumnFilters = encodeURIComponent(JSON.stringify(sqlColumnFilters))
const URIOrderBy = encodeURIComponent(JSON.stringify(sqlOrderBy))
fetch(`${BACKEND_URL}/crosssearch/export/${URIColumnFilters}/${URIOrderBy}`, fetchOptions)
.then(response => {
if (!response.ok) {
throw new Error('Server response was not OK.')
}
return response.blob()
})
.then(blob => {
const blobUrl = window.URL.createObjectURL(blob)
const downloadLink = document.createElement('a')
downloadLink.href = blobUrl
downloadLink.download = filename
document.body.appendChild(downloadLink)
downloadLink.click()
downloadLink.remove()
window.URL.revokeObjectURL(blobUrl)
notify('Download finished.')
})
.catch(_ => {
notify('Downloading cross-search export failed.', 'error')
})
.finally(() => setLoading(false))
notify('Generating CSV file, please wait...', 'info', null)
const response = await fetch(`${BACKEND_URL}/crosssearch/export/${URIColumnFilters}/${URIOrderBy}`, fetchOptions)
if (!response.ok) {
throw new Error('Server response was not OK.')
}
const reader = response.body!.getReader()
const file: Uint8Array<ArrayBufferLike>[] = []
let bytes = 0
let closed = false
const showDownloadProgress = () => {
if (!closed) {
setTimeout(() => {
setMessage(`Downloading CSV file, ${Math.round((bytes / 1000000) * 10) / 10} MB`)
showDownloadProgress()
}, 500)
}
}
showDownloadProgress()
while (true) {
const { done, value } = await reader.read()
if (done) break
bytes = bytes + value.length
file.push(value)
}
closed = true
try {
const blobUrl = window.URL.createObjectURL(new Blob(file))
const downloadLink = document.createElement('a')
downloadLink.href = blobUrl
downloadLink.download = filename
document.body.appendChild(downloadLink)
downloadLink.click()
downloadLink.remove()
window.URL.revokeObjectURL(blobUrl)
notify('Download finished.')
} catch {
notify('Downloading cross-search export failed.', 'error')
} finally {
setLoading(false)
}
}
return (
<MenuItem
onClick={() => {
fetchCSVFile()
void fetchCSVFile()
handleClose()
}}
disabled={loading}
+2 -1
View File
@@ -8,6 +8,7 @@ export type NotificationContext = {
open: boolean
setOpen: (open: boolean) => void
message: string
setMessage: (message: string) => void
severity?: Severity
timeoutValue?: number | null
}
@@ -36,7 +37,7 @@ export const NotificationContextProvider = ({ children }: { children: ReactNode
}, 200)
}
return (
<NotificationContext.Provider value={{ open, setOpen, message, severity, timeoutValue, notify }}>
<NotificationContext.Provider value={{ open, setOpen, message, setMessage, severity, timeoutValue, notify }}>
{children}
</NotificationContext.Provider>
)
+2 -2
View File
@@ -2,6 +2,6 @@ import { NotificationContext } from '@/components/Notification'
import { useContext } from 'react'
export const useNotify = () => {
const { notify } = useContext(NotificationContext)
return notify
const { notify, setMessage } = useContext(NotificationContext)
return { notify, setMessage }
}