Files
modeling-app/src/lib/browserSaveFile.ts
Frank Noirot 00fa40bbc9 Bug fix: make dismiss during export not fire success toast (#3882)
* Bug fix: make dismiss during export not fire success toast

* Fix export fail test, since this failure errors early now

* Remove throttling from send side

* Move toast.loading out to when first engine command is sent, so it is shown immediately

* Use shared, named constants for toast messages

* Hook up a couple other error toasts to the `pendingExport.toastId`
2024-09-17 19:06:06 -04:00

71 lines
2.2 KiB
TypeScript

/// The method below uses the File System Access API when it's supported and
// else falls back to the classic approach. In both cases the function saves
// the file, but in case of where the File System Access API is supported, the
import toast from 'react-hot-toast'
import { EXPORT_TOAST_MESSAGES } from './constants'
// user will get a file save dialog where they can choose where the file should be saved.
export const browserSaveFile = async (
blob: Blob,
suggestedName: string,
toastId: string
) => {
// Feature detection. The API needs to be supported
// and the app not run in an iframe.
const supportsFileSystemAccess =
'showSaveFilePicker' in window &&
(() => {
try {
return window.self === window.top
} catch {
return false
}
})()
// If the File System Access API is supported…
if (
supportsFileSystemAccess &&
window.showSaveFilePicker &&
!(window as any).playwrightSkipFilePicker
) {
try {
// Show the file save dialog.
const handle = await window.showSaveFilePicker({
suggestedName,
})
// Write the blob to the file.
const writable = await handle.createWritable()
await writable.write(blob)
await writable.close()
toast.success(EXPORT_TOAST_MESSAGES.SUCCESS, { id: toastId })
return
} catch (err: any) {
// Fail silently if the user has simply canceled the dialog.
if (err.name === 'AbortError') {
toast.dismiss(toastId)
} else {
console.error(err.name, err.message)
toast.error(EXPORT_TOAST_MESSAGES.FAILED, { id: toastId })
}
return
}
}
// Fallback if the File System Access API is not supported…
// Create the blob URL.
const blobURL = URL.createObjectURL(blob)
// Create the `<a download>` element and append it invisibly.
const a = document.createElement('a')
a.href = blobURL
a.download = suggestedName
a.style.display = 'none'
document.body.append(a)
// Programmatically click the element.
a.click()
// Revoke the blob URL and remove the element.
setTimeout(() => {
URL.revokeObjectURL(blobURL)
a.remove()
}, 1000)
toast.success(EXPORT_TOAST_MESSAGES.SUCCESS, { id: toastId })
}