my-test123
Version:
A planner front-end for Fabric8.
625 lines • 26.3 kB
JavaScript
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Injectable, Inject } from '@angular/core';
import { Headers } from '@angular/http';
import { ActivatedRoute } from '@angular/router';
import { WIT_API_URL, Spaces } from 'ngx-fabric8-wit';
import { HttpService } from './http-service';
var FilterService = /** @class */ (function () {
function FilterService(http, spaces, route, baseApiUrl) {
this.http = http;
this.spaces = spaces;
this.route = route;
this.baseApiUrl = baseApiUrl;
this.filters = [];
this.activeFilters = [];
this.filterChange = new Subject();
this.filterObservable = new Subject();
this.headers = new Headers({ 'Content-Type': 'application/json' });
this.and_notation = '$AND';
this.or_notation = '$OR';
this.equal_notation = '$EQ';
this.not_equal_notation = '$NEQ';
this.in_notation = '$IN';
this.not_in_notation = '$NIN';
this.sub_str_notation = '$SUBSTR';
this.special_keys = {
'null': null,
'true': true,
'false': false,
'': null
};
this.compare_notations = [
this.equal_notation,
this.not_equal_notation,
this.in_notation,
this.not_in_notation,
this.sub_str_notation
];
this.join_notations = [
this.and_notation,
this.or_notation,
];
this.filtertoWorkItemMap = {
'assignee': ['relationships', 'assignees', 'data', ['id']],
'creator': ['relationships', 'creator', 'data', 'id'],
'area': ['relationships', 'area', 'data', 'id'],
'workitemtype': ['relationships', 'baseType', 'data', 'id'],
'iteration': ['relationships', 'iteration', 'data', 'id'],
'state': ['attributes', 'system.state'],
};
}
FilterService.prototype.setFilterValues = function (id, value) {
var index = this.activeFilters.findIndex(function (f) { return f.id === id; });
if (index > -1 && value !== undefined) {
this.activeFilters[index].paramKey = 'filter[' + id + ']';
this.activeFilters[index].value = value;
}
else {
this.activeFilters.push({
id: id,
paramKey: 'filter[' + id + ']',
value: value
});
}
//Emit filter update event
this.filterObservable.next();
};
FilterService.prototype.getFilterValue = function (id) {
var filter = this.activeFilters.find(function (f) { return f.id === id; });
return filter ? filter.value : null;
};
FilterService.prototype.applyFilter = function () {
console.log('[FilterService::applyFilter] - Applying filters', this.activeFilters);
this.filterChange.next(this.activeFilters);
};
FilterService.prototype.getAppliedFilters = function (includeSidePanel) {
if (includeSidePanel === void 0) { includeSidePanel = false; }
if (includeSidePanel) {
var arr = this.getFiltersFromUrl();
arr = arr.concat(this.activeFilters);
//remove duplicates
arr = arr
.filter(function (thing, index, self) { return self.findIndex(function (t) { return t.id === thing.id; }) === index; });
return arr;
}
else {
return this.activeFilters;
}
};
FilterService.prototype.getFiltersFromUrl = function () {
// TODO
// This code needs to be looked at
// to support in query from the expression as well
var refCurrentFilter = [];
if (this.route.snapshot.queryParams['q']) {
var urlString = this.route.snapshot.queryParams['q']
.replace(' $AND ', ' ')
.replace(' $OR ', ' ')
.replace('(', '')
.replace(')', '');
var temp_arr = urlString.split(' ');
for (var i = 0; i < temp_arr.length; i++) {
var arr = temp_arr[i].split(':');
if (arr[1] !== undefined) {
refCurrentFilter.push({
id: arr[0],
paramKey: 'filter[' + arr[0] + ']',
value: arr[1]
});
}
}
;
}
//active filter will have the transient filters
//witgroup and space are permanent filters
return refCurrentFilter.filter(function (f) { return f.id === 'typegroup.name' || f.id === 'space' || f.id === 'iteration'; });
};
FilterService.prototype.clearFilters = function (keys) {
if (keys === void 0) { keys = []; }
if (keys.length) {
this.activeFilters = this.activeFilters.filter(function (f) { return keys.indexOf(f.id) > -1; });
}
else {
this.activeFilters = [];
}
};
/**
* getFilters - Fetches all the available filters
* @param apiUrl - The url to get list of all filters
* @return Observable of FilterModel[] - Array of filters
*/
FilterService.prototype.getFilters = function () {
var _this = this;
return this.spaces.current.switchMap(function (space) {
if (space) {
var apiUrl = space.links.filters;
return _this.http
.get(apiUrl)
.map(function (response) {
return response.json().data;
})
.catch(function (error) {
console.log('API returned error: ', error.message);
return Observable.throw('Error - [FilterService - getFilters]' + error.message);
});
}
else {
return Observable.of([]);
}
});
};
/**
* getFilters - Fetches all the available filters
* @param apiUrl - The url to get list of all filters
* @return Observable of FilterModel[] - Array of filters
*/
FilterService.prototype.getFilters2 = function (apiUrl) {
return this.http
.get(apiUrl)
.map(function (response) {
return response.json().data;
})
.catch(function (error) {
console.log('API returned error: ', error.message);
return Observable.throw('Error - [FilterService - getFilters]' + error.message);
});
};
FilterService.prototype.returnFilters = function () {
return this.filters;
};
/**
* Usage: to check if the workitem matches with current applied filter or not.
* TODO: Make this function better and smarter
* NOTE: To add a new filter you have to do nothing here, just update the filtertoWorkItemMap
* @param WorkItem - workItem
* @returns boolean
*/
FilterService.prototype.doesMatchCurrentFilter = function (workItem) {
var _this = this;
var refCurrentFilter = this.getFiltersFromUrl();
//concat both arrays
refCurrentFilter = refCurrentFilter.concat(this.activeFilters);
console.log('***refCurrentFilter = ', refCurrentFilter);
//remove duplicates
refCurrentFilter = refCurrentFilter
.filter(function (thing, index, self) { return self.findIndex(function (t) { return t.id === thing.id; }) === index; });
return refCurrentFilter.every(function (filter) {
if (filter.id && Object.keys(_this.filtertoWorkItemMap).indexOf(filter.id) > -1) {
var currentAttr_1 = workItem;
return _this.filtertoWorkItemMap[filter.id].every(function (attr, map_index) {
console.log('****** attr = ', attr);
console.log('****** map_index = ', map_index);
console.log('****** filter value = ', filter.value);
if (Array.isArray(attr)) {
if (Array.isArray(currentAttr_1)) {
var innerAttr = currentAttr_1;
return currentAttr_1.some(function (item) {
return item[attr[0]] == filter.value;
});
}
else {
return false;
}
}
else if (currentAttr_1[attr]) {
currentAttr_1 = currentAttr_1[attr];
if (map_index === _this.filtertoWorkItemMap[filter.id].length - 1 && currentAttr_1 != filter.value) {
return false;
}
else {
return true;
}
}
else {
return false;
}
});
}
return true;
});
};
/**
* Take the existing query and simply AND it with provided options
* @param existingQuery
* @param options
*/
FilterService.prototype.constructQueryURL = function (existingQuery, options) {
var _this = this;
var processedObject = '';
// If onptions has any length enclose processedObject with ()
if (Object.keys(options).length > 1) {
processedObject = '(' + Object.keys(options).map(function (key) {
return typeof (options[key]) !== 'string' ? key + ':' + options[key] :
options[key].split(',').map(function (val) {
return key + ':' + val;
}).join(' ' + _this.and_notation + ' ');
}).join(' ' + this.and_notation + ' ') + ')';
}
else if (Object.keys(options).length === 1) {
processedObject = Object.keys(options).map(function (key) {
return typeof (options[key]) !== 'string' ? key + ':' + options[key] :
options[key].split(',').map(function (val) {
return key + ':' + val;
}).join(' ' + _this.and_notation + ' ');
}).join(' ' + this.and_notation + ' ');
}
else {
return decodeURIComponent(existingQuery);
}
// Check if the existing query is empty
// Then return processedObject
if (existingQuery === '') {
return processedObject;
}
else {
// Decode existing URL
var decodedURL = decodeURIComponent(existingQuery);
// Check if there is any composite query in existing one
if (decodedURL.indexOf(this.and_notation) > -1 || decodedURL.indexOf(this.or_notation) > -1) {
// Check if existing query is a group i.e. enclosed
if (decodedURL[0] != '(' || decodedURL[decodedURL.length - 1] != ')') {
// enclose it with ()
decodedURL = '(' + decodedURL + ')';
}
}
// Add the query from option with AND operation
return '(' + decodedURL + ' ' + this.and_notation + ' ' + processedObject + ')';
}
};
/**
*
* @param key The value is the object key like 'workitem_type', 'iteration' etc
* @param compare The values are
* FilterService::equal_notation',
* FilterService::not_equal_notation',
* FilterService::not_equal_notation',
* FilterService::in_notation',
* FilterService::not_in_notation'
* @param value string or array of string of values (in case of IN or NOT IN)
*/
FilterService.prototype.queryBuilder = function (key, compare, value) {
if (this.compare_notations.indexOf(compare.trim()) == -1) {
throw new Error('Not a valid compare notation');
}
var op = {};
op[key.trim()] = {};
if (Array.isArray(value)) {
op[key.trim()][compare.trim()] = value.map(function (v) { return v.trim(); });
}
else {
op[key.trim()][compare.trim()] = value.trim();
}
return op;
};
/**
*
* @param existingQueryObject
* @param join The values are
* FilterService::and_notation,
* FilterService::or_notation
* @param newQueryObject
*/
FilterService.prototype.queryJoiner = function (existingQueryObject, join, newQueryObject) {
if (this.join_notations.indexOf(join.trim()) == -1) {
throw new Error('Not a valid compare notation');
}
// existingQueryObject is empty
if (!Object.keys(existingQueryObject).length) {
if (Object.keys(newQueryObject).length) {
if (this.join_notations.indexOf(Object.keys(newQueryObject)[0]) > -1) {
return newQueryObject;
}
else {
var op = {};
op[this.or_notation] = [newQueryObject];
return op;
}
}
else {
return {};
}
}
else {
// If existingObject is not empty
var existingJoiner = Object.keys(existingQueryObject)[0];
// If existing joiner is not valid
if (this.join_notations.indexOf(existingJoiner) == -1) {
throw new Error('Existing query object is invalid without a joiner in root');
}
// If new object is empty then return existingQueryObject
if (!Object.keys(newQueryObject).length) {
return existingQueryObject;
}
var newJoiner = Object.keys(newQueryObject)[0];
// If new object has join_notation as root
if (this.join_notations.indexOf(newJoiner) > -1) {
// If new joiner existing joiner and given joiner is same
// put all of them under one joiner
if (join === newJoiner && join === existingJoiner) {
var op = {};
op[join] = existingQueryObject[join].concat(newQueryObject[join]);
return op;
}
else if (existingQueryObject[existingJoiner].length === 1 &&
newQueryObject[newJoiner].length === 1) {
var op = {};
op[join] = existingQueryObject[existingJoiner].concat(newQueryObject[newJoiner]);
return op;
}
else if (existingQueryObject[existingJoiner].length === 1) {
var op = {};
if (newJoiner === join) {
op[join] = existingQueryObject[existingJoiner].concat(newQueryObject[newJoiner]);
}
else {
op[join] = existingQueryObject[existingJoiner].concat([
newQueryObject
]);
}
return op;
}
else if (newQueryObject[newJoiner].length === 1) {
var op = {};
if (existingJoiner === join) {
op[join] = existingQueryObject[existingJoiner].concat(newQueryObject[newJoiner]);
}
else {
op[join] = [
existingQueryObject
].concat(newQueryObject[newJoiner]);
}
return op;
}
else {
var op = {};
op[join] = [
existingQueryObject,
newQueryObject
];
return op;
}
}
else {
if (join === existingJoiner) {
existingQueryObject[join].push(newQueryObject);
return existingQueryObject;
}
else {
var op = {};
// If existingQueryObject has only one item in the array
if (existingQueryObject[existingJoiner].length === 1) {
op[join] = existingQueryObject[existingJoiner].concat([
newQueryObject
]);
}
else {
op[join] = [
existingQueryObject,
newQueryObject
];
}
return op;
}
}
}
};
/**
* Query string to JSON conversion
*/
FilterService.prototype.queryToJson = function (query, first_level) {
var _this = this;
if (first_level === void 0) { first_level = true; }
var temp = [], p_count = 0, p_start = -1, new_str = '', output = {};
for (var i = 0; i < query.length; i++) {
if (query[i] === '(') {
if (p_start < 0)
p_start = i;
p_count += 1;
}
if (p_start === -1) {
new_str += query[i];
}
if (query[i] === ')') {
p_count -= 1;
}
if (p_start >= 0 && p_count === 0) {
temp.push(query.substring(p_start + 1, i));
new_str += '__temp__';
p_start = -1;
}
}
temp.reverse();
var arr = new_str.split(this.or_notation);
if (arr.length > 1) {
output[this.or_notation] = arr.map(function (item) {
item = item.trim();
if (item == '__temp__') {
item = temp.pop();
}
while (item.indexOf('__temp__') > -1) {
item = item.replace('__temp__', temp.pop());
}
return _this.queryToJson(item, false);
});
}
else {
arr = new_str.split(this.and_notation);
if (arr.length > 1) {
output[this.and_notation] = arr.map(function (item) {
if (item.trim() == '__temp__') {
item = temp.pop();
}
return _this.queryToJson(item, false);
});
}
else {
var dObj = {};
while (new_str.indexOf('__temp__') > -1) {
new_str = new_str.replace('__temp__', temp.pop());
}
if (new_str.indexOf(this.and_notation) > -1 || new_str.indexOf(this.or_notation) > -1) {
return this.queryToJson(new_str, false);
}
var keyIndex = -1;
var splitter = '';
for (var i = 0; i < new_str.length; i++) {
if (new_str[i] === ':' || new_str[i] === '!') {
splitter = new_str[i];
keyIndex = i;
break;
}
}
var key = new_str.substring(0, keyIndex).trim();
var value = new_str.substring(keyIndex + 1).trim();
var val_arr_1 = value.split(',').map(function (i) { return i.trim(); });
dObj[key] = {};
if (splitter === '!') {
if (val_arr_1.length > 1) {
dObj[key][this.not_in_notation] = val_arr_1;
}
else {
if (Object.keys(this.special_keys).findIndex(function (k) { return k === val_arr_1[0]; }) > -1) {
dObj[key][this.not_equal_notation] = this.special_keys[val_arr_1[0]];
}
else if (key === 'title') {
dObj[key][this.sub_str_notation] = val_arr_1[0];
}
else {
dObj[key][this.not_equal_notation] = val_arr_1[0];
}
}
}
else if (splitter === ':') {
if (val_arr_1.length > 1) {
dObj[key][this.in_notation] = val_arr_1;
}
else {
if (Object.keys(this.special_keys).findIndex(function (k) { return k === val_arr_1[0]; }) > -1) {
dObj[key][this.equal_notation] = this.special_keys[val_arr_1[0]];
}
else if (key === 'title') {
dObj[key][this.sub_str_notation] = val_arr_1[0];
}
else {
dObj[key][this.equal_notation] = val_arr_1[0];
}
}
}
if (first_level) {
output[this.or_notation] = [dObj];
}
else {
return dObj;
}
}
}
return output;
};
FilterService.prototype.jsonToQuery = function (obj) {
var _this = this;
var key = Object.keys(obj)[0]; // key will be AND or OR
var value = obj[key];
return '(' + value.map(function (item) {
if (Object.keys(item)[0] == _this.and_notation || Object.keys(item)[0] == _this.or_notation) {
return _this.jsonToQuery(item);
}
else {
var data_key = Object.keys(item)[0];
var data = item[data_key];
var conditional_operator = Object.keys(data)[0];
var splitter = '';
switch (conditional_operator) {
case _this.equal_notation:
splitter = ':';
return data_key + splitter + data[conditional_operator];
case _this.not_equal_notation:
splitter = '!';
return data_key + splitter + data[conditional_operator];
case _this.in_notation:
splitter = ':';
return data_key + splitter + data[conditional_operator].join();
case _this.not_in_notation:
splitter = '!';
return data_key + splitter + data[conditional_operator].join();
case _this.sub_str_notation:
splitter = ':';
return data_key + splitter + data[conditional_operator];
}
}
})
.join(' ' + key + ' ') + ')';
};
/**
* This decodes a key query term value from a given query string. It is used to
* shortcut the parsing of the query string to get context info from it. Currently,
* it is used when getting the context info from an existing query to give context
* to a following UX flow. This only supports a very narrow usecase currently, but
* may be extended later.
*
* @param queryString search/filter query string.
* @param key key of the term for which we look for the value.
*/
FilterService.prototype.getConditionFromQuery = function (queryString, key) {
if (queryString) {
var decodedQuery = this.queryToJson(queryString);
// we ignore non-AND queries for now, might want to extend that later.
if (!decodedQuery['$AND']) {
console.log('The current query is not supported by getConditionFromQuery() (non-AND query): ' + queryString);
return undefined;
}
else {
var terms = decodedQuery['$AND'];
if (terms || !Array.isArray(terms)) {
for (var i = 0; i < terms.length; i++) {
var thisTerm = terms[i];
if (thisTerm && thisTerm[key]) {
// format of value: {$EQ: "value"}, if not found, value remains undefined
return thisTerm[key]['$EQ'];
}
}
console.log('Condition key not found in query: ' + key + ', query= ' + queryString);
return undefined;
}
else {
console.log('The current query is not supported by getConditionFromQuery() (bad format): ' + queryString);
// use standard non-context create dialog
return undefined;
}
}
}
};
// Temporary function to deal with single level $AND operator
FilterService.prototype.queryToFlat = function (query) {
return query.replace(/^\((.+)\)$/, "$1")
.split(this.and_notation).map(function (item, index) {
return {
field: item.split(':')[0].trim(),
index: index,
value: item.split(':')[1].trim()
};
});
};
FilterService.prototype.flatToQuery = function (arr) {
var _this = this;
var query = {};
arr.forEach(function (item) {
var newQuery = _this.queryBuilder(item.field, _this.equal_notation, item.value);
query = _this.queryJoiner(query, _this.and_notation, newQuery);
});
return query;
};
FilterService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
FilterService.ctorParameters = function () { return [
{ type: HttpService, },
{ type: Spaces, },
{ type: ActivatedRoute, },
{ type: undefined, decorators: [{ type: Inject, args: [WIT_API_URL,] },] },
]; };
return FilterService;
}());
export { FilterService };
//# sourceMappingURL=filter.service.js.map