mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-09 09:23:51 +00:00
refactor: download files from interface (#831)
This commit is contained in:
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user