mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
changed frontend to download export file in chunks
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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,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 }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user