feat: add download file method for files generated by plugin
This commit is contained in:
committed by
Linus Rath
parent
a08a9e9ed3
commit
a679d82cc3
@@ -60,6 +60,7 @@ const PERM_PER_METHOD: Record<string, Permission | null> = {
|
||||
'ui.prompt': null,
|
||||
'ui.rerenderEmail': null,
|
||||
'ui.openExternalUrl': null,
|
||||
'ui.downloadFile': 'ui:download-file'
|
||||
};
|
||||
|
||||
function hasPermission(plugin: InstalledPlugin, perm: Permission): boolean {
|
||||
@@ -400,6 +401,24 @@ async function saveFile(formerFileID:string, file: File): Promise<string> {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
// ─── Download files generated by the plugin. This is not user's files or attachments ──────────────────────────
|
||||
async function downloadFile(args: { content: string; filename: string; contentType?: string }): Promise<void> {
|
||||
const { content, filename, contentType = 'application/json' } = args;
|
||||
|
||||
try {
|
||||
const url = URL.createObjectURL(new Blob([content], { type: contentType }));
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to download file: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── admin config (same as before) ────────────────────────────
|
||||
|
||||
async function adminGetAll(pluginId: string): Promise<Record<string, unknown>> {
|
||||
@@ -547,6 +566,10 @@ export async function dispatchApiCall(
|
||||
window.open(parsed.toString(), '_blank', 'noopener,noreferrer');
|
||||
return undefined;
|
||||
}
|
||||
case 'ui.downloadFile': {
|
||||
const opts = args[0] as { content: string; filename: string; contentType?: string };
|
||||
return downloadFile(opts);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unhandled method "${method}"`);
|
||||
|
||||
@@ -245,7 +245,7 @@ export const API_METHODS = [
|
||||
'jmap.fetchBlob', 'jmap.sendRaw',
|
||||
'admin.getConfig', 'admin.getAllConfig', 'admin.setConfig', 'admin.deleteConfig',
|
||||
'toast.success', 'toast.error', 'toast.info', 'toast.warning',
|
||||
'ui.confirm', 'ui.alert', 'ui.prompt', 'ui.rerenderEmail', 'ui.openExternalUrl',
|
||||
'ui.confirm', 'ui.alert', 'ui.prompt', 'ui.rerenderEmail', 'ui.openExternalUrl', 'ui.downloadFile'
|
||||
] as const;
|
||||
|
||||
export type ApiMethod = (typeof API_METHODS)[number];
|
||||
|
||||
@@ -232,6 +232,9 @@ function buildPluginApi(manifest: PluginManifest) {
|
||||
/** Opens an http/https URL in a new tab via host `window.open`. */
|
||||
openExternalUrl: (url: string, target?: string) =>
|
||||
callApi('ui.openExternalUrl', [url, target]) as Promise<void>,
|
||||
/** Downloads a file generated by the plugin. Not a user's file or attachment. */
|
||||
downloadFile: (opts: { content: string; filename: string; contentType?: string }) =>
|
||||
callApi('ui.downloadFile', [opts]) as Promise<void>,
|
||||
},
|
||||
admin: {
|
||||
getConfig: (key: string) => callApi('admin.getConfig', [key]),
|
||||
|
||||
@@ -925,6 +925,7 @@ export const ALL_PERMISSIONS = [
|
||||
'http:post', 'http:fetch',
|
||||
'ui:observe', 'ui:toolbar', 'ui:app-top-banner', 'ui:email-banner', 'ui:email-footer',
|
||||
'ui:email-details',
|
||||
'ui:download-file',
|
||||
'ui:composer-toolbar', 'ui:composer-sidebar',
|
||||
'ui:sidebar-widget', 'ui:settings-section',
|
||||
'ui:context-menu', 'ui:navigation-rail', 'ui:keyboard',
|
||||
|
||||
Reference in New Issue
Block a user