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 }) => {
|
export const CrossSearchExportMenuItem = ({ handleClose }: { handleClose: () => void }) => {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const { sqlColumnFilters, sqlOrderBy } = usePageContext()
|
const { sqlColumnFilters, sqlOrderBy } = usePageContext()
|
||||||
const notify = useNotify()
|
const { notify, setMessage } = useNotify()
|
||||||
|
|
||||||
const token = useUser().token
|
const token = useUser().token
|
||||||
const fetchOptions = token ? { headers: { Authorization: `Bearer ${token}` } } : {}
|
const fetchOptions = token ? { headers: { Authorization: `Bearer ${token}` } } : {}
|
||||||
|
|
||||||
const filename = `cross_search${currentDateAsString()}.csv`
|
const filename = `cross_search${currentDateAsString()}.csv`
|
||||||
|
|
||||||
const fetchCSVFile = () => {
|
const fetchCSVFile = async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
notify('Downloading CSV file, please wait...', 'info', null)
|
|
||||||
const URIColumnFilters = encodeURIComponent(JSON.stringify(sqlColumnFilters))
|
const URIColumnFilters = encodeURIComponent(JSON.stringify(sqlColumnFilters))
|
||||||
const URIOrderBy = encodeURIComponent(JSON.stringify(sqlOrderBy))
|
const URIOrderBy = encodeURIComponent(JSON.stringify(sqlOrderBy))
|
||||||
|
|
||||||
fetch(`${BACKEND_URL}/crosssearch/export/${URIColumnFilters}/${URIOrderBy}`, fetchOptions)
|
notify('Generating CSV file, please wait...', 'info', null)
|
||||||
.then(response => {
|
const response = await fetch(`${BACKEND_URL}/crosssearch/export/${URIColumnFilters}/${URIOrderBy}`, fetchOptions)
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Server response was not OK.')
|
if (!response.ok) {
|
||||||
}
|
throw new Error('Server response was not OK.')
|
||||||
return response.blob()
|
}
|
||||||
})
|
const reader = response.body!.getReader()
|
||||||
.then(blob => {
|
const file: Uint8Array<ArrayBufferLike>[] = []
|
||||||
const blobUrl = window.URL.createObjectURL(blob)
|
let bytes = 0
|
||||||
const downloadLink = document.createElement('a')
|
let closed = false
|
||||||
downloadLink.href = blobUrl
|
|
||||||
downloadLink.download = filename
|
const showDownloadProgress = () => {
|
||||||
document.body.appendChild(downloadLink)
|
if (!closed) {
|
||||||
downloadLink.click()
|
setTimeout(() => {
|
||||||
downloadLink.remove()
|
setMessage(`Downloading CSV file, ${Math.round((bytes / 1000000) * 10) / 10} MB`)
|
||||||
window.URL.revokeObjectURL(blobUrl)
|
showDownloadProgress()
|
||||||
notify('Download finished.')
|
}, 500)
|
||||||
})
|
}
|
||||||
.catch(_ => {
|
}
|
||||||
notify('Downloading cross-search export failed.', 'error')
|
showDownloadProgress()
|
||||||
})
|
while (true) {
|
||||||
.finally(() => setLoading(false))
|
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 (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
fetchCSVFile()
|
void fetchCSVFile()
|
||||||
handleClose()
|
handleClose()
|
||||||
}}
|
}}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export type NotificationContext = {
|
|||||||
open: boolean
|
open: boolean
|
||||||
setOpen: (open: boolean) => void
|
setOpen: (open: boolean) => void
|
||||||
message: string
|
message: string
|
||||||
|
setMessage: (message: string) => void
|
||||||
severity?: Severity
|
severity?: Severity
|
||||||
timeoutValue?: number | null
|
timeoutValue?: number | null
|
||||||
}
|
}
|
||||||
@@ -36,7 +37,7 @@ export const NotificationContextProvider = ({ children }: { children: ReactNode
|
|||||||
}, 200)
|
}, 200)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<NotificationContext.Provider value={{ open, setOpen, message, severity, timeoutValue, notify }}>
|
<NotificationContext.Provider value={{ open, setOpen, message, setMessage, severity, timeoutValue, notify }}>
|
||||||
{children}
|
{children}
|
||||||
</NotificationContext.Provider>
|
</NotificationContext.Provider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ import { NotificationContext } from '@/components/Notification'
|
|||||||
import { useContext } from 'react'
|
import { useContext } from 'react'
|
||||||
|
|
||||||
export const useNotify = () => {
|
export const useNotify = () => {
|
||||||
const { notify } = useContext(NotificationContext)
|
const { notify, setMessage } = useContext(NotificationContext)
|
||||||
return notify
|
return { notify, setMessage }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user