RIFT-15154: Config parameter map
[osm/UI.git] / skyquake / plugins / composer / src / src / stores / CatalogPackageManagerStore.js
1
2 /*
3 *
4 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 'use strict';
20
21 import _ from 'lodash'
22 import alt from '../alt'
23 import guid from '../libraries/guid'
24 import numeral from 'numeral'
25 import moment from 'moment'
26 import utils from '../libraries/utils'
27 import CatalogPackageManagerSource from '../sources/CatalogPackageManagerSource'
28 import CatalogPackageManagerActions from '../actions/CatalogPackageManagerActions'
29 import CatalogDataSource from '../sources/CatalogDataSource'
30
31 import imgDownload from '../../../node_modules/open-iconic/svg/cloud-download.svg'
32 import imgOnboard from '../../../node_modules/open-iconic/svg/cloud-upload.svg'
33 import imgUpdate from '../../../node_modules/open-iconic/svg/data-transfer-upload.svg'
34
35 const defaults = {
36 downloadPackage: {
37 id: '',
38 name: '',
39 icon: imgDownload,
40 catalogItems: [],
41 transactionId: '',
42 progress: 0,
43 message: 'Requesting catalog package export...',
44 pending: false,
45 success: false,
46 error: false,
47 url: '',
48 urlValidUntil: ''
49 },
50 checkStatusDelayInSeconds: 2,
51 downloadUrlTimeToLiveInMinutes: 5
52 };
53
54 const exception = function ignoreException() {};
55
56 const packagePropertyNames = Object.keys(defaults.downloadPackage);
57
58 function getCatalogPackageManagerServerOrigin() {
59 return utils.getSearchParams(window.location).upload_server + ':4567';
60 }
61
62 function delayStatusCheck(statusCheckFunction, catalogPackage) {
63 if (!catalogPackage.checkStatusTimeoutId) {
64 const delayCallback = function () {
65 delete catalogPackage.checkStatusTimeoutId;
66 statusCheckFunction(catalogPackage).catch(exception);
67 };
68 catalogPackage.checkStatusTimeoutId = _.delay(delayCallback, defaults.checkStatusDelayInSeconds * 1000);
69 }
70 }
71
72 class CatalogPackageManagerStore {
73
74 constructor() {
75
76 this.packages = [];
77
78 this.registerAsync(CatalogDataSource);
79 this.registerAsync(CatalogPackageManagerSource);
80 this.bindAction(CatalogPackageManagerActions.REMOVE_CATALOG_PACKAGE, this.removeCatalogPackage);
81 this.bindAction(CatalogPackageManagerActions.DOWNLOAD_CATALOG_PACKAGE, this.downloadCatalogPackage);
82 this.bindAction(CatalogPackageManagerActions.DOWNLOAD_CATALOG_PACKAGE_STATUS_UPDATED, this.onDownloadCatalogPackageStatusUpdated);
83 this.bindAction(CatalogPackageManagerActions.DOWNLOAD_CATALOG_PACKAGE_ERROR, this.onDownloadCatalogPackageError);
84 this.bindAction(CatalogPackageManagerActions.UPLOAD_CATALOG_PACKAGE, this.uploadCatalogPackage);
85 this.bindAction(CatalogPackageManagerActions.UPLOAD_CATALOG_PACKAGE_STATUS_UPDATED, this.onUploadCatalogPackageStatusUpdated);
86 this.bindAction(CatalogPackageManagerActions.UPLOAD_CATALOG_PACKAGE_ERROR, this.onUploadCatalogPackageError);
87
88 }
89
90 addPackage(catalogPackage) {
91 const packages = [catalogPackage].concat(this.packages);
92 this.setState({packages: packages});
93 }
94
95 updatePackage(catalogPackage) {
96 const packages = this.packages.map(d => {
97 if (d.id === catalogPackage.id) {
98 return Object.assign({}, d, catalogPackage);
99 }
100 return d;
101 });
102 this.setState({packages: packages});
103 }
104
105 removeCatalogPackage(catalogPackage) {
106 const packages = this.packages.filter(d => d.id !== catalogPackage.id);
107 this.setState({packages: packages});
108 }
109
110 uploadCatalogPackage(file) {
111 file.id = file.id || guid();
112 const catalogPackage = _.pick(file, packagePropertyNames);
113 catalogPackage.icon = file.riftAction === 'onboard' ? imgOnboard : imgUpdate;
114 catalogPackage.type = 'upload';
115 this.addPackage(catalogPackage);
116 // note DropZone.js handles the async upload so we don't have to invoke any async action creators
117 }
118
119 onUploadCatalogPackageStatusUpdated(response) {
120 const upload = updateStatusInfo(response);
121 this.updatePackage(upload);
122 // if pending with no transaction id - do nothing
123 // bc DropZone.js will notify upload progress
124 if (upload.pending && upload.transactionId) {
125 delayStatusCheck(this.getInstance().requestCatalogPackageUploadStatus, upload);
126 } else if (upload.success) {
127 this.getInstance().loadCatalogs();
128 }
129 }
130
131 onUploadCatalogPackageError(response) {
132 console.warn('onUploadCatalogPackageError', response);
133 const catalogPackage = updateStatusInfo(response);
134 this.updatePackage(catalogPackage);
135 }
136
137 downloadCatalogPackage(data) {
138 let catalogItems = data['selectedItems'] || [];
139 let schema = data['selectedFormat'] || 'mano';
140 let grammar = data['selectedGrammar'] || 'osm';
141 let format = "YAML";
142 if (catalogItems.length) {
143 const catalogPackage = Object.assign({}, defaults.downloadPackage, {id: guid()});
144 catalogPackage.name = catalogItems[0].name;
145 catalogPackage.type = 'download';
146 if (catalogItems.length > 1) {
147 catalogPackage.name += ' (' + catalogItems.length + ' items)';
148 }
149 catalogPackage.ids = catalogItems.map(d => d.id).sort().toString();
150 catalogPackage.catalogItems = catalogItems;
151 this.addPackage(catalogPackage);
152 this.getInstance().requestCatalogPackageDownload(catalogPackage, format, grammar, schema).catch(exception);
153 }
154 }
155
156 onDownloadCatalogPackageStatusUpdated(response) {
157 const download = updateStatusInfo(response);
158 this.updatePackage(download);
159 if (download.pending) {
160 delayStatusCheck(this.getInstance().requestCatalogPackageDownloadStatus, download);
161 }
162 }
163
164 onDownloadCatalogPackageError(response) {
165 console.warn('onDownloadCatalogPackageError', response);
166 const catalogPackage = updateStatusInfo(response);
167 this.updatePackage(catalogPackage);
168 }
169
170 }
171
172 function calculateUploadProgressMessage(size = 0, progress = 0, bytesSent = 0) {
173 const amount = parseFloat(progress) || 0;
174 const loaded = amount === 100 ? size : size * amount / 100;
175 let progressText;
176 if (amount === 100) {
177 progressText = numeral(loaded).format('0.0b') + ' loaded ';
178 } else if (typeof amount === 'number' && amount != 0) {
179 progressText = numeral(bytesSent).format('0.0b') + ' out of ' + numeral(size).format('0.0b');
180 } else {
181 progressText = progress;
182 }
183 return progressText;
184 }
185
186 function updateStatusInfo(response) {
187 // returns the catalogPackage object with the status fields updated based on the server response
188 const statusInfo = {
189 pending: false,
190 success: false,
191 error: false
192 };
193 const responseData = (response.data.output) ? response.data.output : response.data;
194 const catalogPackage = response.state;
195 switch(response.data.status) {
196 case 'upload-progress':
197 statusInfo.pending = true;
198 statusInfo.progress = parseFloat(responseData.progress) || 0;
199 statusInfo.message = calculateUploadProgressMessage(catalogPackage.size, responseData.progress, responseData.bytesSent);
200 break;
201 case 'upload-success':
202 statusInfo.pending = true;
203 statusInfo.progress = 100;
204 statusInfo.message = 'Upload completed.';
205 statusInfo.transactionId = responseData['transaction-id'] || catalogPackage.transactionId;
206 break;
207 case 'upload-error':
208 statusInfo.error = true;
209 statusInfo.message = responseData.message;
210 break;
211 case 'download-requested':
212 statusInfo.pending = true;
213 statusInfo.progress = 25;
214 statusInfo.transactionId = responseData['transaction-id'] || catalogPackage.transactionId;
215 break;
216 case 'pending':
217 statusInfo.pending = true;
218 statusInfo.progress = 50;
219 statusInfo.message = responseData.events[responseData.events.length - 1].text;
220 break;
221 case 'success':
222 statusInfo.success = true;
223 statusInfo.progress = 100;
224 statusInfo.message = responseData.events[responseData.events.length - 1].text;
225 if (catalogPackage.type === 'download') {
226 statusInfo.urlValidUntil = moment().add(defaults.downloadUrlTimeToLiveInMinutes, 'minutes').toISOString();
227 if (responseData.filename) {
228 statusInfo.url = getCatalogPackageManagerServerOrigin() + '/api/export/' + responseData.filename;
229 } else {
230 statusInfo.url = getCatalogPackageManagerServerOrigin() + '/api/export/' + catalogPackage.transactionId + '.tar.gz';
231 }
232 }
233 break;
234 case 'failure':
235 statusInfo.error = true;
236 statusInfo.message = responseData.errors[0].value;
237 break;
238 default:
239 throw new ReferenceError('a status of "request", "success", "failure", "pending", "upload-completed", "upload-error", "download-requested", "upload-progress", "upload-action" is required');
240 }
241 return Object.assign({}, catalogPackage, statusInfo);
242 }
243
244 export default alt.createStore(CatalogPackageManagerStore, 'CatalogPackageManagerStore');