mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 17:37:37 -02:30
move data transformation logic into a service so it can be reused
This commit is contained in:
@@ -1,333 +1,507 @@
|
|||||||
export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSearchModel', 'SmartSearchService',
|
function searchWithoutKey (term, singleSearchParam = null) {
|
||||||
function($q, Rest, ProcessErrors, $rootScope, Wait, DjangoSearchModel, SmartSearchService) {
|
if (singleSearchParam) {
|
||||||
return {
|
return { [singleSearchParam]: `search=${encodeURIComponent(term)}` };
|
||||||
// kick off building a model for a specific endpoint
|
}
|
||||||
// this is usually a list's basePath
|
return { search: encodeURIComponent(term) };
|
||||||
// unified_jobs is the exception, where we need to fetch many subclass OPTIONS and summary_fields
|
}
|
||||||
initFieldset(path, name) {
|
|
||||||
let defer = $q.defer();
|
|
||||||
defer.resolve(this.getCommonModelOptions(path, name));
|
|
||||||
return defer.promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
getCommonModelOptions(path, name) {
|
function QuerysetService ($q, Rest, ProcessErrors, $rootScope, Wait, DjangoSearchModel, SmartSearchService) {
|
||||||
let resolve, base,
|
return {
|
||||||
defer = $q.defer();
|
// kick off building a model for a specific endpoint
|
||||||
|
// this is usually a list's basePath
|
||||||
|
// unified_jobs is the exception, where we need to fetch many subclass OPTIONS and summary_fields
|
||||||
|
initFieldset(path, name) {
|
||||||
|
let defer = $q.defer();
|
||||||
|
defer.resolve(this.getCommonModelOptions(path, name));
|
||||||
|
return defer.promise;
|
||||||
|
},
|
||||||
|
getCommonModelOptions(path, name) {
|
||||||
|
let resolve, base,
|
||||||
|
defer = $q.defer();
|
||||||
|
|
||||||
this.url = path;
|
this.url = path;
|
||||||
resolve = this.options(path)
|
resolve = this.options(path)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
base = res.data.actions.GET;
|
base = res.data.actions.GET;
|
||||||
let relatedSearchFields = res.data.related_search_fields;
|
let relatedSearchFields = res.data.related_search_fields;
|
||||||
defer.resolve({
|
defer.resolve({
|
||||||
models: {
|
models: {
|
||||||
[name]: new DjangoSearchModel(name, base, relatedSearchFields)
|
[name]: new DjangoSearchModel(name, base, relatedSearchFields)
|
||||||
},
|
},
|
||||||
options: res
|
options: res
|
||||||
});
|
|
||||||
});
|
});
|
||||||
return defer.promise;
|
});
|
||||||
},
|
return defer.promise;
|
||||||
|
},
|
||||||
|
replaceDefaultFlags (value) {
|
||||||
|
value = value.toString().replace(/__icontains_DEFAULT/g, "__icontains");
|
||||||
|
value = value.toString().replace(/__search_DEFAULT/g, "__search");
|
||||||
|
|
||||||
replaceDefaultFlags (value) {
|
return value;
|
||||||
value = value.toString().replace(/__icontains_DEFAULT/g, "__icontains");
|
},
|
||||||
value = value.toString().replace(/__search_DEFAULT/g, "__search");
|
replaceEncodedTokens(value) {
|
||||||
|
return decodeURIComponent(value).replace(/"|'/g, "");
|
||||||
|
},
|
||||||
|
encodeTerms (values, key) {
|
||||||
|
key = this.replaceDefaultFlags(key);
|
||||||
|
|
||||||
return value;
|
if (!Array.isArray(values)) {
|
||||||
},
|
values = [values];
|
||||||
|
}
|
||||||
|
|
||||||
replaceEncodedTokens(value) {
|
return values
|
||||||
return decodeURIComponent(value).replace(/"|'/g, "");
|
.map(value => {
|
||||||
},
|
value = this.replaceDefaultFlags(value);
|
||||||
|
value = this.replaceEncodedTokens(value);
|
||||||
|
return [key, value]
|
||||||
|
})
|
||||||
|
|
||||||
encodeTerms (values, key) {
|
},
|
||||||
key = this.replaceDefaultFlags(key);
|
// encodes ui-router params from {operand__key__comparator: value} pairs to API-consumable URL
|
||||||
|
encodeQueryset(params) {
|
||||||
|
if (typeof params !== 'object') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
if (!Array.isArray(values)) {
|
return _.reduce(params, (result, value, key) => {
|
||||||
values = [values];
|
if (result !== '?') {
|
||||||
|
result += '&';
|
||||||
}
|
}
|
||||||
|
|
||||||
return values
|
const encodedTermString = this.encodeTerms(value, key)
|
||||||
.map(value => {
|
.map(([key, value]) => `${key}=${value}`)
|
||||||
value = this.replaceDefaultFlags(value);
|
.join('&');
|
||||||
value = this.replaceEncodedTokens(value);
|
|
||||||
return [key, value]
|
|
||||||
})
|
|
||||||
|
|
||||||
},
|
return result += encodedTermString;
|
||||||
// encodes ui-router params from {operand__key__comparator: value} pairs to API-consumable URL
|
}, '?');
|
||||||
encodeQueryset(params) {
|
},
|
||||||
if (typeof params !== 'object') {
|
// like encodeQueryset, but return an actual unstringified API-consumable http param object
|
||||||
return '';
|
encodeQuerysetObject(params) {
|
||||||
|
return _.reduce(params, (obj, value, key) => {
|
||||||
|
const encodedTerms = this.encodeTerms(value, key);
|
||||||
|
|
||||||
|
for (let encodedIndex in encodedTerms) {
|
||||||
|
const [encodedKey, encodedValue] = encodedTerms[encodedIndex];
|
||||||
|
obj[encodedKey] = obj[encodedKey] || [];
|
||||||
|
obj[encodedKey].push(encodedValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.reduce(params, (result, value, key) => {
|
return obj;
|
||||||
if (result !== '?') {
|
}, {});
|
||||||
result += '&';
|
},
|
||||||
}
|
// encodes a ui smart-search param to a django-friendly param
|
||||||
|
// operand:key:comparator:value => {operand__key__comparator: value}
|
||||||
const encodedTermString = this.encodeTerms(value, key)
|
encodeParam({ term, relatedSearchTerm, searchTerm, singleSearchParam }){
|
||||||
.map(([key, value]) => `${key}=${value}`)
|
// Assumption here is that we have a key and a value so the length
|
||||||
.join('&');
|
// of the paramParts array will be 2. [0] is the key and [1] the value
|
||||||
|
let paramParts = SmartSearchService.splitTermIntoParts(term);
|
||||||
return result += encodedTermString;
|
let keySplit = paramParts[0].split('.');
|
||||||
}, '?');
|
let exclude = false;
|
||||||
},
|
let lessThanGreaterThan = paramParts[1].match(/^(>|<).*$/) ? true : false;
|
||||||
// like encodeQueryset, but return an actual unstringified API-consumable http param object
|
if(keySplit[0].match(/^-/g)) {
|
||||||
encodeQuerysetObject(params) {
|
exclude = true;
|
||||||
return _.reduce(params, (obj, value, key) => {
|
keySplit[0] = keySplit[0].replace(/^-/, '');
|
||||||
const encodedTerms = this.encodeTerms(value, key);
|
}
|
||||||
|
let paramString = exclude ? "not__" : "";
|
||||||
for (let encodedIndex in encodedTerms) {
|
let valueString = paramParts[1];
|
||||||
const [encodedKey, encodedValue] = encodedTerms[encodedIndex];
|
if(keySplit.length === 1) {
|
||||||
obj[encodedKey] = obj[encodedKey] || [];
|
if(searchTerm && !lessThanGreaterThan) {
|
||||||
obj[encodedKey].push(encodedValue)
|
if(singleSearchParam) {
|
||||||
}
|
paramString += keySplit[0] + '__icontains';
|
||||||
|
|
||||||
return obj;
|
|
||||||
}, {});
|
|
||||||
},
|
|
||||||
// encodes a ui smart-search param to a django-friendly param
|
|
||||||
// operand:key:comparator:value => {operand__key__comparator: value}
|
|
||||||
encodeParam({ term, relatedSearchTerm, searchTerm, singleSearchParam }){
|
|
||||||
// Assumption here is that we have a key and a value so the length
|
|
||||||
// of the paramParts array will be 2. [0] is the key and [1] the value
|
|
||||||
let paramParts = SmartSearchService.splitTermIntoParts(term);
|
|
||||||
let keySplit = paramParts[0].split('.');
|
|
||||||
let exclude = false;
|
|
||||||
let lessThanGreaterThan = paramParts[1].match(/^(>|<).*$/) ? true : false;
|
|
||||||
if(keySplit[0].match(/^-/g)) {
|
|
||||||
exclude = true;
|
|
||||||
keySplit[0] = keySplit[0].replace(/^-/, '');
|
|
||||||
}
|
|
||||||
let paramString = exclude ? "not__" : "";
|
|
||||||
let valueString = paramParts[1];
|
|
||||||
if(keySplit.length === 1) {
|
|
||||||
if(searchTerm && !lessThanGreaterThan) {
|
|
||||||
if(singleSearchParam) {
|
|
||||||
paramString += keySplit[0] + '__icontains';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
paramString += keySplit[0] + '__icontains_DEFAULT';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(relatedSearchTerm) {
|
|
||||||
if(singleSearchParam) {
|
|
||||||
paramString += keySplit[0];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
paramString += keySplit[0] + '__search_DEFAULT';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
paramString += keySplit[0] + '__icontains_DEFAULT';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(relatedSearchTerm) {
|
||||||
|
if(singleSearchParam) {
|
||||||
paramString += keySplit[0];
|
paramString += keySplit[0];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
paramString += keySplit.join('__');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lessThanGreaterThan) {
|
|
||||||
if(paramParts[1].match(/^>=.*$/)) {
|
|
||||||
paramString += '__gte';
|
|
||||||
valueString = valueString.replace(/^(>=)/,"");
|
|
||||||
}
|
|
||||||
else if(paramParts[1].match(/^<=.*$/)) {
|
|
||||||
paramString += '__lte';
|
|
||||||
valueString = valueString.replace(/^(<=)/,"");
|
|
||||||
}
|
|
||||||
else if(paramParts[1].match(/^<.*$/)) {
|
|
||||||
paramString += '__lt';
|
|
||||||
valueString = valueString.replace(/^(<)/,"");
|
|
||||||
}
|
|
||||||
else if(paramParts[1].match(/^>.*$/)) {
|
|
||||||
paramString += '__gt';
|
|
||||||
valueString = valueString.replace(/^(>)/,"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(singleSearchParam) {
|
|
||||||
return {[singleSearchParam]: paramString + "=" + valueString};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return {[paramString] : encodeURIComponent(valueString)};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// decodes a django queryset param into a ui smart-search tag or set of tags
|
|
||||||
decodeParam(value, key){
|
|
||||||
|
|
||||||
let decodeParamString = function(searchString) {
|
|
||||||
if(key === 'search') {
|
|
||||||
// Don't include 'search:' in the search tag
|
|
||||||
return decodeURIComponent(`${searchString}`);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
key = key.toString().replace(/__icontains_DEFAULT/g, "");
|
paramString += keySplit[0] + '__search_DEFAULT';
|
||||||
key = key.toString().replace(/__search_DEFAULT/g, "");
|
|
||||||
let split = key.split('__');
|
|
||||||
let decodedParam = searchString;
|
|
||||||
let exclude = false;
|
|
||||||
if(key.startsWith('not__')) {
|
|
||||||
exclude = true;
|
|
||||||
split = split.splice(1, split.length);
|
|
||||||
}
|
|
||||||
if(key.endsWith('__gt')) {
|
|
||||||
decodedParam = '>' + decodedParam;
|
|
||||||
split = split.splice(0, split.length-1);
|
|
||||||
}
|
|
||||||
else if(key.endsWith('__lt')) {
|
|
||||||
decodedParam = '<' + decodedParam;
|
|
||||||
split = split.splice(0, split.length-1);
|
|
||||||
}
|
|
||||||
else if(key.endsWith('__gte')) {
|
|
||||||
decodedParam = '>=' + decodedParam;
|
|
||||||
split = split.splice(0, split.length-1);
|
|
||||||
}
|
|
||||||
else if(key.endsWith('__lte')) {
|
|
||||||
decodedParam = '<=' + decodedParam;
|
|
||||||
split = split.splice(0, split.length-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let uriDecodedParam = decodeURIComponent(decodedParam);
|
|
||||||
|
|
||||||
return exclude ? `-${split.join('.')}:${uriDecodedParam}` : `${split.join('.')}:${uriDecodedParam}`;
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
else {
|
||||||
|
paramString += keySplit[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
paramString += keySplit.join('__');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lessThanGreaterThan) {
|
||||||
|
if(paramParts[1].match(/^>=.*$/)) {
|
||||||
|
paramString += '__gte';
|
||||||
|
valueString = valueString.replace(/^(>=)/,"");
|
||||||
|
}
|
||||||
|
else if(paramParts[1].match(/^<=.*$/)) {
|
||||||
|
paramString += '__lte';
|
||||||
|
valueString = valueString.replace(/^(<=)/,"");
|
||||||
|
}
|
||||||
|
else if(paramParts[1].match(/^<.*$/)) {
|
||||||
|
paramString += '__lt';
|
||||||
|
valueString = valueString.replace(/^(<)/,"");
|
||||||
|
}
|
||||||
|
else if(paramParts[1].match(/^>.*$/)) {
|
||||||
|
paramString += '__gt';
|
||||||
|
valueString = valueString.replace(/^(>)/,"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(singleSearchParam) {
|
||||||
|
return {[singleSearchParam]: paramString + "=" + valueString};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {[paramString] : encodeURIComponent(valueString)};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// decodes a django queryset param into a ui smart-search tag or set of tags
|
||||||
|
decodeParam(value, key){
|
||||||
|
|
||||||
|
let decodeParamString = function(searchString) {
|
||||||
|
if(key === 'search') {
|
||||||
|
// Don't include 'search:' in the search tag
|
||||||
|
return decodeURIComponent(`${searchString}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
key = key.toString().replace(/__icontains_DEFAULT/g, "");
|
||||||
|
key = key.toString().replace(/__search_DEFAULT/g, "");
|
||||||
|
let split = key.split('__');
|
||||||
|
let decodedParam = searchString;
|
||||||
|
let exclude = false;
|
||||||
|
if(key.startsWith('not__')) {
|
||||||
|
exclude = true;
|
||||||
|
split = split.splice(1, split.length);
|
||||||
|
}
|
||||||
|
if(key.endsWith('__gt')) {
|
||||||
|
decodedParam = '>' + decodedParam;
|
||||||
|
split = split.splice(0, split.length-1);
|
||||||
|
}
|
||||||
|
else if(key.endsWith('__lt')) {
|
||||||
|
decodedParam = '<' + decodedParam;
|
||||||
|
split = split.splice(0, split.length-1);
|
||||||
|
}
|
||||||
|
else if(key.endsWith('__gte')) {
|
||||||
|
decodedParam = '>=' + decodedParam;
|
||||||
|
split = split.splice(0, split.length-1);
|
||||||
|
}
|
||||||
|
else if(key.endsWith('__lte')) {
|
||||||
|
decodedParam = '<=' + decodedParam;
|
||||||
|
split = split.splice(0, split.length-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let uriDecodedParam = decodeURIComponent(decodedParam);
|
||||||
|
|
||||||
|
return exclude ? `-${split.join('.')}:${uriDecodedParam}` : `${split.join('.')}:${uriDecodedParam}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(value)){
|
||||||
|
value = _.uniq(_.flattenDeep(value));
|
||||||
|
return _.map(value, (item) => {
|
||||||
|
return decodeParamString(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return decodeParamString(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// encodes a django queryset for ui-router's URLMatcherFactory
|
||||||
|
// {operand__key__comparator: value, } => 'operand:key:comparator:value;...'
|
||||||
|
// value.isArray expands to:
|
||||||
|
// {operand__key__comparator: [value1, value2], } => 'operand:key:comparator:value1;operand:key:comparator:value1...'
|
||||||
|
encodeArr(params) {
|
||||||
|
let url;
|
||||||
|
url = _.reduce(params, (result, value, key) => {
|
||||||
|
return result.concat(encodeUrlString(value, key));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return url.join(';');
|
||||||
|
|
||||||
|
// {key:'value'} => 'key:value'
|
||||||
|
// {key: [value1, value2, ...]} => ['key:value1', 'key:value2']
|
||||||
|
function encodeUrlString(value, key){
|
||||||
if (Array.isArray(value)){
|
if (Array.isArray(value)){
|
||||||
value = _.uniq(_.flattenDeep(value));
|
value = _.uniq(_.flattenDeep(value));
|
||||||
return _.map(value, (item) => {
|
return _.map(value, (item) => {
|
||||||
return decodeParamString(item);
|
return `${key}:${item}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return decodeParamString(value);
|
return `${key}:${value}`;
|
||||||
}
|
|
||||||
},
|
|
||||||
convertToSearchTags(obj) {
|
|
||||||
const tags = [];
|
|
||||||
for (let key in obj) {
|
|
||||||
const value = obj[key];
|
|
||||||
tags.push(this.decodeParam(value, key));
|
|
||||||
}
|
|
||||||
return tags;
|
|
||||||
},
|
|
||||||
// encodes a django queryset for ui-router's URLMatcherFactory
|
|
||||||
// {operand__key__comparator: value, } => 'operand:key:comparator:value;...'
|
|
||||||
// value.isArray expands to:
|
|
||||||
// {operand__key__comparator: [value1, value2], } => 'operand:key:comparator:value1;operand:key:comparator:value1...'
|
|
||||||
encodeArr(params) {
|
|
||||||
let url;
|
|
||||||
url = _.reduce(params, (result, value, key) => {
|
|
||||||
return result.concat(encodeUrlString(value, key));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return url.join(';');
|
|
||||||
|
|
||||||
// {key:'value'} => 'key:value'
|
|
||||||
// {key: [value1, value2, ...]} => ['key:value1', 'key:value2']
|
|
||||||
function encodeUrlString(value, key){
|
|
||||||
if (Array.isArray(value)){
|
|
||||||
value = _.uniq(_.flattenDeep(value));
|
|
||||||
return _.map(value, (item) => {
|
|
||||||
return `${key}:${item}`;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return `${key}:${value}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// decodes a django queryset for ui-router's URLMatcherFactory
|
|
||||||
// 'operand:key:comparator:value,...' => {operand__key__comparator: value, }
|
|
||||||
decodeArr(arr) {
|
|
||||||
let params = {};
|
|
||||||
_.forEach(arr.split(';'), (item) => {
|
|
||||||
let key = item.split(':')[0],
|
|
||||||
value = item.split(':')[1];
|
|
||||||
if(!params[key]){
|
|
||||||
params[key] = value;
|
|
||||||
}
|
|
||||||
else if (Array.isArray(params[key])){
|
|
||||||
params[key] = _.uniq(_.flattenDeep(params[key]));
|
|
||||||
params[key].push(value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
params[key] = [params[key], value];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return params;
|
|
||||||
},
|
|
||||||
// REST utilities
|
|
||||||
options(endpoint) {
|
|
||||||
Rest.setUrl(endpoint);
|
|
||||||
return Rest.options(endpoint);
|
|
||||||
},
|
|
||||||
search(endpoint, params) {
|
|
||||||
Wait('start');
|
|
||||||
this.url = `${endpoint}${this.encodeQueryset(params)}`;
|
|
||||||
Rest.setUrl(this.url);
|
|
||||||
|
|
||||||
return Rest.get()
|
|
||||||
.then(function(response) {
|
|
||||||
Wait('stop');
|
|
||||||
|
|
||||||
if (response
|
|
||||||
.headers('X-UI-Max-Events') !== null) {
|
|
||||||
response.data.maxEvents = response.
|
|
||||||
headers('X-UI-Max-Events');
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
})
|
|
||||||
.catch(function(response) {
|
|
||||||
Wait('stop');
|
|
||||||
|
|
||||||
this.error(response.data, response.status);
|
|
||||||
|
|
||||||
throw response;
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
error(data, status) {
|
|
||||||
if(data && data.detail){
|
|
||||||
let error = typeof data.detail === "string" ? data.detail : JSON.parse(data.detail);
|
|
||||||
|
|
||||||
if(_.isArray(error)){
|
|
||||||
data.detail = error[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ProcessErrors($rootScope, data, status, null, {
|
|
||||||
hdr: 'Error!',
|
|
||||||
msg: `Invalid search term entered. GET returned: ${status}`
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// Removes state definition defaults and pagination terms
|
|
||||||
stripDefaultParams(params, defaults) {
|
|
||||||
if(defaults) {
|
|
||||||
let stripped =_.pick(params, (value, key) => {
|
|
||||||
// setting the default value of a term to null in a state definition is a very explicit way to ensure it will NEVER generate a search tag, even with a non-default value
|
|
||||||
return defaults[key] !== value && key !== 'order_by' && key !== 'page' && key !== 'page_size' && defaults[key] !== null;
|
|
||||||
});
|
|
||||||
let strippedCopy = _.cloneDeep(stripped);
|
|
||||||
if(_.keys(_.pick(defaults, _.keys(strippedCopy))).length > 0){
|
|
||||||
for (var key in strippedCopy) {
|
|
||||||
if (strippedCopy.hasOwnProperty(key)) {
|
|
||||||
let value = strippedCopy[key];
|
|
||||||
if(_.isArray(value)){
|
|
||||||
let index = _.indexOf(value, defaults[key]);
|
|
||||||
value = value.splice(index, 1)[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stripped = strippedCopy;
|
|
||||||
}
|
|
||||||
return _(strippedCopy).map(this.decodeParam).flatten().value();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return _(params).map(this.decodeParam).flatten().value();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
}
|
// decodes a django queryset for ui-router's URLMatcherFactory
|
||||||
|
// 'operand:key:comparator:value,...' => {operand__key__comparator: value, }
|
||||||
|
decodeArr(arr) {
|
||||||
|
let params = {};
|
||||||
|
|
||||||
|
if (!arr) {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
_.forEach(arr.split(';'), (item) => {
|
||||||
|
let key = item.split(':')[0],
|
||||||
|
value = item.split(':')[1];
|
||||||
|
if(!params[key]){
|
||||||
|
params[key] = value;
|
||||||
|
}
|
||||||
|
else if (Array.isArray(params[key])){
|
||||||
|
params[key] = _.uniq(_.flattenDeep(params[key]));
|
||||||
|
params[key].push(value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params[key] = [params[key], value];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
// REST utilities
|
||||||
|
options(endpoint) {
|
||||||
|
Rest.setUrl(endpoint);
|
||||||
|
return Rest.options(endpoint);
|
||||||
|
},
|
||||||
|
search(endpoint, params) {
|
||||||
|
Wait('start');
|
||||||
|
this.url = `${endpoint}${this.encodeQueryset(params)}`;
|
||||||
|
Rest.setUrl(this.url);
|
||||||
|
|
||||||
|
return Rest.get()
|
||||||
|
.then(function(response) {
|
||||||
|
Wait('stop');
|
||||||
|
|
||||||
|
if (response
|
||||||
|
.headers('X-UI-Max-Events') !== null) {
|
||||||
|
response.data.maxEvents = response.
|
||||||
|
headers('X-UI-Max-Events');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch(function(response) {
|
||||||
|
Wait('stop');
|
||||||
|
|
||||||
|
this.error(response.data, response.status);
|
||||||
|
|
||||||
|
throw response;
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
error(data, status) {
|
||||||
|
if(data && data.detail){
|
||||||
|
let error = typeof data.detail === "string" ? data.detail : JSON.parse(data.detail);
|
||||||
|
|
||||||
|
if(_.isArray(error)){
|
||||||
|
data.detail = error[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProcessErrors($rootScope, data, status, null, {
|
||||||
|
hdr: 'Error!',
|
||||||
|
msg: `Invalid search term entered. GET returned: ${status}`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// Removes state definition defaults and pagination terms
|
||||||
|
stripDefaultParams(params, defaultParams) {
|
||||||
|
if (!params) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if(defaultParams) {
|
||||||
|
let stripped =_.pick(params, (value, key) => {
|
||||||
|
// setting the default value of a term to null in a state definition is a very explicit way to ensure it will NEVER generate a search tag, even with a non-default value
|
||||||
|
return defaultParams[key] !== value && key !== 'order_by' && key !== 'page' && key !== 'page_size' && defaultParams[key] !== null;
|
||||||
|
});
|
||||||
|
let strippedCopy = _.cloneDeep(stripped);
|
||||||
|
if(_.keys(_.pick(defaultParams, _.keys(strippedCopy))).length > 0){
|
||||||
|
for (var key in strippedCopy) {
|
||||||
|
if (strippedCopy.hasOwnProperty(key)) {
|
||||||
|
let value = strippedCopy[key];
|
||||||
|
if(_.isArray(value)){
|
||||||
|
let index = _.indexOf(value, defaultParams[key]);
|
||||||
|
value = value.splice(index, 1)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stripped = strippedCopy;
|
||||||
|
}
|
||||||
|
return _(strippedCopy).map(this.decodeParam).flatten().value();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return _(params).map(this.decodeParam).flatten().value();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mergeQueryset (queryset, additional, singleSearchParam) {
|
||||||
|
const space = '%20and%20';
|
||||||
|
|
||||||
|
const merged = _.merge({}, queryset, additional, (objectValue, sourceValue, key, object) => {
|
||||||
|
if (!(object[key] && object[key] !== sourceValue)) {
|
||||||
|
// // https://lodash.com/docs/3.10.1#each
|
||||||
|
// If this returns undefined merging is handled by default _.merge algorithm
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isArray(object[key])) {
|
||||||
|
object[key].push(sourceValue);
|
||||||
|
return object[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (singleSearchParam) {
|
||||||
|
if (!object[key]) {
|
||||||
|
return sourceValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const singleSearchParamKeys = object[key].split(space);
|
||||||
|
|
||||||
|
if (_.includes(singleSearchParamKeys, sourceValue)) {
|
||||||
|
return object[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${object[key]}${space}${sourceValue}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the array of keys
|
||||||
|
return [object[key], sourceValue];
|
||||||
|
});
|
||||||
|
|
||||||
|
return merged;
|
||||||
|
},
|
||||||
|
getSearchInputQueryset (searchInput, isRelatedField = null, isAnsibleFactField = null, singleSearchParam = null) {
|
||||||
|
// XXX Should find a better approach than passing in the two 'is...Field' callbacks XXX
|
||||||
|
const space = '%20and%20';
|
||||||
|
let params = {};
|
||||||
|
|
||||||
|
// Remove leading/trailing whitespace if there is any
|
||||||
|
const terms = (searchInput) ? searchInput.trim() : '';
|
||||||
|
|
||||||
|
if (!(terms && terms !== '')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let splitTerms;
|
||||||
|
|
||||||
|
if (singleSearchParam === 'host_filter') {
|
||||||
|
splitTerms = SmartSearchService.splitFilterIntoTerms(terms);
|
||||||
|
} else {
|
||||||
|
splitTerms = SmartSearchService.splitSearchIntoTerms(terms);
|
||||||
|
}
|
||||||
|
|
||||||
|
const combineSameSearches = (a, b) => {
|
||||||
|
if (!a) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isArray(a)) {
|
||||||
|
return a.concat(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (singleSearchParam) {
|
||||||
|
return `${a}${space}${b}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [a, b];
|
||||||
|
};
|
||||||
|
|
||||||
|
_.each(splitTerms, term => {
|
||||||
|
const termParts = SmartSearchService.splitTermIntoParts(term);
|
||||||
|
let termParams;
|
||||||
|
|
||||||
|
if (termParts.length === 1) {
|
||||||
|
termParams = searchWithoutKey(term, singleSearchParam);
|
||||||
|
} else if (isAnsibleFactField && isAnsibleFactField(termParts)) {
|
||||||
|
termParams = this.encodeParam({ term, singleSearchParam });
|
||||||
|
} else if (isRelatedField && isRelatedField(termParts)) {
|
||||||
|
termParams = this.encodeParam({ term, singleSearchParam, related: true });
|
||||||
|
} else {
|
||||||
|
termParams = this.encodeParam({ term, singleSearchParam });
|
||||||
|
}
|
||||||
|
|
||||||
|
params = _.merge(params, termParams, combineSameSearches);
|
||||||
|
});
|
||||||
|
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
removeTermsFromQueryset(queryset, term, isRelatedField = null, singleSearchParam = null) {
|
||||||
|
const modifiedQueryset = _.cloneDeep(queryset);
|
||||||
|
|
||||||
|
const removeSingleTermFromQueryset = (value, key) => {
|
||||||
|
const space = '%20and%20';
|
||||||
|
|
||||||
|
if (Array.isArray(modifiedQueryset[key])) {
|
||||||
|
modifiedQueryset[key] = modifiedQueryset[key].filter(item => item !== value);
|
||||||
|
if (modifiedQueryset[key].length < 1) {
|
||||||
|
delete modifiedQueryset[key];
|
||||||
|
}
|
||||||
|
} else if (singleSearchParam && _.get(modifiedQueryset, singleSearchParam, []).includes(space)) {
|
||||||
|
const searchParamParts = modifiedQueryset[singleSearchParam].split(space);
|
||||||
|
// The value side of each paramPart might have been encoded in
|
||||||
|
// SmartSearch.splitFilterIntoTerms
|
||||||
|
_.each(searchParamParts, (paramPart, paramPartIndex) => {
|
||||||
|
searchParamParts[paramPartIndex] = decodeURIComponent(paramPart);
|
||||||
|
});
|
||||||
|
|
||||||
|
const paramPartIndex = searchParamParts.indexOf(value);
|
||||||
|
|
||||||
|
if (paramPartIndex !== -1) {
|
||||||
|
searchParamParts.splice(paramPartIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiedQueryset[singleSearchParam] = searchParamParts.join(space);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
delete modifiedQueryset[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const termParts = SmartSearchService.splitTermIntoParts(term);
|
||||||
|
|
||||||
|
let removed;
|
||||||
|
|
||||||
|
if (termParts.length === 1) {
|
||||||
|
removed = searchWithoutKey(term, singleSearchParam);
|
||||||
|
} else if (isRelatedField && isRelatedField(termParts)) {
|
||||||
|
removed = this.encodeParam({ term, singleSearchParam, related: true });
|
||||||
|
} else {
|
||||||
|
removed = this.encodeParam({ term, singleSearchParam });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!removed) {
|
||||||
|
removed = searchWithoutKey(termParts[termParts.length - 1], singleSearchParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.each(removed, removeSingleTermFromQueryset);
|
||||||
|
|
||||||
|
return modifiedQueryset;
|
||||||
|
},
|
||||||
|
createSearchTagsFromQueryset(queryset, defaultParams = null, singleSearchParam = null) {
|
||||||
|
const space = '%20and%20';
|
||||||
|
const modifiedQueryset = angular.copy(queryset);
|
||||||
|
|
||||||
|
let searchTags = [];
|
||||||
|
|
||||||
|
if (singleSearchParam && modifiedQueryset[singleSearchParam]) {
|
||||||
|
const searchParam = modifiedQueryset[singleSearchParam].split(space);
|
||||||
|
delete modifiedQueryset[singleSearchParam];
|
||||||
|
|
||||||
|
$.each(searchParam, (index, param) => {
|
||||||
|
const paramParts = decodeURIComponent(param).split(/=(.+)/);
|
||||||
|
const reconstructedSearchString = this.decodeParam(paramParts[1], paramParts[0]);
|
||||||
|
|
||||||
|
searchTags.push(reconstructedSearchString);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchTags.concat(this.stripDefaultParams(modifiedQueryset, defaultParams));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QuerysetService.$inject = [
|
||||||
|
'$q',
|
||||||
|
'Rest',
|
||||||
|
'ProcessErrors',
|
||||||
|
'$rootScope',
|
||||||
|
'Wait',
|
||||||
|
'DjangoSearchModel',
|
||||||
|
'SmartSearchService',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export default QuerysetService;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ function SmartSearchController (
|
|||||||
GetBasePath,
|
GetBasePath,
|
||||||
i18n,
|
i18n,
|
||||||
qs,
|
qs,
|
||||||
SmartSearchService
|
|
||||||
) {
|
) {
|
||||||
const searchKey = `${$scope.iterator}_search`;
|
const searchKey = `${$scope.iterator}_search`;
|
||||||
const optionsKey = `${$scope.list.iterator}_options`;
|
const optionsKey = `${$scope.list.iterator}_options`;
|
||||||
@@ -58,7 +57,7 @@ function SmartSearchController (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function compareParams(a, b) {
|
function compareParams (a, b) {
|
||||||
for (let key in a) {
|
for (let key in a) {
|
||||||
if (!(key in b) || a[key].toString() !== b[key].toString()) {
|
if (!(key in b) || a[key].toString() !== b[key].toString()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -106,22 +105,8 @@ function SmartSearchController (
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateSearchTags () {
|
function generateSearchTags () {
|
||||||
$scope.searchTags = [];
|
const { singleSearchParam } = $scope;
|
||||||
|
$scope.searchTags = qs.createSearchTagsFromQueryset(queryset, defaults, singleSearchParam);
|
||||||
const querysetCopy = angular.copy(queryset);
|
|
||||||
|
|
||||||
if ($scope.singleSearchParam && querysetCopy[$scope.singleSearchParam]) {
|
|
||||||
const searchParam = querysetCopy[$scope.singleSearchParam].split('%20and%20');
|
|
||||||
delete querysetCopy[$scope.singleSearchParam];
|
|
||||||
|
|
||||||
$.each(searchParam, (index, param) => {
|
|
||||||
const paramParts = decodeURIComponent(param).split(/=(.+)/);
|
|
||||||
const reconstructedSearchString = qs.decodeParam(paramParts[1], paramParts[0]);
|
|
||||||
$scope.searchTags.push(reconstructedSearchString);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.searchTags = $scope.searchTags.concat(qs.stripDefaultParams(querysetCopy, defaults));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function revertSearch (queryToBeRestored) {
|
function revertSearch (queryToBeRestored) {
|
||||||
@@ -149,14 +134,7 @@ function SmartSearchController (
|
|||||||
$scope.showKeyPane = !$scope.showKeyPane;
|
$scope.showKeyPane = !$scope.showKeyPane;
|
||||||
};
|
};
|
||||||
|
|
||||||
function searchWithoutKey (term, singleSearchParam = null) {
|
function isAnsibleFactField (termParts) {
|
||||||
if (singleSearchParam) {
|
|
||||||
return { [singleSearchParam]: `search=${encodeURIComponent(term)}` };
|
|
||||||
}
|
|
||||||
return { search: encodeURIComponent(term) };
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAnsibleFactSearchTerm (termParts) {
|
|
||||||
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
||||||
return rootField === 'ansible_facts';
|
return rootField === 'ansible_facts';
|
||||||
}
|
}
|
||||||
@@ -172,111 +150,21 @@ function SmartSearchController (
|
|||||||
return (isRelatedSearchTermField || isBaseModelRelatedSearchTermField);
|
return (isRelatedSearchTermField || isBaseModelRelatedSearchTermField);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSearchInputQueryset ({ terms, singleSearchParam }) {
|
|
||||||
let params = {};
|
|
||||||
|
|
||||||
// remove leading/trailing whitespace
|
|
||||||
terms = (terms) ? terms.trim() : '';
|
|
||||||
let splitTerms;
|
|
||||||
|
|
||||||
if (singleSearchParam === 'host_filter') {
|
|
||||||
splitTerms = SmartSearchService.splitFilterIntoTerms(terms);
|
|
||||||
} else {
|
|
||||||
splitTerms = SmartSearchService.splitSearchIntoTerms(terms);
|
|
||||||
}
|
|
||||||
|
|
||||||
const combineSameSearches = (a, b) => {
|
|
||||||
if (!a) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_.isArray(a)) {
|
|
||||||
return a.concat(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (singleSearchParam) {
|
|
||||||
return `${a}%20and%20${b}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [a, b];
|
|
||||||
};
|
|
||||||
|
|
||||||
_.each(splitTerms, term => {
|
|
||||||
const termParts = SmartSearchService.splitTermIntoParts(term);
|
|
||||||
let termParams;
|
|
||||||
|
|
||||||
if (termParts.length === 1) {
|
|
||||||
termParams = searchWithoutKey(term, singleSearchParam);
|
|
||||||
} else if (isAnsibleFactSearchTerm(termParts)) {
|
|
||||||
termParams = qs.encodeParam({ term, singleSearchParam });
|
|
||||||
} else if (isRelatedField(termParts)) {
|
|
||||||
termParams = qs.encodeParam({ term, singleSearchParam, related: true });
|
|
||||||
} else {
|
|
||||||
termParams = qs.encodeParam({ term, singleSearchParam });
|
|
||||||
}
|
|
||||||
|
|
||||||
params = _.merge(params, termParams, combineSameSearches);
|
|
||||||
});
|
|
||||||
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergeQueryset (qset, additional, singleSearchParam) {
|
|
||||||
const merged = _.merge({}, qset, additional, (objectValue, sourceValue, key, object) => {
|
|
||||||
if (!(object[key] && object[key] !== sourceValue)) {
|
|
||||||
// // https://lodash.com/docs/3.10.1#each
|
|
||||||
// If this returns undefined merging is handled by default _.merge algorithm
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_.isArray(object[key])) {
|
|
||||||
object[key].push(sourceValue);
|
|
||||||
return object[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (singleSearchParam) {
|
|
||||||
if (!object[key]) {
|
|
||||||
return sourceValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const singleSearchParamKeys = object[key].split('%20and%20');
|
|
||||||
|
|
||||||
if (_.includes(singleSearchParamKeys, sourceValue)) {
|
|
||||||
return object[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${object[key]}%20and%20${sourceValue}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the array of keys
|
|
||||||
return [object[key], sourceValue];
|
|
||||||
});
|
|
||||||
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.addTerms = terms => {
|
$scope.addTerms = terms => {
|
||||||
const { singleSearchParam } = $scope;
|
const { singleSearchParam } = $scope;
|
||||||
const origQueryset = _.clone(queryset);
|
const unmodifiedQueryset = _.clone(queryset);
|
||||||
|
|
||||||
// Remove leading/trailing whitespace if there is any
|
const searchInputQueryset = qs.getSearchInputQueryset(terms, isRelatedField, isAnsibleFactField, singleSearchParam);
|
||||||
terms = (terms) ? terms.trim() : '';
|
const modifiedQueryset = qs.mergeQueryset(queryset, searchInputQueryset, singleSearchParam);
|
||||||
|
|
||||||
if (!(terms && terms !== '')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchInputQueryset = getSearchInputQueryset({ terms, singleSearchParam });
|
|
||||||
queryset = mergeQueryset(queryset, searchInputQueryset, singleSearchParam);
|
|
||||||
|
|
||||||
// Go back to the first page after a new search
|
// Go back to the first page after a new search
|
||||||
delete queryset.page;
|
delete modifiedQueryset.page;
|
||||||
|
|
||||||
// https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic
|
// https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic
|
||||||
// This transition will not reload controllers/resolves/views but will register new
|
// This transition will not reload controllers/resolves/views but will register new
|
||||||
// $stateParams[searchKey] terms.
|
// $stateParams[searchKey] terms.
|
||||||
if (!$scope.querySet) {
|
if (!$scope.querySet) {
|
||||||
$state.go('.', { [searchKey]: queryset })
|
$state.go('.', { [searchKey]: modifiedQueryset })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// same as above in $scope.remove. For some reason deleting the page
|
// same as above in $scope.remove. For some reason deleting the page
|
||||||
// from the queryset works for all lists except lists in modals.
|
// from the queryset works for all lists except lists in modals.
|
||||||
@@ -284,80 +172,26 @@ function SmartSearchController (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
qs.search(path, queryset)
|
qs.search(path, modifiedQueryset)
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
if ($scope.querySet) {
|
if ($scope.querySet) {
|
||||||
$scope.querySet = queryset;
|
$scope.querySet = modifiedQueryset;
|
||||||
}
|
}
|
||||||
$scope.dataset = data;
|
$scope.dataset = data;
|
||||||
$scope.collection = data.results;
|
$scope.collection = data.results;
|
||||||
})
|
})
|
||||||
.catch(() => revertSearch(origQueryset));
|
.catch(() => revertSearch(unmodifiedQueryset));
|
||||||
|
|
||||||
$scope.searchTerm = null;
|
$scope.searchTerm = null;
|
||||||
|
|
||||||
generateSearchTags();
|
generateSearchTags();
|
||||||
};
|
};
|
||||||
|
|
||||||
function removeTermsFromQueryset(qset, term, singleSearchParam = null) {
|
|
||||||
const returnedQueryset = _.cloneDeep(qset);
|
|
||||||
|
|
||||||
const removeSingleTermFromQueryset = (value, key) => {
|
|
||||||
const space = '%20and%20';
|
|
||||||
|
|
||||||
if (Array.isArray(returnedQueryset[key])) {
|
|
||||||
returnedQueryset[key] = returnedQueryset[key].filter(item => item !== value);
|
|
||||||
if (returnedQueryset[key].length < 1) {
|
|
||||||
delete returnedQueryset[key];
|
|
||||||
}
|
|
||||||
} else if (singleSearchParam && _.get(returnedQueryset, singleSearchParam, []).includes(space)) {
|
|
||||||
const searchParamParts = returnedQueryset[singleSearchParam].split(space);
|
|
||||||
// The value side of each paramPart might have been encoded in
|
|
||||||
// SmartSearch.splitFilterIntoTerms
|
|
||||||
_.each(searchParamParts, (paramPart, paramPartIndex) => {
|
|
||||||
searchParamParts[paramPartIndex] = decodeURIComponent(paramPart);
|
|
||||||
});
|
|
||||||
|
|
||||||
const paramPartIndex = searchParamParts.indexOf(value);
|
|
||||||
|
|
||||||
if (paramPartIndex !== -1) {
|
|
||||||
searchParamParts.splice(paramPartIndex, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
returnedQueryset[singleSearchParam] = searchParamParts.join(space);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
delete returnedQueryset[key];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const termParts = SmartSearchService.splitTermIntoParts(term);
|
|
||||||
|
|
||||||
let removed;
|
|
||||||
|
|
||||||
if (termParts.length === 1) {
|
|
||||||
removed = searchWithoutKey(term, singleSearchParam);
|
|
||||||
} else if (isRelatedField(termParts)) {
|
|
||||||
removed = qs.encodeParam({ term, singleSearchParam, related: true });
|
|
||||||
} else {
|
|
||||||
removed = qs.encodeParam({ term, singleSearchParam });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!removed) {
|
|
||||||
removed = searchWithoutKey(termParts[termParts.length - 1], singleSearchParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
_.each(removed, removeSingleTermFromQueryset);
|
|
||||||
|
|
||||||
return returnedQueryset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove tag, merge new queryset, $state.go
|
// remove tag, merge new queryset, $state.go
|
||||||
$scope.removeTerm = index => {
|
$scope.removeTerm = index => {
|
||||||
const { singleSearchParam } = $scope;
|
const { singleSearchParam } = $scope;
|
||||||
const [term] = $scope.searchTags.splice(index, 1);
|
const [term] = $scope.searchTags.splice(index, 1);
|
||||||
|
|
||||||
const modifiedQueryset = removeTermsFromQueryset(queryset, term, singleSearchParam);
|
const modifiedQueryset = qs.removeTermsFromQueryset(queryset, term, isRelatedField, singleSearchParam);
|
||||||
|
|
||||||
if (!$scope.querySet) {
|
if (!$scope.querySet) {
|
||||||
$state.go('.', { [searchKey]: modifiedQueryset })
|
$state.go('.', { [searchKey]: modifiedQueryset })
|
||||||
@@ -365,8 +199,7 @@ function SmartSearchController (
|
|||||||
// for some reason deleting a tag from a list in a modal does not
|
// for some reason deleting a tag from a list in a modal does not
|
||||||
// remove the param from $stateParams. Here we'll manually check to make sure
|
// remove the param from $stateParams. Here we'll manually check to make sure
|
||||||
// that that happened and remove it if it didn't.
|
// that that happened and remove it if it didn't.
|
||||||
const clearedParams = removeTermsFromQueryset(
|
const clearedParams = qs.removeTermsFromQueryset($stateParams[searchKey], term, isRelatedField, singleSearchParam);
|
||||||
$stateParams[searchKey], term, singleSearchParam);
|
|
||||||
$stateParams[searchKey] = clearedParams;
|
$stateParams[searchKey] = clearedParams;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -416,7 +249,6 @@ SmartSearchController.$inject = [
|
|||||||
'GetBasePath',
|
'GetBasePath',
|
||||||
'i18n',
|
'i18n',
|
||||||
'QuerySet',
|
'QuerySet',
|
||||||
'SmartSearchService',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default SmartSearchController;
|
export default SmartSearchController;
|
||||||
|
|||||||
Reference in New Issue
Block a user