mirror of
https://github.com/ansible/awx.git
synced 2026-05-24 09:07:45 -02:30
Merge pull request #2138 from mabashian/2126-search-multiple-requests
Fixed issue where search actions were sending two requests
This commit is contained in:
@@ -16,10 +16,99 @@ function SmartSearchController (
|
|||||||
let queryset;
|
let queryset;
|
||||||
let transitionSuccessListener;
|
let transitionSuccessListener;
|
||||||
|
|
||||||
configService.getConfig()
|
const compareParams = (a, b) => {
|
||||||
.then(config => init(config));
|
for (let key in a) {
|
||||||
|
if (!(key in b) || a[key].toString() !== b[key].toString()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let key in b) {
|
||||||
|
if (!(key in a)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
function init (config) {
|
const generateSearchTags = () => {
|
||||||
|
const { singleSearchParam } = $scope;
|
||||||
|
$scope.searchTags = qs.createSearchTagsFromQueryset(queryset, defaults, singleSearchParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
const listenForTransitionSuccess = () => {
|
||||||
|
transitionSuccessListener = $transitions.onSuccess({}, trans => {
|
||||||
|
// State has changed - check to see if this is a param change
|
||||||
|
if (trans.from().name === trans.to().name) {
|
||||||
|
if (!compareParams(trans.params('from')[searchKey], trans.params('to')[searchKey])) {
|
||||||
|
// Params are not the same - we need to update the search. This should only
|
||||||
|
// happen when the user hits the forward/back browser navigation buttons.
|
||||||
|
queryset = trans.params('to')[searchKey];
|
||||||
|
qs.search(path, queryset).then((res) => {
|
||||||
|
$scope.dataset = res.data;
|
||||||
|
$scope.collection = res.data.results;
|
||||||
|
$scope.$emit('updateDataset', res.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.searchTerm = null;
|
||||||
|
generateSearchTags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const isAnsibleFactField = (termParts) => {
|
||||||
|
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
||||||
|
return rootField === 'ansible_facts';
|
||||||
|
};
|
||||||
|
|
||||||
|
const revertSearch = (queryToBeRestored) => {
|
||||||
|
queryset = queryToBeRestored;
|
||||||
|
// 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
|
||||||
|
if (!$scope.querySet) {
|
||||||
|
transitionSuccessListener();
|
||||||
|
$state.go('.', { [searchKey]: queryset })
|
||||||
|
.then(() => listenForTransitionSuccess());
|
||||||
|
}
|
||||||
|
qs.search(path, queryset).then((res) => {
|
||||||
|
if ($scope.querySet) {
|
||||||
|
$scope.querySet = queryset;
|
||||||
|
}
|
||||||
|
$scope.dataset = res.data;
|
||||||
|
$scope.collection = res.data.results;
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.searchTerm = null;
|
||||||
|
|
||||||
|
generateSearchTags();
|
||||||
|
};
|
||||||
|
|
||||||
|
const isFilterableBaseField = (termParts) => {
|
||||||
|
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
||||||
|
const listName = $scope.list.name;
|
||||||
|
const baseFieldPath = `models.${listName}.base.${rootField}`;
|
||||||
|
const isBaseField = _.has($scope, `${baseFieldPath}`);
|
||||||
|
|
||||||
|
const isFilterable = _.get($scope, `${baseFieldPath}.filterable`);
|
||||||
|
const isBaseModelRelatedSearchTermField = (_.get($scope, `${baseFieldPath}.type`) === 'field');
|
||||||
|
|
||||||
|
return isBaseField && !isBaseModelRelatedSearchTermField && isFilterable;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isRelatedField = (termParts) => {
|
||||||
|
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
||||||
|
const listName = $scope.list.name;
|
||||||
|
const baseRelatedTypePath = `models.${listName}.base.${rootField}.type`;
|
||||||
|
|
||||||
|
const isRelatedSearchTermField = (_.contains($scope.models[listName].related, rootField));
|
||||||
|
const isBaseModelRelatedSearchTermField = (_.get($scope, baseRelatedTypePath) === 'field');
|
||||||
|
|
||||||
|
return (isRelatedSearchTermField || isBaseModelRelatedSearchTermField);
|
||||||
|
};
|
||||||
|
|
||||||
|
configService.getConfig()
|
||||||
|
.then(config => {
|
||||||
let version;
|
let version;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -52,7 +141,7 @@ function SmartSearchController (
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
$scope.models = data.models;
|
$scope.models = data.models;
|
||||||
$scope.options = data.options.data;
|
$scope.options = data.options.data;
|
||||||
$scope.keyFields = _.reduce(data.models[$scope.djangoModel].base, function(result, value, key) {
|
$scope.keyFields = _.reduce(data.models[$scope.djangoModel].base, (result, value, key) => {
|
||||||
if (value.filterable) {
|
if (value.filterable) {
|
||||||
result.push(key);
|
result.push(key);
|
||||||
}
|
}
|
||||||
@@ -63,43 +152,6 @@ function SmartSearchController (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function compareParams (a, b) {
|
|
||||||
for (let key in a) {
|
|
||||||
if (!(key in b) || a[key].toString() !== b[key].toString()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let key in b) {
|
|
||||||
if (!(key in a)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transitionSuccessListener) {
|
|
||||||
transitionSuccessListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
transitionSuccessListener = $transitions.onSuccess({}, trans => {
|
|
||||||
// State has changed - check to see if this is a param change
|
|
||||||
if (trans.from().name === trans.to().name) {
|
|
||||||
if (!compareParams(trans.params('from')[searchKey], trans.params('to')[searchKey])) {
|
|
||||||
// Params are not the same - we need to update the search. This should only
|
|
||||||
// happen when the user hits the forward/back browser navigation buttons.
|
|
||||||
queryset = trans.params('to')[searchKey];
|
|
||||||
qs.search(path, queryset).then((res) => {
|
|
||||||
$scope.dataset = res.data;
|
|
||||||
$scope.collection = res.data.results;
|
|
||||||
$scope.$emit('updateDataset', res.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.searchTerm = null;
|
|
||||||
generateSearchTags();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.$on('$destroy', transitionSuccessListener);
|
$scope.$on('$destroy', transitionSuccessListener);
|
||||||
$scope.$watch('disableSearch', disableSearch => {
|
$scope.$watch('disableSearch', disableSearch => {
|
||||||
if (disableSearch) {
|
if (disableSearch) {
|
||||||
@@ -108,66 +160,15 @@ function SmartSearchController (
|
|||||||
$scope.searchPlaceholder = i18n._('Search');
|
$scope.searchPlaceholder = i18n._('Search');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function generateSearchTags () {
|
listenForTransitionSuccess();
|
||||||
const { singleSearchParam } = $scope;
|
|
||||||
$scope.searchTags = qs.createSearchTagsFromQueryset(queryset, defaults, singleSearchParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
function revertSearch (queryToBeRestored) {
|
|
||||||
queryset = queryToBeRestored;
|
|
||||||
// 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
|
|
||||||
if (!$scope.querySet) {
|
|
||||||
$state.go('.', { [searchKey]: queryset });
|
|
||||||
}
|
|
||||||
qs.search(path, queryset).then((res) => {
|
|
||||||
if ($scope.querySet) {
|
|
||||||
$scope.querySet = queryset;
|
|
||||||
}
|
|
||||||
$scope.dataset = res.data;
|
|
||||||
$scope.collection = res.data.results;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.searchTerm = null;
|
|
||||||
|
|
||||||
generateSearchTags();
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.toggleKeyPane = () => {
|
$scope.toggleKeyPane = () => {
|
||||||
$scope.showKeyPane = !$scope.showKeyPane;
|
$scope.showKeyPane = !$scope.showKeyPane;
|
||||||
};
|
};
|
||||||
|
|
||||||
function isAnsibleFactField (termParts) {
|
|
||||||
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
|
||||||
return rootField === 'ansible_facts';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFilterableBaseField (termParts) {
|
|
||||||
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
|
||||||
const listName = $scope.list.name;
|
|
||||||
const baseFieldPath = `models.${listName}.base.${rootField}`;
|
|
||||||
const isBaseField = _.has($scope, `${baseFieldPath}`);
|
|
||||||
|
|
||||||
const isFilterable = _.get($scope, `${baseFieldPath}.filterable`);
|
|
||||||
const isBaseModelRelatedSearchTermField = (_.get($scope, `${baseFieldPath}.type`) === 'field');
|
|
||||||
|
|
||||||
return isBaseField && !isBaseModelRelatedSearchTermField && isFilterable;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRelatedField (termParts) {
|
|
||||||
const rootField = termParts[0].split('.')[0].replace(/^-/, '');
|
|
||||||
const listName = $scope.list.name;
|
|
||||||
const baseRelatedTypePath = `models.${listName}.base.${rootField}.type`;
|
|
||||||
|
|
||||||
const isRelatedSearchTermField = (_.contains($scope.models[listName].related, rootField));
|
|
||||||
const isBaseModelRelatedSearchTermField = (_.get($scope, baseRelatedTypePath) === 'field');
|
|
||||||
|
|
||||||
return (isRelatedSearchTermField || isBaseModelRelatedSearchTermField);
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.addTerms = terms => {
|
$scope.addTerms = terms => {
|
||||||
const { singleSearchParam } = $scope;
|
const { singleSearchParam } = $scope;
|
||||||
const unmodifiedQueryset = _.clone(queryset);
|
const unmodifiedQueryset = _.clone(queryset);
|
||||||
@@ -182,11 +183,13 @@ function SmartSearchController (
|
|||||||
// 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) {
|
||||||
|
transitionSuccessListener();
|
||||||
$state.go('.', { [searchKey]: queryset })
|
$state.go('.', { [searchKey]: queryset })
|
||||||
.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.
|
||||||
delete $stateParams[searchKey].page;
|
delete $stateParams[searchKey].page;
|
||||||
|
listenForTransitionSuccess();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +215,7 @@ function SmartSearchController (
|
|||||||
queryset = qs.removeTermsFromQueryset(queryset, term, isFilterableBaseField, isRelatedField, isAnsibleFactField, singleSearchParam);
|
queryset = qs.removeTermsFromQueryset(queryset, term, isFilterableBaseField, isRelatedField, isAnsibleFactField, singleSearchParam);
|
||||||
|
|
||||||
if (!$scope.querySet) {
|
if (!$scope.querySet) {
|
||||||
|
transitionSuccessListener();
|
||||||
$state.go('.', { [searchKey]: queryset })
|
$state.go('.', { [searchKey]: queryset })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// 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
|
||||||
@@ -219,6 +223,7 @@ function SmartSearchController (
|
|||||||
// that that happened and remove it if it didn't.
|
// that that happened and remove it if it didn't.
|
||||||
const clearedParams = qs.removeTermsFromQueryset($stateParams[searchKey], term, isFilterableBaseField, isRelatedField, isAnsibleFactField, singleSearchParam);
|
const clearedParams = qs.removeTermsFromQueryset($stateParams[searchKey], term, isFilterableBaseField, isRelatedField, isAnsibleFactField, singleSearchParam);
|
||||||
$stateParams[searchKey] = clearedParams;
|
$stateParams[searchKey] = clearedParams;
|
||||||
|
listenForTransitionSuccess();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +251,9 @@ function SmartSearchController (
|
|||||||
queryset = cleared;
|
queryset = cleared;
|
||||||
|
|
||||||
if (!$scope.querySet) {
|
if (!$scope.querySet) {
|
||||||
$state.go('.', { [searchKey]: queryset });
|
transitionSuccessListener();
|
||||||
|
$state.go('.', { [searchKey]: queryset })
|
||||||
|
.then(() => listenForTransitionSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
qs.search(path, queryset)
|
qs.search(path, queryset)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ describe('Directive: Smart Search', () => {
|
|||||||
dom,
|
dom,
|
||||||
$compile,
|
$compile,
|
||||||
$state = {},
|
$state = {},
|
||||||
$stateParams,
|
|
||||||
GetBasePath,
|
GetBasePath,
|
||||||
QuerySet,
|
QuerySet,
|
||||||
ConfigService = {},
|
ConfigService = {},
|
||||||
@@ -44,6 +43,7 @@ describe('Directive: Smart Search', () => {
|
|||||||
translateFilter = jasmine.createSpy('translateFilter');
|
translateFilter = jasmine.createSpy('translateFilter');
|
||||||
i18n = jasmine.createSpy('i18n');
|
i18n = jasmine.createSpy('i18n');
|
||||||
$state = jasmine.createSpyObj('$state', ['go']);
|
$state = jasmine.createSpyObj('$state', ['go']);
|
||||||
|
$state.go.and.callFake(() => { return { then: function(){} }; });
|
||||||
|
|
||||||
$provide.value('ConfigService', ConfigService);
|
$provide.value('ConfigService', ConfigService);
|
||||||
$provide.value('QuerySet', QuerySet);
|
$provide.value('QuerySet', QuerySet);
|
||||||
|
|||||||
Reference in New Issue
Block a user