Unable to prompt browser to save file wi...
# package-development
m
Btw. Did you find any solution to this? https://github.com/hey-api/openapi-ts/issues/796
Just wanted to follow up on this one, Turns out that
@hey-api/openapi-ts
has been working quite hard since the version used in Umbraco (
0.42.1
), they are now at
0.52.4
and they have an option to use
@hey-api/client-fetch
over just
fetch
. When you do that you can get access to the response headers which was part of what I needed. The generated "services" and models are quite different and it seems like they are exploring with generating "tree-shakaeble" services (aka only function) https://heyapi.vercel.app/openapi-ts/migrating.html#tree-shakeable-services Any way, after trying the upgrade to get access to headers I noticed that generating the code in the "old" way that the backoffice has right now breaks, it also would break the
tryExecuteAndNotify
-pattern that Umbraco is using so I ended up just using a reglar fetch call for this one place in the code.
Copy code
// Getting the token from OpenAPI, this was configured from the AuthContext in entry.ts.
const tokenPromise = (OpenAPI.TOKEN as any as () => Promise<string>);
    const token = await tokenPromise();

    const response = await fetch(`/umbraco/api/newsletter-studio/recipients-export/get-details/${this.args.workspaceKey}?e=${this.args.key}`, {
      method: 'GET',
      headers: {
          'Authorization': 'Bearer ' + token
      }
    });

    const blob = await response.blob();
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;

    // Get the filename from the response headers if provided
    const contentDisposition = response.headers.get('Content-Disposition');
    let fileName = 'downloaded_file.pdf';
    if (contentDisposition && contentDisposition.includes('attachment')) {
        const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        const matches = filenameRegex.exec(contentDisposition);
        if (matches != null && matches[1]) {
            fileName = matches[1].replace(/['"]/g, '');
        }
    }

    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    window.URL.revokeObjectURL(url);
w
So my approach is near identical @User
Copy code
ts
let data: Blob | File = new Blob();

// Some Service from Generated OpenAPI Client
data = await ReportDashboardService.generateReport();

// Download the file
downloadBlob(data, `report.csv`);
Copy code
ts
/**
 * Initiates a download of a Blob or File object.
 * @param {Blob | File} data - The data to be downloaded.
 * @param {string} filename - The name of the file to be downloaded.
 */
export function downloadBlob(data: Blob | File | string, filename: string): void {

    // Ensure data is a Blob or File before attempting to download
    if (typeof data === "string") {
        console.warn('Data is string, converting to blob as CSV type');
        data = new Blob([data], { type: "text/csv" });
    }

    // Create a URL for the data
    const url = window.URL.createObjectURL(data);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;

    // Append the anchor to the body
    document.body.appendChild(a);

    // Trigger the download
    a.click();

    // Clean up & remove anchor from body
    window.URL.revokeObjectURL(url);
    document.body.removeChild(a);
}
8 Views