Skip to content

Commit

Permalink
[kbss-cvut#37] Implement export of records to JSON.
Browse files Browse the repository at this point in the history
  • Loading branch information
ledsoft committed Dec 15, 2023
1 parent d1c8dac commit c1769f6
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 18 deletions.
14 changes: 14 additions & 0 deletions js/actions/AsyncActionUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function asyncRequest(type) {
return {type};
}

export function asyncError(type, error) {
return {
type,
error
};
}

export function asyncSuccess(type) {
return {type};
}
34 changes: 25 additions & 9 deletions js/actions/RecordsActions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as ActionConstants from "../constants/ActionConstants";
import {ROLE} from "../constants/DefaultConstants";
import {HttpHeaders, ROLE} from "../constants/DefaultConstants";
import {axiosBackend} from "./index";
import {API_URL} from '../../config';
import {asyncError, asyncRequest, asyncSuccess} from "./AsyncActionUtils";
import {fileDownload} from "../utils/Utils";

export function loadRecords(currentUser, institutionKey = null) {
//console.log("Loading records");
Expand All @@ -22,9 +24,7 @@ export function loadRecords(currentUser, institutionKey = null) {
}

export function loadRecordsPending() {
return {
type: ActionConstants.LOAD_RECORDS_PENDING
}
return asyncRequest(ActionConstants.LOAD_RECORDS_PENDING);
}

export function loadRecordsSuccess(records) {
Expand All @@ -35,12 +35,28 @@ export function loadRecordsSuccess(records) {
}

export function loadRecordsError(error) {
return {
type: ActionConstants.LOAD_RECORDS_ERROR,
error
}
return asyncError(ActionConstants.LOAD_RECORDS_ERROR, error);
}

export function exportRecords(exportType, institutionKey) {

return (dispatch) => {
dispatch(asyncRequest(ActionConstants.EXPORT_RECORDS_PENDING));
const urlSuffix = institutionKey ? `?institution=${institutionKey}` : '';
return axiosBackend.get(`${API_URL}/rest/records/export${urlSuffix}`, {
headers: {
accept: exportType.mediaType
},
responseType: 'arraybuffer'
}).then((resp) => {
const disposition = resp.headers[HttpHeaders.CONTENT_DISPOSITION];
const filenameMatch = disposition
? disposition.match(/filename="(.+\..+)"/)
: null;
const fileName = filenameMatch ? filenameMatch[1] : "records" + exportType.fileExtension;
fileDownload(resp.data, fileName, exportType.mediaType);
return dispatch(asyncSuccess(ActionConstants.EXPORT_RECORDS_SUCCESS));
}).catch((error) => {
dispatch(asyncError(ActionConstants.EXPORT_RECORDS_ERROR, error.response.data));
});
}
}
8 changes: 5 additions & 3 deletions js/components/institution/InstitutionController.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
updateInstitution
} from "../../actions/InstitutionActions";
import * as EntityFactory from "../../utils/EntityFactory";
import {loadRecords} from "../../actions/RecordsActions";
import {exportRecords, loadRecords} from "../../actions/RecordsActions";
import omit from 'lodash/omit';
import {loadFormTemplates} from "../../actions/FormTemplatesActions";

Expand Down Expand Up @@ -126,7 +126,8 @@ class InstitutionController extends React.Component {
};

_onExportRecords = (exportType) => {
// TODO
const institutionKey = this.state.institution.key;
this.props.exportRecords(exportType, institutionKey);
};

_onAddNewUser = (institution) => {
Expand Down Expand Up @@ -191,6 +192,7 @@ function mapDispatchToProps(dispatch) {
loadFormTemplates: bindActionCreators(loadFormTemplates, dispatch),
deleteUser: bindActionCreators(deleteUser, dispatch),
transitionToWithOpts: bindActionCreators(transitionToWithOpts, dispatch),
unloadInstitutionMembers: bindActionCreators(unloadInstitutionMembers, dispatch)
unloadInstitutionMembers: bindActionCreators(unloadInstitutionMembers, dispatch),
exportRecords: bindActionCreators(exportRecords, dispatch)
}
}
7 changes: 4 additions & 3 deletions js/components/record/RecordsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React from 'react';
import Records from "./Records";
import Routes from "../../constants/RoutesConstants";
import {transitionToWithOpts} from "../../utils/Routing";
import {loadRecords} from "../../actions/RecordsActions";
import {exportRecords, loadRecords} from "../../actions/RecordsActions";
import {injectIntl} from "react-intl";
import withI18n from "../../i18n/withI18n";
import {connect} from "react-redux";
Expand Down Expand Up @@ -54,7 +54,7 @@ class RecordsController extends React.Component {
};

_onExportRecords = (exportType) => {

this.props.exportRecords(exportType);
};

render() {
Expand Down Expand Up @@ -92,7 +92,8 @@ function mapDispatchToProps(dispatch) {
return {
deleteRecord: bindActionCreators(deleteRecord, dispatch),
loadRecords: bindActionCreators(loadRecords, dispatch),
exportRecords: bindActionCreators(exportRecords, dispatch),
loadFormTemplates: bindActionCreators(loadFormTemplates, dispatch),
transitionToWithOpts: bindActionCreators(transitionToWithOpts, dispatch)
transitionToWithOpts: bindActionCreators(transitionToWithOpts, dispatch),
}
}
3 changes: 2 additions & 1 deletion js/constants/DefaultConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ export const STATISTICS_TYPE = {
export const SCRIPT_ERROR = 'SCRIPT_ERROR';

export const HttpHeaders = {
AUTHORIZATION: "Authorization"
AUTHORIZATION: "Authorization",
CONTENT_DISPOSITION: "content-disposition"
}

export const MediaType = {
Expand Down
6 changes: 4 additions & 2 deletions js/constants/ExportType.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import {MediaType} from "./DefaultConstants";

export const ExportType = {
EXCEL: {
mediaType: MediaType.EXCEL
mediaType: MediaType.EXCEL,
fileExtension: ".xslx"
},
JSON: {
mediaType: MediaType.JSON
mediaType: MediaType.JSON,
fileExtension: ".json"
}
};
22 changes: 22 additions & 0 deletions js/utils/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,25 @@ export function formatDateWithMilliseconds(timestamp) {
export function sanitizeArray(arr) {
return arr ? (Array.isArray(arr) ? arr : [arr]) : [];
}

/**
* Ensures that file download using Ajax triggers browser file save mechanism.
*
* Adapted from https://github.com/kennethjiang/js-file-download/blob/master/file-download.js
* @param data The downloaded data
* @param filename Name of the file
* @param mimeType Type of data
*/
export function fileDownload(data, filename, mimeType = "application/octet-stream") {
const blob = new Blob([data], {type: mimeType});
const blobURL = window.URL.createObjectURL(blob);
const tempLink = document.createElement("a");
tempLink.style.display = "none";
tempLink.href = blobURL;
tempLink.setAttribute("download", filename);

document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
}

0 comments on commit c1769f6

Please sign in to comment.