refactor: download files from interface (#831)

This commit is contained in:
Carlos Valente
2024-03-18 20:27:58 +01:00
committed by GitHub
parent a91a8a6358
commit 4b21745fc7
5 changed files with 75 additions and 66 deletions
+59 -11
View File
@@ -10,27 +10,54 @@ import {
} from 'ontime-types';
import { ImportMap } from 'ontime-utils';
import { makeCSV, makeTable } from '../../features/cuesheet/cuesheetUtils';
import { apiEntryUrl } from './constants';
import fileDownload from './utils';
import { createBlob, downloadBlob } from './utils';
const dbPath = `${apiEntryUrl}/db`;
/**
* HTTP request to download db in JSON format
* HTTP request to the current DB
*/
export async function downloadRundown(fileName?: string) {
return fileDownload(
dbPath,
{ name: fileName ?? 'rundown', type: 'json' },
{ type: 'application/json;charset=utf-8;' },
);
async function getDb(): Promise<AxiosResponse<DatabaseModel>> {
return axios.get(`${dbPath}/download`);
}
/**
* HTTP request to download db in CSV format
* Request download of the current project file
* @param fileName
*/
export async function downloadCSV(fileName?: string) {
return fileDownload(dbPath, { name: fileName ?? 'rundown', type: 'csv' }, { type: 'text/csv;charset=utf-8;' });
export async function downloadProject(fileName: string = 'ontime-project') {
try {
const { data, name } = await fileDownload(fileName);
const fileContent = JSON.stringify(data, null, 2);
const blob = createBlob(fileContent, 'application/json;charset=utf-8;');
downloadBlob(blob, `${name}.json`);
} catch (error) {
console.error(error);
}
}
/**
* Request download of the current rundown as a CSV file
* @param fileName
*/
export async function downloadCSV(fileName: string = 'rundown') {
try {
const { data, name } = await fileDownload(fileName);
const { project, rundown, customFields } = data;
const sheetData = makeTable(project, rundown, customFields);
const fileContent = makeCSV(sheetData);
const blob = createBlob(fileContent, 'text/csv;charset=utf-8;');
downloadBlob(blob, `${name}.csv`);
} catch (error) {
console.error(error);
}
}
/**
@@ -153,3 +180,24 @@ export async function importSpreadsheetPreview(file: File, options: ImportMap):
return response.data;
}
/**
* Utility function gets project from db
* @param fileName
* @returns
*/
async function fileDownload(fileName: string): Promise<{ data: DatabaseModel; name: string }> {
const response = await getDb();
const headerLine = response.headers['Content-Disposition'];
// try and get the filename from the response
let name = fileName;
if (headerLine != null) {
const startFileNameIndex = headerLine.indexOf('"') + 1;
const endFileNameIndex = headerLine.lastIndexOf('"');
name = headerLine.substring(startFileNameIndex, endFileNameIndex);
}
return { data: response.data, name };
}
+13 -48
View File
@@ -2,7 +2,6 @@ import axios, { AxiosError } from 'axios';
import { LogLevel } from 'ontime-types';
import { generateId, millisToString } from 'ontime-utils';
import { makeCSV, makeTable } from '../../features/cuesheet/cuesheetUtils';
import { ontimeQueryClient } from '../queryClient';
import { addLog } from '../stores/logger';
import { nowInMillis } from '../utils/time';
@@ -56,63 +55,29 @@ export async function invalidateAllCaches() {
await ontimeQueryClient.invalidateQueries();
}
type FileOptions = {
name: string;
type: string;
};
type BlobOptions = {
type: string;
};
/**
* Gets DB from backend and prepares a file to be downloaded
* @param url
* @param fileOptions
* @param blobOptions
* Creates blob from content
* @param fileContent
* @param type
* @returns
*/
export default async function fileDownload(url: string, fileOptions: FileOptions, blobOptions: BlobOptions) {
const response = await axios({
url: `${url}/db`,
method: 'GET',
});
export function createBlob(fileContent: string, type: string): Blob {
return new Blob([fileContent], { type });
}
const headerLine = response.headers['Content-Disposition'];
let { name: fileName } = fileOptions;
const { type: fileType } = fileOptions;
const { project, rundown, customFields } = response.data;
// try and get the filename from the response
if (headerLine != null) {
const startFileNameIndex = headerLine.indexOf('"') + 1;
const endFileNameIndex = headerLine.lastIndexOf('"');
fileName = headerLine.substring(startFileNameIndex, endFileNameIndex);
}
let fileContent = '';
if (fileType === 'json') {
fileContent = JSON.stringify(response.data);
fileName += '.json';
}
if (fileType === 'csv') {
const sheetData = makeTable(project, rundown, customFields);
fileContent = makeCSV(sheetData);
fileName += '.csv';
}
const blob = new Blob([fileContent], { type: blobOptions.type });
/**
* downloads a blob
* @param downloadUrl
* @param fileName
*/
export function downloadBlob(blob: Blob, fileName: string) {
const downloadUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', downloadUrl);
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
// Clean up the URL.createObjectURL to release resources
URL.revokeObjectURL(downloadUrl);
return;
}
@@ -75,10 +75,6 @@ $inner-padding: 1rem;
box-shadow: 0 1px $white-10;
}
tr {
padding: 1rem 0;
}
th {
font-weight: 400;
color: $gray-400;
@@ -5,7 +5,7 @@ import { IoEllipsisHorizontal } from '@react-icons/all-files/io5/IoEllipsisHoriz
import {
deleteProject,
downloadCSV,
downloadRundown,
downloadProject,
duplicateProject,
loadProject,
renameProject,
@@ -148,7 +148,7 @@ function ActionMenu({
};
const handleDownload = async () => {
await downloadRundown(filename);
await downloadProject(filename);
};
const handleExportCSV = async () => {
@@ -1,5 +1,5 @@
.current {
background-color: $blue-900;
background-color: $blue-1100;
}
.actionButton {