diff options
Diffstat (limited to 'openecomp-ui/src')
8 files changed, 249 insertions, 202 deletions
diff --git a/openecomp-ui/src/nfvo-components/loader/Loader.jsx b/openecomp-ui/src/nfvo-components/loader/Loader.jsx index cbfed1b214..9ebe52dcfc 100644 --- a/openecomp-ui/src/nfvo-components/loader/Loader.jsx +++ b/openecomp-ui/src/nfvo-components/loader/Loader.jsx @@ -1,18 +1,19 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2017 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing - * permissions and limitations under the License. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + import React from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; @@ -33,9 +34,12 @@ class Loader extends React.Component { isLoading: false }; + shouldComponentUpdate(nextProps) { + return (nextProps.isLoading !== this.props.isLoading); + } + render() { let {isLoading} = this.props; - return ( <div className='onboarding-loader'> { diff --git a/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js b/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js index 7c0c0e2b08..2b531b08fa 100644 --- a/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js +++ b/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js @@ -1,21 +1,24 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2017 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing - * permissions and limitations under the License. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ SHOW: null, - HIDE: null + HIDE: null, + + SEND_REQUEST: null, + RECEIVE_RESPONSE: null }); diff --git a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js index 2eff70a617..3afdad0573 100644 --- a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js +++ b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js @@ -1,22 +1,50 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2017 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing - * permissions and limitations under the License. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ import {actionTypes} from './LoaderConstants.js'; -export default (state = {}, action) => { +export default (state = {fetchingRequests : 0, currentlyFetching : [], isLoading : false}, action) => { + let fetchingRequests = state.fetchingRequests; + let newArray; switch (action.type) { + case actionTypes.SEND_REQUEST: + fetchingRequests++; + newArray = state.currentlyFetching.slice(); + newArray.splice(0, 0, action.url); + if (DEBUG) { + console.log('Loader SEND REQUEST url: ' + action.url); + console.log('Loader SEND REQUEST number of fetching requests: ' + fetchingRequests); + } + return { + fetchingRequests: fetchingRequests, + currentlyFetching : newArray, + isLoading: true + }; + case actionTypes.RECEIVE_RESPONSE: + fetchingRequests--; + + newArray = state.currentlyFetching.filter((item) => {return item !== action.url;}); + if (DEBUG) { + console.log('Loader RECEIVE_RESPONSE url: ' + action.url); + console.log('Loader RECEIVE_RESPONSE: number of fetching requests: ' + fetchingRequests); + } + return { + currentlyFetching : newArray, + fetchingRequests: fetchingRequests, + isLoading: (fetchingRequests !== 0) + }; case actionTypes.SHOW: return {isLoading: true}; case actionTypes.HIDE: diff --git a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js index d58a2454b6..146d5285d9 100644 --- a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js +++ b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js @@ -1,17 +1,17 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2017 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing - * permissions and limitations under the License. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ import store from 'sdc-app/AppStore.js'; import React from 'react'; @@ -54,15 +54,15 @@ function parseATTExceptionObject(responseJSON) { return {title, msg}; } -var errorResponseHandler = (xhr/*, textStatus, errorThrown*/) => { +var errorResponseHandler = (error) => { let errorData; - if (xhr.responseJSON) { - errorData = parseATTExceptionObject(xhr.responseJSON); + if (error.data) { + errorData = parseATTExceptionObject(error.data); } else { errorData = { - title: xhr.statusText, - msg: xhr.responseText, + title: error.statusText, + msg: error.responseText, }; } store.dispatch({ diff --git a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js index c878c9e673..01819844c7 100644 --- a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js +++ b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js @@ -1,45 +1,70 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2017 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing - * permissions and limitations under the License. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ -import {RestfulAPI} from 'restful-js'; import uuid from 'uuid-js'; import md5 from 'md5'; +import axios from 'axios'; import store from 'sdc-app/AppStore.js'; import {actionTypes as LoaderConstants} from 'nfvo-components/loader/LoaderConstants.js'; import Configuration from 'sdc-app/config/Configuration.js'; import errorResponseHandler from './ErrorResponseHandler.js'; +//methods +const GET = 'GET'; +const POST = 'POST'; +const PUT = 'PUT'; +const DELETE = 'DELETE'; + +// content-types +const APPLICATION_JSON = 'application/json'; +const MULTIPART_FORM_DATA = 'multipart/form-data'; + +const BINARY = 'binary'; + const AUTHORIZATION_HEADER = 'X-AUTH-TOKEN'; const STORAGE_AUTH_KEY = 'sdc-auth-token'; const REQUEST_ID_HEADER = 'X-ECOMP-RequestID'; const CONTENT_MD5_HEADER = 'Content-MD5'; +function applySecurity(options, data) { + let headers = options.headers || (options.headers = {}); + let authToken = localStorage.getItem(STORAGE_AUTH_KEY); + if (authToken) { + headers[AUTHORIZATION_HEADER] = authToken; + } -function applyMD5Header(options, data) { + let attApiHeaders = Configuration.get('ATTApiHeaders'), + attUidHeader = attApiHeaders && attApiHeaders.userId; + if (attUidHeader) { + headers[attUidHeader.name] = attUidHeader.value; + } + + headers[REQUEST_ID_HEADER] = uuid.create().toString(); if (options.md5) { let headers = options.headers; headers[CONTENT_MD5_HEADER] = window.btoa(md5(JSON.stringify(data)).toLowerCase()); } } -function handleResponse(xhr) { - let authToken = xhr.getResponseHeader(AUTHORIZATION_HEADER); - let prevToken = this && this.headers && this.headers[AUTHORIZATION_HEADER]; + +function handleSuccess(responseHeaders, requestHeaders) { + let authToken = responseHeaders[AUTHORIZATION_HEADER]; + let prevToken = requestHeaders && requestHeaders[AUTHORIZATION_HEADER]; if (authToken && authToken !== prevToken) { if (authToken === 'null') { localStorage.removeItem(STORAGE_AUTH_KEY); @@ -49,94 +74,89 @@ function handleResponse(xhr) { } } +class RestAPIUtil { + handleRequest(url, type, options = {}, data){ + if (DEBUG) { + console.log('axios --> Making REST call (' + type + '): ' + url); + } -class RestAPIUtil extends RestfulAPI { + applySecurity(options, data); - applySecurity(options, data) { - let headers = options.headers || (options.headers = {}); + // TODO see ig necessary or in transformrequest funtion + if (type === POST || type === PUT) { + if (data instanceof FormData) { + options.headers.contentType = MULTIPART_FORM_DATA; + } + else { + options.headers.contentType = APPLICATION_JSON; +// config.data = JSON.stringify(data); + } - let authToken = localStorage.getItem(STORAGE_AUTH_KEY); - if (authToken) { - headers[AUTHORIZATION_HEADER] = authToken; + } else { + data = null; } - let attApiHeaders = Configuration.get('ATTApiHeaders'), - attUidHeader = attApiHeaders && attApiHeaders.userId; - if (attUidHeader) { - headers[attUidHeader.name] = attUidHeader.value; + let config = { + method: type, + url: url, + headers : options.headers, + data : data + }; + + store.dispatch({type: LoaderConstants.SEND_REQUEST, url: url}); + if (options.dataType === BINARY) { + config.responseType = 'arraybuffer'; + return axios(config). + then(result => { + store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : result.config.url}); + return ({ + blob : new Blob([result.data] ), + headers : result.headers + }); + }).catch(error => { + store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : error.config.url}); + errorResponseHandler(error.response); }); + } else { + return axios(config). + then(result => { + store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : result.config.url}); + handleSuccess(result.headers, result.config.headers); + return result.data; + }).catch(error => { + store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : error.config.url}); + errorResponseHandler(error.response); + throw {responseJSON: error.response.data}; + }); } - headers[REQUEST_ID_HEADER] = uuid.create().toString(); - applyMD5Header(options, data); } - handleRequest(url, type, options = {}, data){ - let success = options.success; - options.success = function (resp, textStatus, xhr) { - handleResponse.call(this, xhr); - if (success) { - success.call(options.context, {...resp}, textStatus, xhr); - } - }; + fetch(url, options) { + return this.handleRequest(url, GET, options); + } - if (DEBUG) { - console.log('--> Making REST call (' + type + '): ' + url); - } - return super.handleRequest(url, type, options, data); + get(url, options) { + return this.fetch(url, options); } -} + post(url, data, options) { + return this.handleRequest(url, POST, options, data); + } -const instance = new RestAPIUtil({ - errorResponseHandler, - ajaxStartHandler: () => store.dispatch({type: LoaderConstants.SHOW}), - ajaxStopHandler: () => store.dispatch({type: LoaderConstants.HIDE}) -}); - -// jQuery binary transport to download files through XHR -// http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ -// https://github.com/henrya/js-jquery/tree/master/BinaryTransport -instance.$.ajaxTransport('+binary', function (options/*, originalOptions , jqXHR*/) { - // check for conditions and support for blob / arraybuffer response type - if (window.FormData && ((options.dataType && (options.dataType === 'binary')) || - (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || - (window.Blob && options.data instanceof Blob)))) - ) { - return { - // create new XMLHttpRequest - send: function (headers, callback) { - // setup all letiables - let xhr = new XMLHttpRequest(), - url = options.url, - type = options.type, - async = options.async || true, - // blob or arraybuffer. Default is blob - dataType = options.responseType || 'blob', - data = options.data || null, - username = options.username || null, - password = options.password || null; - - xhr.addEventListener('load', function () { - let data = {}; - data[options.dataType] = xhr.response; - // make callback and send data - callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders()); - }); + put(url, data, options) { + return this.handleRequest(url, PUT, options, data); + } - xhr.open(type, url, async, username, password); + destroy(url, options) { + return this.handleRequest(url, DELETE, options); + } + + + +} + +const instance = new RestAPIUtil(); - // setup custom headers - for (let i in headers) { - xhr.setRequestHeader(i, headers[i]); - } - xhr.responseType = dataType; - xhr.send(data); - }, - abort: function () { - } - }; - } -}); export default instance; diff --git a/openecomp-ui/src/nfvo-utils/ShowFileSaveDialog.js b/openecomp-ui/src/nfvo-utils/ShowFileSaveDialog.js new file mode 100644 index 0000000000..bddd49c700 --- /dev/null +++ b/openecomp-ui/src/nfvo-utils/ShowFileSaveDialog.js @@ -0,0 +1,49 @@ +/* + * Copyright © 2016-2017 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function getTimestampString() { + let date = new Date(); + let z = n => n < 10 ? '0' + n : n; + return `${date.getFullYear()}-${z(date.getMonth())}-${z(date.getDate())}_${z(date.getHours())}-${z(date.getMinutes())}`; +} + + +export default function showFileSaveDialog({blob, headers, defaultFilename, addTimestamp}) { + let filename; + let contentDisposition = headers['content-disposition'] ? headers['content-disposition'] : ''; + let match = contentDisposition ? contentDisposition.match(/filename=(.*?)(;|$)/) : false; + if (match) { + filename = match[1]; + } else { + filename = defaultFilename; + } + + if (addTimestamp) { + filename = filename.replace(/(^.*?)\.([^.]+$)/, `$1_${getTimestampString()}.$2`); + } + + let link = document.createElement('a'); + let url = URL.createObjectURL(blob); + link.href = url; + link.download = filename; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + setTimeout(function(){ + document.body.removeChild(link); + URL.revokeObjectURL(url); + }, 0); +}; diff --git a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js index 3c41b126e6..fa2d4695ae 100644 --- a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js +++ b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js @@ -1,19 +1,20 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2017 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing - * permissions and limitations under the License. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import showFileSaveDialog from 'nfvo-utils/ShowFileSaveDialog.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import isEqual from 'lodash/isEqual.js'; import cloneDeep from 'lodash/cloneDeep.js'; @@ -30,13 +31,6 @@ const options = { } }; - -function getTimestampString() { - let date = new Date(); - let z = n => n < 10 ? '0' + n : n; - return `${date.getFullYear()}-${z(date.getMonth())}-${z(date.getDate())}_${z(date.getHours())}-${z(date.getMinutes())}`; -} - function fetchVspIdAndVersion() { let vspId = sessionStorage.getItem('validationAppVspId'); @@ -55,34 +49,6 @@ function fetchVspIdAndVersion() { } -function showFileSaveDialog({blob, xhr, defaultFilename, addTimestamp}) { - let filename; - let contentDisposition = xhr.getResponseHeader('content-disposition'); - let match = contentDisposition ? contentDisposition.match(/filename=(.*?)(;|$)/) : false; - if (match) { - filename = match[1]; - } else { - filename = defaultFilename; - } - - if (addTimestamp) { - filename = filename.replace(/(^.*?)\.([^.]+$)/, `$1_${getTimestampString()}.$2`); - } - - let link = document.createElement('a'); - let url = URL.createObjectURL(blob); - link.href = url; - link.download = filename; - link.style.display = 'none'; - document.body.appendChild(link); - link.click(); - setTimeout(function(){ - document.body.removeChild(link); - URL.revokeObjectURL(url); - }, 0); -} - - function uploadFile(formData) { return fetchVspIdAndVersion() .then(response => { @@ -137,9 +103,9 @@ function downloadHeatFile() { ...options, dataType: 'binary' }) - .done((blob, statusText, xhr) => showFileSaveDialog({ - blob, - xhr, + .done((response) => showFileSaveDialog({ + blob: response.blob, + headers: response.headers, defaultFilename: 'HEAT_file.zip', addTimestamp: true })); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js index 735c6d7f8b..355c823afe 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js @@ -1,19 +1,20 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2017 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing - * permissions and limitations under the License. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import showFileSaveDialog from 'nfvo-utils/ShowFileSaveDialog.js'; import Configuration from 'sdc-app/config/Configuration.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; @@ -182,40 +183,6 @@ function getExpandedItemsId(items, itemIdToToggle) { return false; } -function getTimestampString() { - let date = new Date(); - let z = n => n < 10 ? '0' + n : n; - return `${date.getFullYear()}-${z(date.getMonth())}-${z(date.getDate())}_${z(date.getHours())}-${z(date.getMinutes())}`; -} - -function showFileSaveDialog({blob, xhr, defaultFilename, addTimestamp}) { - let filename; - let contentDisposition = xhr.getResponseHeader('content-disposition') ? xhr.getResponseHeader('content-disposition') : ''; - let match = contentDisposition.match(/filename=(.*?)(;|$)/); - if (match) { - filename = match[1]; - } - else { - filename = defaultFilename; - } - - if (addTimestamp) { - filename = filename.replace(/(^.*?)\.([^.]+$)/, `$1_${getTimestampString()}.$2`); - } - - let link = document.createElement('a'); - let url = URL.createObjectURL(blob); - link.href = url; - link.download = filename; - link.style.display = 'none'; - document.body.appendChild(link); - link.click(); - setTimeout(function(){ - document.body.removeChild(link); - URL.revokeObjectURL(url); - }, 0); -} - function migrateSoftwareProduct(vspId, version) { return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/heal`); } @@ -325,10 +292,20 @@ const SoftwareProductActionHelper = { }, downloadHeatFile(dispatch, {softwareProductId, heatCandidate, isReadOnlyMode, version}){ - let p = isReadOnlyMode ? Promise.resolve() : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate, version}); + let p = isReadOnlyMode ? Promise.resolve() : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, { + softwareProductId, + heatCandidate, + version}); p.then(() => { fetchOrchestrationTemplateCandidate(softwareProductId, version) - .then((blob, statusText, xhr) => showFileSaveDialog({blob, xhr, defaultFilename: 'HEAT_file.zip', addTimestamp: true})); + .then((response) => { + showFileSaveDialog({ + blob: response.blob, + headers: response.headers, + defaultFilename: 'HEAT_file.zip', + addTimestamp: true + }); + }); }, null/* do not download if data was not saved correctly*/); }, |