mirror of
https://github.com/ansible/awx.git
synced 2026-03-10 05:59:28 -02:30
Merge pull request #4669 from mabashian/smart-search-default-behavior
Smart search default behavior
This commit is contained in:
@@ -1830,7 +1830,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
// smart-search directive
|
// smart-search directive
|
||||||
html += `
|
html += `
|
||||||
<div
|
<div
|
||||||
ng-hide="${itm}.length === 0 && (${collection.iterator}_searchTags | isEmpty)">
|
ng-hide="${itm}.length === 0 && (searchTags | isEmpty)">
|
||||||
<smart-search
|
<smart-search
|
||||||
django-model="${itm}"
|
django-model="${itm}"
|
||||||
search-size="${width}"
|
search-size="${width}"
|
||||||
@@ -1855,7 +1855,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += `
|
html += `
|
||||||
<div
|
<div
|
||||||
class="row"
|
class="row"
|
||||||
ng-show="${itm}.length === 0 && !(${collection.iterator}_searchTags | isEmpty)">
|
ng-show="${itm}.length === 0 && !(searchTags | isEmpty)">
|
||||||
<div class="col-lg-12 List-searchNoResults">
|
<div class="col-lg-12 List-searchNoResults">
|
||||||
No records matched your search.
|
No records matched your search.
|
||||||
</div>
|
</div>
|
||||||
@@ -1865,7 +1865,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
// Show the "no items" box when loading is done and the user isn't actively searching and there are no results
|
// Show the "no items" box when loading is done and the user isn't actively searching and there are no results
|
||||||
var emptyListText = (collection.emptyListText) ? collection.emptyListText : i18n._("PLEASE ADD ITEMS TO THIS LIST");
|
var emptyListText = (collection.emptyListText) ? collection.emptyListText : i18n._("PLEASE ADD ITEMS TO THIS LIST");
|
||||||
html += `<div ng-hide="is_superuser">`;
|
html += `<div ng-hide="is_superuser">`;
|
||||||
html += `<div class="List-noItems" ng-show="${itm}.length === 0 && (${collection.iterator}_searchTags | isEmpty)"> ${emptyListText} </div>`;
|
html += `<div class="List-noItems" ng-show="${itm}.length === 0 && (searchTags | isEmpty)"> ${emptyListText} </div>`;
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default ['$scope', '$stateParams', '$state', '$filter', 'GetBasePath', 'Q
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
path = GetBasePath($scope.basePath) || $scope.basePath;
|
path = GetBasePath($scope.basePath) || $scope.basePath;
|
||||||
queryset = _.merge($stateParams[`${$scope.iterator}_search`], { page: page });
|
queryset = _.merge($stateParams[`${$scope.iterator}_search`], { page: page.toString() });
|
||||||
$state.go('.', {
|
$state.go('.', {
|
||||||
[$scope.iterator + '_search']: queryset
|
[$scope.iterator + '_search']: queryset
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import directive from './smart-search.directive';
|
|||||||
import controller from './smart-search.controller';
|
import controller from './smart-search.controller';
|
||||||
import service from './queryset.service';
|
import service from './queryset.service';
|
||||||
import DjangoSearchModel from './django-search-model.class';
|
import DjangoSearchModel from './django-search-model.class';
|
||||||
|
import smartSearchService from './smart-search.service';
|
||||||
|
|
||||||
export default
|
export default
|
||||||
angular.module('SmartSearchModule', [])
|
angular.module('SmartSearchModule', [])
|
||||||
.directive('smartSearch', directive)
|
.directive('smartSearch', directive)
|
||||||
.controller('SmartSearchController', controller)
|
.controller('SmartSearchController', controller)
|
||||||
.service('QuerySet', service)
|
.service('QuerySet', service)
|
||||||
|
.service('SmartSearchService', smartSearchService)
|
||||||
.constant('DjangoSearchModel', DjangoSearchModel);
|
.constant('DjangoSearchModel', DjangoSearchModel);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSearchModel', '$cacheFactory',
|
export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSearchModel', '$cacheFactory', 'SmartSearchService',
|
||||||
function($q, Rest, ProcessErrors, $rootScope, Wait, DjangoSearchModel, $cacheFactory) {
|
function($q, Rest, ProcessErrors, $rootScope, Wait, DjangoSearchModel, $cacheFactory, SmartSearchService) {
|
||||||
return {
|
return {
|
||||||
// kick off building a model for a specific endpoint
|
// kick off building a model for a specific endpoint
|
||||||
// this is usually a list's basePath
|
// this is usually a list's basePath
|
||||||
@@ -67,29 +67,120 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
|||||||
return angular.isObject(params) ? `?${queryset}` : '';
|
return angular.isObject(params) ? `?${queryset}` : '';
|
||||||
|
|
||||||
function encodeTerm(value, key){
|
function encodeTerm(value, key){
|
||||||
|
|
||||||
|
key = key.replace(/__icontains_DEFAULT/g, "__icontains");
|
||||||
|
key = key.replace(/__search_DEFAULT/g, "__search");
|
||||||
|
|
||||||
if (Array.isArray(value)){
|
if (Array.isArray(value)){
|
||||||
return _.map(value, (item) => `${key}=${item}`).join('&') + '&';
|
let concated = '';
|
||||||
|
angular.forEach(value, function(item){
|
||||||
|
item = item.replace(/"|'/g, "");
|
||||||
|
concated += `${key}=${item}&`;
|
||||||
|
});
|
||||||
|
return concated;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
value = value.replace(/"|'/g, "");
|
||||||
return `${key}=${value}&`;
|
return `${key}=${value}&`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// encodes a ui smart-search param to a django-friendly param
|
// encodes a ui smart-search param to a django-friendly param
|
||||||
// operand:key:comparator:value => {operand__key__comparator: value}
|
// operand:key:comparator:value => {operand__key__comparator: value}
|
||||||
encodeParam(param){
|
encodeParam(params){
|
||||||
let split = param.split(':');
|
// Assumption here is that we have a key and a value so the length
|
||||||
return {[split.slice(0,split.length -1).join('__')] : split[split.length-1]};
|
// of the paramParts array will be 2. [0] is the key and [1] the value
|
||||||
|
let paramParts = SmartSearchService.splitTermIntoParts(params.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(params.searchTerm && !lessThanGreaterThan) {
|
||||||
|
paramString += keySplit[0] + '__icontains_DEFAULT';
|
||||||
|
}
|
||||||
|
else if(params.relatedSearchTerm) {
|
||||||
|
paramString += keySplit[0] + '__search_DEFAULT';
|
||||||
|
}
|
||||||
|
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(/^(>)/,"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {[paramString] : valueString};
|
||||||
},
|
},
|
||||||
// decodes a django queryset param into a ui smart-search tag or set of tags
|
// decodes a django queryset param into a ui smart-search tag or set of tags
|
||||||
decodeParam(value, key){
|
decodeParam(value, key){
|
||||||
|
|
||||||
|
let decodeParamString = function(searchString) {
|
||||||
|
if(key === 'search') {
|
||||||
|
// Don't include 'search:' in the search tag
|
||||||
|
return decodeURIComponent(`${searchString}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
key = key.replace(/__icontains_DEFAULT/g, "");
|
||||||
|
key = key.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);
|
||||||
|
}
|
||||||
|
return exclude ? `-${split.join('.')}:${decodedParam}` : `${split.join('.')}:${decodedParam}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (Array.isArray(value)){
|
if (Array.isArray(value)){
|
||||||
return _.map(value, (item) => {
|
return _.map(value, (item) => {
|
||||||
return `${key.split('__').join(':')}:${item}`;
|
return decodeParamString(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return `${key.split('__').join(':')}:${value}`;
|
return decodeParamString(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -161,6 +252,7 @@ export default ['$q', 'Rest', 'ProcessErrors', '$rootScope', 'Wait', 'DjangoSear
|
|||||||
success(data) {
|
success(data) {
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', 'QuerySet',
|
export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', 'QuerySet', 'SmartSearchService',
|
||||||
function($stateParams, $scope, $state, QuerySet, GetBasePath, qs) {
|
function($stateParams, $scope, $state, QuerySet, GetBasePath, qs, SmartSearchService) {
|
||||||
|
|
||||||
let path, relations,
|
let path, relations,
|
||||||
// steps through the current tree of $state configurations, grabs default search params
|
// steps through the current tree of $state configurations, grabs default search params
|
||||||
@@ -17,6 +17,7 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
|||||||
$scope.searchTags = stripDefaultParams($state.params[`${$scope.iterator}_search`]);
|
$scope.searchTags = stripDefaultParams($state.params[`${$scope.iterator}_search`]);
|
||||||
qs.initFieldset(path, $scope.djangoModel, relations).then((data) => {
|
qs.initFieldset(path, $scope.djangoModel, relations).then((data) => {
|
||||||
$scope.models = data.models;
|
$scope.models = data.models;
|
||||||
|
$scope.options = data.options.data;
|
||||||
$scope.$emit(`${$scope.list.iterator}_options`, data.options);
|
$scope.$emit(`${$scope.list.iterator}_options`, data.options);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -51,6 +52,16 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
|||||||
return flat;
|
return flat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDefaults(term) {
|
||||||
|
if ($scope.list.defaultSearchParams) {
|
||||||
|
return $scope.list.defaultSearchParams(term);
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
search: encodeURIComponent(term)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$scope.toggleKeyPane = function() {
|
$scope.toggleKeyPane = function() {
|
||||||
$scope.showKeyPane = !$scope.showKeyPane;
|
$scope.showKeyPane = !$scope.showKeyPane;
|
||||||
};
|
};
|
||||||
@@ -69,10 +80,37 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
|||||||
|
|
||||||
// remove tag, merge new queryset, $state.go
|
// remove tag, merge new queryset, $state.go
|
||||||
$scope.remove = function(index) {
|
$scope.remove = function(index) {
|
||||||
let removed = qs.encodeParam($scope.searchTags.splice(index, 1)[0]);
|
let tagToRemove = $scope.searchTags.splice(index, 1)[0];
|
||||||
|
let termParts = SmartSearchService.splitTermIntoParts(tagToRemove);
|
||||||
|
let removed;
|
||||||
|
if (termParts.length === 1) {
|
||||||
|
removed = setDefaults(tagToRemove);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let root = termParts[0].split(".")[0].replace(/^-/, '');
|
||||||
|
let encodeParams = {
|
||||||
|
term: tagToRemove
|
||||||
|
};
|
||||||
|
if(_.has($scope.options.actions.GET, root)) {
|
||||||
|
if($scope.options.actions.GET[root].type && $scope.options.actions.GET[root].type === 'field') {
|
||||||
|
encodeParams.relatedSearchTerm = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
encodeParams.searchTerm = true;
|
||||||
|
}
|
||||||
|
removed = qs.encodeParam(encodeParams);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
removed = setDefaults(tagToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
_.each(removed, (value, key) => {
|
_.each(removed, (value, key) => {
|
||||||
if (Array.isArray(queryset[key])){
|
if (Array.isArray(queryset[key])){
|
||||||
_.remove(queryset[key], (item) => item === value);
|
_.remove(queryset[key], (item) => item === value);
|
||||||
|
// If the array is now empty, remove that key
|
||||||
|
if(queryset[key].length === 0) {
|
||||||
|
delete queryset[key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
delete queryset[key];
|
delete queryset[key];
|
||||||
@@ -92,26 +130,46 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', '
|
|||||||
let params = {},
|
let params = {},
|
||||||
origQueryset = _.clone(queryset);
|
origQueryset = _.clone(queryset);
|
||||||
|
|
||||||
function setDefaults(term) {
|
// Remove leading/trailing whitespace if there is any
|
||||||
// "name" and "description" are sane defaults for MOST models, but not ALL!
|
terms = terms.trim();
|
||||||
// defaults may be configured in ListDefinition.defaultSearchParams
|
|
||||||
if ($scope.list.defaultSearchParams) {
|
|
||||||
return $scope.list.defaultSearchParams(term);
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
or__name__icontains: term,
|
|
||||||
or__description__icontains: term
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(terms && terms !== '') {
|
if(terms && terms !== '') {
|
||||||
_.forEach(terms.split(' '), (term) => {
|
// Split the terms up
|
||||||
|
let splitTerms = SmartSearchService.splitSearchIntoTerms(terms);
|
||||||
|
_.forEach(splitTerms, (term) => {
|
||||||
|
|
||||||
|
let termParts = SmartSearchService.splitTermIntoParts(term);
|
||||||
|
|
||||||
|
function combineSameSearches(a,b){
|
||||||
|
if (_.isArray(a)) {
|
||||||
|
return a.concat(b);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(a) {
|
||||||
|
return [a,b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if only a value is provided, search using default keys
|
// if only a value is provided, search using default keys
|
||||||
if (term.split(':').length === 1) {
|
if (termParts.length === 1) {
|
||||||
params = _.merge(params, setDefaults(term));
|
params = _.merge(params, setDefaults(term), combineSameSearches);
|
||||||
} else {
|
} else {
|
||||||
params = _.merge(params, qs.encodeParam(term));
|
// Figure out if this is a search term
|
||||||
|
let root = termParts[0].split(".")[0].replace(/^-/, '');
|
||||||
|
if(_.has($scope.options.actions.GET, root)) {
|
||||||
|
if($scope.options.actions.GET[root].type && $scope.options.actions.GET[root].type === 'field') {
|
||||||
|
params = _.merge(params, qs.encodeParam({term: term, relatedSearchTerm: true}), combineSameSearches);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params = _.merge(params, qs.encodeParam({term: term, searchTerm: true}), combineSameSearches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Its not a search term or a related search term - treat it as a string
|
||||||
|
else {
|
||||||
|
params = _.merge(params, setDefaults(term), combineSameSearches);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export default [function() {
|
||||||
|
return {
|
||||||
|
splitSearchIntoTerms(searchString) {
|
||||||
|
return searchString.match(/(?:[^\s("')]+|"[^"]*"|'[^']*')+/g);
|
||||||
|
},
|
||||||
|
splitTermIntoParts(searchTerm) {
|
||||||
|
let breakOnColon = searchTerm.match(/(?:[^:"]+|"[^"]*")+/g);
|
||||||
|
|
||||||
|
if(breakOnColon.length > 2) {
|
||||||
|
// concat all the strings after the first one together
|
||||||
|
let stringsToJoin = breakOnColon.slice(1,breakOnColon.length);
|
||||||
|
return [breakOnColon[0], stringsToJoin.join(':')];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return breakOnColon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}];
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
describe('Service: QuerySet', () => {
|
describe('Service: QuerySet', () => {
|
||||||
let $httpBackend,
|
let $httpBackend,
|
||||||
QuerySet,
|
QuerySet,
|
||||||
Authorization;
|
Authorization,
|
||||||
|
SmartSearchService;
|
||||||
|
|
||||||
beforeEach(angular.mock.module('Tower', ($provide) =>{
|
beforeEach(angular.mock.module('Tower', ($provide) =>{
|
||||||
// @todo: improve app source / write testing utilities for interim
|
// @todo: improve app source / write testing utilities for interim
|
||||||
@@ -17,9 +18,10 @@ describe('Service: QuerySet', () => {
|
|||||||
}));
|
}));
|
||||||
beforeEach(angular.mock.module('RestServices'));
|
beforeEach(angular.mock.module('RestServices'));
|
||||||
|
|
||||||
beforeEach(angular.mock.inject((_$httpBackend_, _QuerySet_) => {
|
beforeEach(angular.mock.inject((_$httpBackend_, _QuerySet_, _SmartSearchService_) => {
|
||||||
$httpBackend = _$httpBackend_;
|
$httpBackend = _$httpBackend_;
|
||||||
QuerySet = _QuerySet_;
|
QuerySet = _QuerySet_;
|
||||||
|
SmartSearchService = _SmartSearchService_;
|
||||||
|
|
||||||
// @todo: improve app source
|
// @todo: improve app source
|
||||||
// config.js / local_settings emit $http requests in the app's run block
|
// config.js / local_settings emit $http requests in the app's run block
|
||||||
@@ -33,24 +35,27 @@ describe('Service: QuerySet', () => {
|
|||||||
.respond(200, '');
|
.respond(200, '');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('fn encodeQuery', () => {
|
describe('fn encodeParam', () => {
|
||||||
xit('null/undefined params should return an empty string', () => {
|
it('should encode parameters properly', () =>{
|
||||||
expect(QuerySet.encodeQuery(null)).toEqual('');
|
expect(QuerySet.encodeParam({term: "name:foo", searchTerm: true})).toEqual({"name__icontains_DEFAULT" : "foo"});
|
||||||
expect(QuerySet.encodeQuery(undefined)).toEqual('');
|
expect(QuerySet.encodeParam({term: "-name:foo", searchTerm: true})).toEqual({"not__name__icontains_DEFAULT" : "foo"});
|
||||||
|
expect(QuerySet.encodeParam({term: "name:'foo bar'", searchTerm: true})).toEqual({"name__icontains_DEFAULT" : "'foo bar'"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-name:'foo bar'", searchTerm: true})).toEqual({"not__name__icontains_DEFAULT" : "'foo bar'"});
|
||||||
|
expect(QuerySet.encodeParam({term: "organization:foo", relatedSearchTerm: true})).toEqual({"organization__search_DEFAULT" : "foo"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-organization:foo", relatedSearchTerm: true})).toEqual({"not__organization__search_DEFAULT" : "foo"});
|
||||||
|
expect(QuerySet.encodeParam({term: "organization.name:foo", relatedSearchTerm: true})).toEqual({"organization__name" : "foo"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-organization.name:foo", relatedSearchTerm: true})).toEqual({"not__organization__name" : "foo"});
|
||||||
|
expect(QuerySet.encodeParam({term: "id:11", searchTerm: true})).toEqual({"id__icontains_DEFAULT" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-id:11", searchTerm: true})).toEqual({"not__id__icontains_DEFAULT" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "id:>11", searchTerm: true})).toEqual({"id__gt" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-id:>11", searchTerm: true})).toEqual({"not__id__gt" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "id:>=11", searchTerm: true})).toEqual({"id__gte" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-id:>=11", searchTerm: true})).toEqual({"not__id__gte" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "id:<11", searchTerm: true})).toEqual({"id__lt" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-id:<11", searchTerm: true})).toEqual({"not__id__lt" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "id:<=11", searchTerm: true})).toEqual({"id__lte" : "11"});
|
||||||
|
expect(QuerySet.encodeParam({term: "-id:<=11", searchTerm: true})).toEqual({"not__id__lte" : "11"});
|
||||||
});
|
});
|
||||||
xit('should encode params to a string', () => {
|
|
||||||
let params = {
|
|
||||||
or__created_by: 'Jenkins',
|
|
||||||
or__modified_by: 'Jenkins',
|
|
||||||
and__not__status: 'success',
|
|
||||||
},
|
|
||||||
result = '?or__created_by=Jenkins&or__modified_by=Jenkins&and__not__status=success';
|
|
||||||
expect(QuerySet.encodeQuery(params)).toEqual(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
xdescribe('fn decodeQuery', () => {
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
43
awx/ui/tests/spec/smart-search/smart-search.service-test.js
Normal file
43
awx/ui/tests/spec/smart-search/smart-search.service-test.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('Service: SmartSearch', () => {
|
||||||
|
let SmartSearchService;
|
||||||
|
|
||||||
|
beforeEach(angular.mock.module('Tower'));
|
||||||
|
|
||||||
|
beforeEach(angular.mock.module('SmartSearchModule'));
|
||||||
|
|
||||||
|
beforeEach(angular.mock.inject((_SmartSearchService_) => {
|
||||||
|
SmartSearchService = _SmartSearchService_;
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('fn splitSearchIntoTerms', () => {
|
||||||
|
it('should convert the search string to an array tag strings', () =>{
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('foo')).toEqual(["foo"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('foo bar')).toEqual(["foo", "bar"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:foo bar')).toEqual(["name:foo", "bar"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:foo description:bar')).toEqual(["name:foo", "description:bar"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:"foo bar"')).toEqual(["name:\"foo bar\""]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:"foo bar" description:"bar foo"')).toEqual(["name:\"foo bar\"", "description:\"bar foo\""]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:"foo bar" description:"bar foo"')).toEqual(["name:\"foo bar\"", "description:\"bar foo\""]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:\'foo bar\'')).toEqual(["name:\'foo bar\'"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:\'foo bar\' description:\'bar foo\'')).toEqual(["name:\'foo bar\'", "description:\'bar foo\'"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:\'foo bar\' description:\'bar foo\'')).toEqual(["name:\'foo bar\'", "description:\'bar foo\'"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:\"foo bar\" description:\'bar foo\'')).toEqual(["name:\"foo bar\"", "description:\'bar foo\'"]);
|
||||||
|
expect(SmartSearchService.splitSearchIntoTerms('name:\"foo bar\" foo')).toEqual(["name:\"foo bar\"", "foo"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fn splitTermIntoParts', () => {
|
||||||
|
it('should convert the search term to a key and value', () =>{
|
||||||
|
expect(SmartSearchService.splitTermIntoParts('foo')).toEqual(["foo"]);
|
||||||
|
expect(SmartSearchService.splitTermIntoParts('foo:bar')).toEqual(["foo", "bar"]);
|
||||||
|
expect(SmartSearchService.splitTermIntoParts('foo:bar:foobar')).toEqual(["foo", "bar:foobar"]);
|
||||||
|
expect(SmartSearchService.splitTermIntoParts('name:\"foo bar\"')).toEqual(["name", "\"foo bar\""]);
|
||||||
|
expect(SmartSearchService.splitTermIntoParts('name:\"foo:bar\"')).toEqual(["name", "\"foo:bar\""]);
|
||||||
|
expect(SmartSearchService.splitTermIntoParts('name:\'foo bar\'')).toEqual(["name", "\'foo bar\'"]);
|
||||||
|
expect(SmartSearchService.splitTermIntoParts('name:\'foo:bar\'')).toEqual(["name", "\'foo:bar\'"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user