mirror of
https://github.com/ansible/awx.git
synced 2024-11-01 08:21:15 +03:00
Smart Search - support array of values per key (#4187)
* Smart Search - support array of values per key, #4162 * lint
This commit is contained in:
parent
6022668706
commit
1dab4f903c
@ -249,7 +249,7 @@ var tower = angular.module('Tower', [
|
||||
},
|
||||
// decoding
|
||||
// from "_search=operator:key:compator=value& ... "
|
||||
// to "_search=operator:key:compator=value& ... "
|
||||
// to {operator__key1__comparator=value, ... }
|
||||
decode: function(item) {
|
||||
return QuerySet.$get().decodeArr(item);
|
||||
},
|
||||
|
@ -51,10 +51,19 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
encodeQueryset(params) {
|
||||
let queryset;
|
||||
queryset = _.reduce(params, (result, value, key) => {
|
||||
return result + `${key}=${value}&`;
|
||||
return result + encodeTerm(value, key);
|
||||
}, '');
|
||||
queryset = queryset.substring(0, queryset.length - 1);
|
||||
return angular.isObject(params) ? `?${queryset}` : '';
|
||||
|
||||
function encodeTerm(value, key){
|
||||
if (Array.isArray(value)){
|
||||
return _.map(value, (item) => `${key}=${item}`).join('&') + '&';
|
||||
}
|
||||
else {
|
||||
return `${key}=${value}&`;
|
||||
}
|
||||
}
|
||||
},
|
||||
// encodes a ui smart-search param to a django-friendly param
|
||||
// operand:key:comparator:value => {operand__key__comparator: value}
|
||||
@ -62,19 +71,42 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
let split = param.split(':');
|
||||
return {[split.slice(0,split.length -1).join('__')] : split[split.length-1]};
|
||||
},
|
||||
// decodes a django queryset param into ui smart-search param
|
||||
decodeParam(key, value){
|
||||
return `${key.split('__').join(':')}:${value}`;
|
||||
// decodes a django queryset param into a ui smart-search tag or set of tags
|
||||
decodeParam(value, key){
|
||||
if (Array.isArray(value)){
|
||||
return _.map(value, (item) => {
|
||||
return `${key.split('__').join(':')}:${item}`;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return `${key.split('__').join(':')}:${value}`;
|
||||
}
|
||||
},
|
||||
|
||||
// encodes a django queryset for ui-router's URLMatcherFactory
|
||||
// {operand__key__comparator: value, } => 'operand:key:comparator:value,...'
|
||||
// {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(`${key}:${value}`);
|
||||
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)){
|
||||
return _.map(value, (item) => {
|
||||
return `${key}:${item}`;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return `${key}:${value}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// decodes a django queryset for ui-router's URLMatcherFactory
|
||||
@ -84,7 +116,15 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
||||
_.forEach(arr.split(';'), (item) => {
|
||||
let key = item.split(':')[0],
|
||||
value = item.split(':')[1];
|
||||
params[key] = value;
|
||||
if(!params[key]){
|
||||
params[key] = value;
|
||||
}
|
||||
else if (Array.isArray(params[key])){
|
||||
params[key].push(value);
|
||||
}
|
||||
else {
|
||||
params[key] = [params[key], value];
|
||||
}
|
||||
});
|
||||
return params;
|
||||
},
|
||||
|
@ -22,10 +22,11 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
||||
|
||||
// Removes state definition defaults and pagination terms
|
||||
function stripDefaultParams(params) {
|
||||
return _.pick(params, (value, key) => {
|
||||
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 !== 'page' && key !== 'page_size' && defaults[key] !== null;
|
||||
});
|
||||
return _(stripped).map(qs.decodeParam).flatten().value();
|
||||
}
|
||||
|
||||
// searchable relationships
|
||||
@ -53,8 +54,16 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
||||
};
|
||||
|
||||
// remove tag, merge new queryset, $state.go
|
||||
$scope.remove = function(key) {
|
||||
delete queryset[key];
|
||||
$scope.remove = function(index) {
|
||||
let removed = qs.encodeParam($scope.searchTags.splice(index, 1)[0]);
|
||||
_.each(removed, (value, key) => {
|
||||
if (Array.isArray(queryset[key])){
|
||||
_.remove(queryset[key], (item) => item === value);
|
||||
}
|
||||
else {
|
||||
delete queryset[key];
|
||||
}
|
||||
});
|
||||
$state.go('.', {
|
||||
[$scope.iterator + '_search']: queryset });
|
||||
qs.search(path, queryset).then((res) => {
|
||||
@ -91,7 +100,16 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
||||
}
|
||||
|
||||
params.page = '1';
|
||||
queryset = _.merge(queryset, params);
|
||||
queryset = _.merge(queryset, params, (objectValue, sourceValue, key, object) => {
|
||||
if (object[key] && object[key] !== sourceValue){
|
||||
return [object[key], sourceValue];
|
||||
}
|
||||
else {
|
||||
// // https://lodash.com/docs/3.10.1#merge
|
||||
// If customizer fn returns undefined merging is handled by default _.merge algorithm
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
// https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic
|
||||
// This transition will not reload controllers/resolves/views
|
||||
// but will register new $stateParams[$scope.iterator + '_search'] terms
|
||||
@ -105,9 +123,5 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
||||
$scope.searchTerm = null;
|
||||
$scope.searchTags = stripDefaultParams(queryset);
|
||||
};
|
||||
|
||||
$scope.decodeParam = function(key, value) {
|
||||
return qs.decodeParam(key, value);
|
||||
};
|
||||
}
|
||||
];
|
||||
|
@ -19,12 +19,12 @@
|
||||
<div class="SmartSearch-tags">
|
||||
<div class="SmartSearch-tagSection">
|
||||
<div class="SmartSearch-flexContainer">
|
||||
<div class="SmartSearch-tagContainer" ng-repeat="(key, value) in searchTags track by $index">
|
||||
<div class="SmartSearch-deleteContainer" ng-click="remove(key)">
|
||||
<div class="SmartSearch-tagContainer" ng-repeat="tag in searchTags track by $index">
|
||||
<div class="SmartSearch-deleteContainer" ng-click="remove($index)">
|
||||
<i class="fa fa-times SmartSearch-tagDelete"></i>
|
||||
</div>
|
||||
<div class="SmartSearch-tag SmartSearch-tag--deletable">
|
||||
<span class="SmartSearch-name">{{decodeParam(key, value)}}</span>
|
||||
<span class="SmartSearch-name">{{tag}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a href class="SmartSearch-clearAll" ng-click="clearAll()" ng-show="!(searchTags | isEmpty)">CLEAR ALL</a>
|
||||
|
Loading…
Reference in New Issue
Block a user