diff --git a/public/app/features/inspector/utils/download.test.ts b/public/app/features/inspector/utils/download.test.ts index 7294ded12fe..6735731dabb 100644 --- a/public/app/features/inspector/utils/download.test.ts +++ b/public/app/features/inspector/utils/download.test.ts @@ -38,10 +38,25 @@ describe('inspector download', () => { const filename = call[1]; const text = await blob.text(); + // By default the BOM character should not be included + expect(await hasBOM(blob)).toBe(false); expect(text).toEqual(expected); expect(filename).toEqual(`${title}-data-${dateTimeFormat(1400000000000)}.csv`); } ); + + it('should include the BOM character when useExcelHeader is true', async () => { + downloadDataFrameAsCsv(dataFrameFromJSON(json), 'test', { useExcelHeader: true }); + + const call = (saveAs as unknown as jest.Mock).mock.calls[0]; + const blob = call[0]; + const filename = call[1]; + const text = await blob.text(); + + expect(await hasBOM(blob)).toBe(true); + expect(text).toEqual('sep=,\r\n"time","name","value"\r\n100,a,1'); + expect(filename).toEqual(`test-data-${dateTimeFormat(1400000000000)}.csv`); + }); }); describe('downloadAsJson', () => { @@ -104,3 +119,19 @@ describe('inspector download', () => { }); }); }); + +async function hasBOM(blob: Blob) { + const reader = new FileReader(); + return new Promise((resolve, reject) => { + reader.onload = (event: ProgressEvent) => { + if (event.target?.result instanceof ArrayBuffer) { + const arr = new Uint8Array(event.target.result); + resolve(arr[0] === 0xef && arr[1] === 0xbb && arr[2] === 0xbf); // Check for UTF-8 BOM + } else { + reject(new Error('Unexpected FileReader result type')); + } + }; + reader.onerror = reject; + reader.readAsArrayBuffer(blob.slice(0, 3)); // Read only the first 3 bytes + }); +} diff --git a/public/app/features/inspector/utils/download.ts b/public/app/features/inspector/utils/download.ts index 47c52a47f3a..2a7c203677b 100644 --- a/public/app/features/inspector/utils/download.ts +++ b/public/app/features/inspector/utils/download.ts @@ -57,8 +57,9 @@ export function downloadDataFrameAsCsv( transformId: DataTransformerID = DataTransformerID.noop ) { const dataFrameCsv = toCSV([dataFrame], csvConfig); + const bomChar = csvConfig?.useExcelHeader ? String.fromCharCode(0xfeff) : ''; - const blob = new Blob([String.fromCharCode(0xfeff), dataFrameCsv], { + const blob = new Blob([bomChar, dataFrameCsv], { type: 'text/csv;charset=utf-8', });