Adding filter bar
[aai/sparky-fe.git] / src / generic-components / filterBar / FilterBarUtils.js
1 /*
2  * ============LICENSE_START===================================================
3  * SPARKY (AAI UI service)
4  * ============================================================================
5  * Copyright © 2017 AT&T Intellectual Property.
6  * Copyright © 2017 Amdocs
7  * All rights reserved.
8  * ============================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=====================================================
21  *
22  * ECOMP and OpenECOMP are trademarks
23  * and service marks of AT&T Intellectual Property.
24  */
25 import isEmpty from 'lodash/isEmpty';
26 import moment from 'moment-timezone';
27 import {
28   POST,
29   POST_HEADER
30 } from 'app/networking/NetworkConstants.js';
31 import {
32   UNIFIED_FILTERS_URL,
33   DISCOVER_FILTERS_ERROR_MSG,
34   DATE_TIME_ZONE,
35   FILTER_ATTRIBUTE_TO,
36   FILTER_ATTRIBUTE_FROM,
37   FILTER_ATTRIBUTE_CODE,
38   FILTER_ATTRIBUTE_VALUES,
39   FILTER_ATTRIBUTE_CONTROLS,
40   FILTER_ATTRIBUTE_DEFAULT_VALUE,
41   FILTER_TYPE_ENUM,
42   filterBarActionTypes
43 } from 'generic-components/filterBar/FilterBarConstants.js';
44 import {
45   MESSAGE_LEVEL_WARNING
46 } from 'utils/GlobalConstants.js';
47 import {
48   getSetGlobalMessageEvent
49 } from 'app/globalInlineMessageBar/GlobalInlineMessageBarActions.js';
50
51 export function buildFilterValueMap(filterValueString) {
52   let filterValueObj = {};
53   let filters = filterValueString.split(',');
54
55   for (let filterIndex in filters) {
56     let filterStringParts = filters[filterIndex].split('=');
57
58     filterValueObj[filterStringParts[0]] = filterStringParts[1];
59   }
60
61   return filterValueObj;
62 }
63
64 export function buildFilterValueMapFromObj(filterValues) {
65   let filterValueObj = {};
66
67   for (let filterIndex in filterValues) {
68     filterValueObj[filterValues[filterIndex].filterId] = filterValues[filterIndex].filterValue;
69   }
70
71   return filterValueObj;
72 }
73
74 export function getFilterListQueryString(filterValueList) {
75   let filterQueryList = [];
76
77   for (let filter in filterValueList) {
78     if (filterValueList[filter]) {
79       filterQueryList.push(
80         {
81           'filterId': filter,
82           'filterValue': filterValueList[filter]
83         }
84       );
85     }
86   }
87
88   return filterQueryList;
89 }
90
91 function getFilterSearchURL() {
92   return UNIFIED_FILTERS_URL.replace('@@IP-ADDRESS@@', document.location.hostname);
93 }
94
95 function getFiltersQueryObject(viewName) {
96   return {
97     'viewName': viewName
98   };
99 }
100
101 function getFiltersEvent(actionType, filterList) {
102   return {
103     type: actionType,
104     data: filterList
105   };
106 }
107
108 export function getUnifiedFilters(viewName, actionType) {
109   return dispatch => {
110     return fetch(getFilterSearchURL(), {
111       credentials: 'same-origin',
112       method: POST,
113       headers: POST_HEADER,
114       body: JSON.stringify(getFiltersQueryObject(viewName))
115     }).then(
116       (response) => response.json()
117     ).then(
118       (responseJson) => {
119         dispatch(
120           getFiltersEvent(actionType, responseJson.filters)
121         );
122       }
123     ).catch(
124       () => {
125         dispatch(getSetGlobalMessageEvent(DISCOVER_FILTERS_ERROR_MSG, MESSAGE_LEVEL_WARNING));
126       }
127     );
128   };
129 }
130
131 function extractConvertedDateValues(dateValues) {
132   let convertedValues = {};
133   if (dateValues.from) {
134     let startMoment = moment(dateValues.from);
135     convertedValues.startDate = startMoment.toDate();
136     convertedValues.time_zone = startMoment.format(DATE_TIME_ZONE);
137   }
138
139   if (dateValues.to) {
140     let endMoment = moment(dateValues.to);
141     convertedValues.endDate = endMoment.toDate();
142     convertedValues.time_zone = endMoment.format(DATE_TIME_ZONE);
143   }
144
145   convertedValues.code = dateValues.code;
146
147   return convertedValues;
148 }
149
150 function convertFilterValues(filterValues) {
151   let convertedFilterValues = {};
152
153   for (let filterId in filterValues) {
154     if (filterValues.hasOwnProperty(filterId) &&
155       !isEmpty(filterValues[filterId]) && !isEmpty(filterValues[filterId].controls)) {
156       let controls = filterValues[filterId].controls;
157       let firstControlKey = Object.keys(controls)[0];
158       if (controls[firstControlKey][FILTER_ATTRIBUTE_VALUES][FILTER_ATTRIBUTE_FROM] ||
159         controls[firstControlKey][FILTER_ATTRIBUTE_VALUES][FILTER_ATTRIBUTE_TO]) {
160         // TODO should check against filter type (ex: dropdown or date)
161         // rather than assuming value attributes (ex: 'to' or 'from')
162         convertedFilterValues[filterId] =
163           extractConvertedDateValues(controls[firstControlKey][FILTER_ATTRIBUTE_VALUES]);
164       } else {
165         let codeValue = controls[firstControlKey][FILTER_ATTRIBUTE_VALUES][FILTER_ATTRIBUTE_CODE];
166         convertedFilterValues[filterId] = codeValue;
167       }
168     }
169   }
170
171   return convertedFilterValues;
172 }
173
174 function combineMissingFilters(filterValues, allFilters) {
175   let allFilterIds = Object.keys(allFilters);
176
177   for (let id in allFilterIds) {
178     if (!filterValues.hasOwnProperty(allFilterIds[id])) {
179       filterValues[allFilterIds[id]] = '';
180     }
181   }
182
183   return filterValues;
184 }
185
186 function getFilterSelectionEvent(selectedValuesMap, convertedValues) {
187   return {
188     type: filterBarActionTypes.NEW_SELECTIONS,
189     data: {
190       selectedValuesMap: convertedValues,
191       unifiedValues: selectedValuesMap
192     }
193   };
194 }
195
196 export function processFilterSelection(filterValues, allFilters) {
197   let convertedFilterValues = convertFilterValues(filterValues);
198   let combinedFilterValues = combineMissingFilters(convertedFilterValues, allFilters);
199
200   // dispatch NEW_SELECTION event type with converted values as the data
201   return getFilterSelectionEvent(filterValues, combinedFilterValues);
202 }
203
204 export function setNonConvertedFilterValues(nonConvertedValues) {
205   return {
206     type: filterBarActionTypes.SET_NON_CONVERTED_VALUES,
207     data: nonConvertedValues
208   };
209 }
210
211 function convertedFilterValuesEvent(nonConvertedValues, convertedValues) {
212   return {
213     type: filterBarActionTypes.SET_CONVERTED_VALUES,
214     data: {
215       nonConvertedValues: nonConvertedValues,
216       convertedValues: convertedValues
217     }
218   };
219 }
220
221 function mapValuesToOption(filterOptions, nonConvertedValue) {
222   let mappedValues = {};
223
224   // loop over options to find match for value
225   for (let i in filterOptions) {
226     if (filterOptions[i].code === nonConvertedValue) {
227       // found the matching
228       mappedValues = filterOptions[i];
229       break;
230     }
231   }
232
233   return mappedValues;
234 }
235
236 function mapValuesToDateOption(nonConvertedValue) {
237   let mappedValues = {};
238
239   if (nonConvertedValue.startDate) {
240     mappedValues.from = new Date(nonConvertedValue.startDate);
241   } else {
242     mappedValues.from = null;
243   }
244
245   if (nonConvertedValue.endDate) {
246     mappedValues.to = new Date(nonConvertedValue.endDate);
247   } else {
248     mappedValues.to = null;
249   }
250
251   mappedValues.code = nonConvertedValue.code;
252
253   return mappedValues;
254 }
255
256 function mapValuesToFilter(nonConvertedValues, allFilters, currentlySetFilterValues) {
257   let convertedValues = {};
258
259   for (let nonConvertedId in nonConvertedValues) {
260     if (nonConvertedValues[nonConvertedId] !== '') {
261       let matchingFilterObj = allFilters[nonConvertedId];
262       let filterControlId = Object.keys(matchingFilterObj.controls)[0];
263       let mappedValue = {};
264
265       if (matchingFilterObj[FILTER_ATTRIBUTE_CONTROLS][filterControlId].type === FILTER_TYPE_ENUM.DATE) {
266         mappedValue = mapValuesToDateOption(nonConvertedValues[nonConvertedId]);
267       } else {
268         mappedValue = mapValuesToOption(matchingFilterObj[FILTER_ATTRIBUTE_CONTROLS][filterControlId].options,
269           nonConvertedValues[nonConvertedId]);
270       }
271
272       let values = {};
273       values[FILTER_ATTRIBUTE_VALUES] = mappedValue;
274       let filterControlers = {};
275       filterControlers[filterControlId] = values;
276       let filter = {};
277       filter[FILTER_ATTRIBUTE_CONTROLS] = filterControlers;
278       convertedValues[nonConvertedId] = filter;
279     } else if (!isEmpty(currentlySetFilterValues[nonConvertedId])) {
280       // currently a value is set for this filter, need to ensure we map this filter
281       // to an empty value so that it is cleared/reset
282       let matchingFilterObj = allFilters[nonConvertedId];
283       let filterControlId = Object.keys(matchingFilterObj.controls)[0];
284       let mappedValue = {};
285       let values = {};
286       values[FILTER_ATTRIBUTE_VALUES] = mappedValue;
287       let filterControlers = {};
288       filterControlers[filterControlId] = values;
289       let filter = {};
290       filter[FILTER_ATTRIBUTE_CONTROLS] = filterControlers;
291       convertedValues[nonConvertedId] = filter;
292     }
293   }
294
295   return convertedValues;
296 }
297
298 export function convertNonConvertedValues(nonConvertedValues, allFilters, currentlySetFilterValues) {
299   let convertedValues = mapValuesToFilter(nonConvertedValues, allFilters, currentlySetFilterValues);
300   return convertedFilterValuesEvent(nonConvertedValues, convertedValues);
301 }
302
303 export function clearFilters() {
304   return {
305     type: filterBarActionTypes.CLEAR_FILTERS
306   };
307 }
308
309 function getSetUnifiedFilterValuesEvent(unifiedValues) {
310   return {
311     type: filterBarActionTypes.SET_UNIFIED_VALUES,
312     data: unifiedValues
313   };
314 }
315
316 function getFilterDefault(filters, filterId) {
317   let filterControlId = Object.keys(filters[filterId][FILTER_ATTRIBUTE_CONTROLS])[0];
318   let defaultValue = filters[filterId][FILTER_ATTRIBUTE_CONTROLS][filterControlId][FILTER_ATTRIBUTE_DEFAULT_VALUE];
319   if (!defaultValue) {
320     defaultValue = {};
321   }
322   return defaultValue;
323 }
324
325 export function setFilterSelectionsToDefaults(filters, filterValues) {
326   let defaultFilterMap = {};
327
328   for (let filterId in filters) {
329     let filterDefaultValue = getFilterDefault(filters, filterId);
330     if (!isEmpty(filterDefaultValue) || (filterValues && filterValues[filterId])) {
331       let filterControlId = Object.keys(filters[filterId][FILTER_ATTRIBUTE_CONTROLS])[0];
332       let controller = {};
333       controller.values = filterDefaultValue;
334       let controllers = {};
335       controllers[filterControlId] = controller;
336       let controls = {};
337       controls.controls = controllers;
338       defaultFilterMap[filterId] = controls;
339     }
340   }
341
342   if (isEmpty(defaultFilterMap)) {
343     // there are no default values, so need to ensure all filters get cleared,
344     // but just incase this 'clearing'
345     let combinedValues = combineMissingFilters(defaultFilterMap, filters);
346     return setNonConvertedFilterValues(combinedValues);
347   } else {
348     // jsut set the Unified Filter Value which will be sent down to the filter (filter
349     // will set itself to the default value and then send notification back up of the selection
350     return getSetUnifiedFilterValuesEvent(defaultFilterMap);
351   }
352 }