1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-31 15:21:13 +03:00

AC-171 Lastest changes for improving select and lookup workflow. Streamlined selection workflow with helpers/Selection.js. Restored the checkbox and fixed the hover background color on Lookup dialogs. Fixed bug in lookup dialog where most recent selection not showing up when user navigates back to same lookup multiple times. Both selection and lookup now work in an Angular fashion by manipulating the data set to affect view changes rather than attempting to manipulate the DOM within the controller.

This commit is contained in:
chouseknecht 2013-07-17 16:46:26 -04:00
parent bd693f226e
commit 49fd23d84d
12 changed files with 110 additions and 189 deletions

View File

@ -60,7 +60,8 @@ angular.module('ansible', [
'EventsHelper',
'ProjectPathHelper',
'md5Helper',
'AccessHelper'
'AccessHelper',
'SelectionHelper'
])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.

View File

@ -12,7 +12,7 @@
function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, CredentialList,
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
ClearScope, ProcessErrors, GetBasePath)
ClearScope, ProcessErrors, GetBasePath, SelectionInit)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -24,16 +24,7 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res
var scope = view.inject(list, { mode: mode }); // Inject our view
scope.selected = [];
if (scope.PostRefreshRemove) {
scope.PostRefreshRemove();
}
scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
$("tr.success").each(function(index) {
// Make sure no rows have a green background
var ngc = $(this).attr('ng-class');
scope[ngc] = "";
});
});
SelectionInit({ scope: scope, list: list });
SearchInit({ scope: scope, set: 'credentials', list: list, url: defaultUrl });
PaginateInit({ scope: scope, list: list, url: defaultUrl });
@ -125,28 +116,11 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res
ReturnToCaller();
}
}
scope.toggle_credential = function(id) {
if (scope[list.iterator + "_" + id + "_class"] == "success") {
scope[list.iterator + "_" + id + "_class"] = "";
document.getElementById('check_' + id).checked = false;
if (scope.selected.indexOf(id) > -1) {
scope.selected.splice(scope.selected.indexOf(id),1);
}
}
else {
scope[list.iterator + "_" + id + "_class"] = "success";
document.getElementById('check_' + id).checked = true;
if (scope.selected.indexOf(id) == -1) {
scope.selected.push(id);
}
}
}
}
CredentialsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'CredentialList', 'GenerateList',
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
'GetBasePath'];
'GetBasePath', 'SelectionInit'];
function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm,

View File

@ -294,7 +294,7 @@ function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeP
LookUpInit({
scope: scope,
form: form,
current_item: (scope.organization) ? scope.organization : null,
current_item: (scope.organization !== undefined) ? scope.organization : null,
list: OrganizationList,
field: 'organization'
});

View File

@ -25,18 +25,6 @@ function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Re
var scope = view.inject(list, { mode: mode });
$rootScope.flashMessage = null;
scope.selected = [];
if (scope.PostRefreshRemove) {
scope.PostRefreshRemove();
}
scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
$("tr.success").each(function(index) {
// Make sure no rows have a green background
var ngc = $(this).attr('ng-class');
scope[ngc] = "";
});
});
SearchInit({ scope: scope, set: 'job_templates', list: list, url: defaultUrl });
PaginateInit({ scope: scope, list: list, url: defaultUrl });
@ -129,23 +117,6 @@ function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Re
}
}
scope.toggle_job_template = function(id) {
if (scope[list.iterator + "_" + id + "_class"] == "success") {
scope[list.iterator + "_" + id + "_class"] = "";
document.getElementById('check_' + id).checked = false;
if (scope.selected.indexOf(id) > -1) {
scope.selected.splice(scope.selected.indexOf(id),1);
}
}
else {
scope[list.iterator + "_" + id + "_class"] = "success";
document.getElementById('check_' + id).checked = true;
if (scope.selected.indexOf(id) == -1) {
scope.selected.push(id);
}
}
}
scope.submitJob = function(id) {
SubmitJob({ scope: scope, id: id });
}
@ -347,6 +318,9 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route
for (var i=0; i < data.length; i++) {
scope.playbook_options.push(data[i]);
}
if (!scope.$$phase) {
scope.$digest();
}
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,

View File

@ -27,18 +27,7 @@ function OrganizationsList ($scope, $rootScope, $location, $log, Rest, Alert, Lo
$rootScope.flashMessage = null;
LoadBreadCrumbs();
if (scope.PostRefreshRemove) {
scope.PostRefreshRemove();
}
scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
$("tr.success").each(function(index) {
// Make sure no rows have a green background
var ngc = $(this).attr('ng-class');
scope[ngc] = "";
});
});
// Initialize search and paginate pieces and load data
SearchInit({ scope: scope, set: list.name, list: list, url: defaultUrl });
PaginateInit({ scope: scope, list: list, url: defaultUrl });
@ -76,23 +65,6 @@ function OrganizationsList ($scope, $rootScope, $location, $log, Rest, Alert, Lo
action: action
});
}
scope.toggle_organization = function(id) {
if (scope[list.iterator + "_" + id + "_class"] == "success") {
scope[list.iterator + "_" + id + "_class"] = "";
document.getElementById('check_' + id).checked = false;
if (scope.selected.indexOf(id) > -1) {
scope.selected.splice(scope.selected.indexOf(id),1);
}
}
else {
scope[list.iterator + "_" + id + "_class"] = "success";
document.getElementById('check_' + id).checked = true;
if (scope.selected.indexOf(id) == -1) {
scope.selected.push(id);
}
}
}
}
OrganizationsList.$inject=[ '$scope', '$rootScope', '$location', '$log', 'Rest', 'Alert', 'LoadBreadCrumbs', 'Prompt',

View File

@ -12,7 +12,7 @@
function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, ProjectList,
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
ClearScope, ProcessErrors, GetBasePath)
ClearScope, ProcessErrors, GetBasePath, SelectionInit)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -25,16 +25,7 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
scope.selected = [];
$rootScope.flashMessage = null;
if (scope.PostRefreshRemove) {
scope.PostRefreshRemove();
}
scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
$("tr.success").each(function(index) {
// Make sure no rows have a green background
var ngc = $(this).attr('ng-class');
scope[ngc] = "";
});
});
SelectionInit({ scope: scope, list: list });
SearchInit({ scope: scope, set: 'projects', list: list, url: defaultUrl });
PaginateInit({ scope: scope, list: list, url: defaultUrl });
@ -128,28 +119,11 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
ReturnToCaller(1);
}
}
scope.toggle_project = function(id) {
if (scope[list.iterator + "_" + id + "_class"] == "success") {
scope[list.iterator + "_" + id + "_class"] = "";
document.getElementById('check_' + id).checked = false;
if (scope.selected.indexOf(id) > -1) {
scope.selected.splice(scope.selected.indexOf(id),1);
}
}
else {
scope[list.iterator + "_" + id + "_class"] = "success";
document.getElementById('check_' + id).checked = true;
if (scope.selected.indexOf(id) == -1) {
scope.selected.push(id);
}
}
}
}
ProjectsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'ProjectList', 'GenerateList',
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
'GetBasePath' ];
'GetBasePath', 'SelectionInit'];
function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, ProjectsForm,

View File

@ -12,7 +12,7 @@
function TeamsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, TeamList,
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
ClearScope, ProcessErrors, SetTeamListeners, GetBasePath)
ClearScope, ProcessErrors, SetTeamListeners, GetBasePath, SelectionInit)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -23,7 +23,9 @@ function TeamsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Ale
var mode = (paths[0] == 'teams') ? 'edit' : 'select'; // if base path 'teams', we're here to add/edit teams
var scope = view.inject(list, { mode: mode }); // Inject our view
scope.selected = [];
SelectionInit({ scope: scope, list: list });
if (scope.PostRefreshRemove) {
scope.PostRefreshRemove();
}
@ -32,12 +34,6 @@ function TeamsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Ale
for( var i=0; i < scope.teams.length; i++) {
scope.teams[i].organization_name = scope.teams[i].summary_fields.organization.name;
}
$("tr.success").each(function(index) {
// Make sure no rows have a green background
var ngc = $(this).attr('ng-class');
scope[ngc] = "";
});
});
//SetTeamListeners({ scope: scope, set: 'teams', iterator: list.iterator });
@ -145,28 +141,11 @@ function TeamsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Ale
ReturnToCaller();
}
}
scope.toggle_team = function(id) {
if (scope[list.iterator + "_" + id + "_class"] == "success") {
scope[list.iterator + "_" + id + "_class"] = "";
document.getElementById('check_' + id).checked = false;
if (scope.selected.indexOf(id) > -1) {
scope.selected.splice(scope.selected.indexOf(id),1);
}
}
else {
scope[list.iterator + "_" + id + "_class"] = "success";
document.getElementById('check_' + id).checked = true;
if (scope.selected.indexOf(id) == -1) {
scope.selected.push(id);
}
}
}
}
TeamsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'TeamList', 'GenerateList',
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
'SetTeamListeners', 'GetBasePath' ];
'SetTeamListeners', 'GetBasePath', 'SelectionInit'];
function TeamsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm,

View File

@ -12,7 +12,7 @@
function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest,
Alert, UserList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit,
ReturnToCaller, ClearScope, ProcessErrors, GetBasePath)
ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -30,18 +30,9 @@ function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest,
PaginateInit({ scope: scope, list: list, url: defaultUrl });
scope.search(list.iterator);
LoadBreadCrumbs();
if (scope.PostRefreshRemove) {
scope.PostRefreshRemove();
}
scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
// Remove the 'success' class, which makes green or selected rows, from each row
for (var i=0; i < scope[list.name].length; i++) {
scope[list.iterator + '_' + scope[list.name][i].id + '_class'] = '';
}
});
SelectionInit({ scope: scope, list: list });
scope.addUser = function() {
$location.path($location.path() + '/add');
@ -88,7 +79,6 @@ function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest,
// calls are finished.
if (scope.queue.length == scope.selected.length) {
// All the api calls finished
$('input[type="checkbox"]').prop("checked",false);
scope.selected = [];
var errors = 0;
for (var i=0; i < scope.queue.length; i++) {
@ -133,27 +123,11 @@ function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest,
}
}
scope.toggle_user = function(id) {
if (scope[list.iterator + "_" + id + "_class"] == "success") {
scope[list.iterator + "_" + id + "_class"] = "";
document.getElementById('check_' + id).checked = false;
if (scope.selected.indexOf(id) > -1) {
scope.selected.splice(scope.selected.indexOf(id),1);
}
}
else {
scope[list.iterator + "_" + id + "_class"] = "success";
document.getElementById('check_' + id).checked = true;
if (scope.selected.indexOf(id) == -1) {
scope.selected.push(id);
}
}
}
}
UsersList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'UserList', 'GenerateList',
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
'GetBasePath' ];
'GetBasePath', 'SelectionInit'];
function UsersAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, UserForm,

View File

@ -43,7 +43,7 @@ angular.module('LookUpHelper', [ 'RestServices', 'Utilities', 'SearchHelper', 'P
var found = false;
var name;
for (var i=0; i < listScope[list.name].length; i++) {
if (listScope[list.iterator + "_" + listScope[list.name][i].id + "_class"] == "success") {
if (listScope[list.name][i]['checked'] == '1') {
found = true;
scope[field] = listScope[list.name][i].id;
if (scope[form.name + '_form'] && form.fields[field] && form.fields[field].sourceModel) {
@ -72,23 +72,31 @@ angular.module('LookUpHelper', [ 'RestServices', 'Utilities', 'SearchHelper', 'P
}
listScope['toggle_' + list.iterator] = function(id) {
// when user clicks a row, remove 'success' class from all rows except clicked-on row
if (listScope[list.name]) {
for (var i=0; i < listScope[list.name].length; i++) {
listScope[list.iterator + "_" + listScope[list.name][i].id + "_class"] = "";
}
}
if (id != null && id != undefined) {
listScope[list.iterator + "_" + id + "_class"] = "success";
for (var i=0; i < scope[list.name].length; i++) {
if (listScope[list.name][i]['id'] == id) {
listScope[list.name][i]['checked'] = '1';
listScope[list.name][i]['success_class'] = 'success';
}
else {
listScope[list.name][i]['checked'] = '0';
listScope[list.name][i]['success_class'] = '';
}
}
}
SearchInit({ scope: listScope, set: list.name, list: list, url: defaultUrl });
PaginateInit({ scope: listScope, list: list, url: defaultUrl, mode: 'lookup' });
listScope.search(list.iterator);
if (current_item) {
listScope['toggle_' + list.iterator](current_item);
// If user made a selection previously, mark it as selected when modal loads
if (listScope.lookupPostRefreshRemove) {
listScope.lookupPostRefreshRemove();
}
listScope.lookupPostRefreshRemove = scope.$on('PostRefresh', function() {
listScope['toggle_' + list.iterator](scope[field]);
});
listScope.search(list.iterator);
}
}
}]);

View File

@ -0,0 +1,60 @@
/*********************************************
* Copyright (c) 2013 AnsibleWorks, Inc.
*
* SelectionHelper
* Used in list controllers where the list might also be used as a selection list.
*
* SelectionInit( {
* scope: <list scope>,
* list: <list object>
* })
*/
angular.module('SelectionHelper', [])
.factory('SelectionInit', [ function() {
return function(params) {
var scope = params.scope; // form scope
var list = params.list; // list object
scope.selected = []; //array of selected row IDs
// toggle row selection
scope['toggle_' + list.iterator] = function(id) {
for (var i=0; i < scope[list.name].length; i++) {
if (scope[list.name][i]['id'] == id) {
if (scope[list.name][i]['checked'] == '0') {
// select the row
scope[list.name][i]['checked'] = '1';
scope[list.name][i]['success_class'] = 'success';
if (scope.selected.indexOf(id) == -1) {
// add id to the array
scope.selected.push(id);
}
}
else {
// unselect the row
scope[list.name][i]['checked'] = '0';
scope[list.name][i]['success_class'] = '';
if (scope.selected.indexOf(id) > -1) {
// remove id from the array
scope.selected.splice(scope.selected.indexOf(id),1);
}
}
}
}
}
// Initialize our data set after a refresh
if (scope.SelectPostRefreshRemove) {
scope.SelectPostRefreshRemove();
}
scope.SelectPostRefreshRemove = scope.$on('PostRefresh', function() {
scope.selected = [];
for (var i=0; i < scope[list.name].length; i++) {
scope[list.name][i]['checked'] = '0';
scope[list.name][i]['success_class'] = '';
}
});
}
}]);

View File

@ -201,7 +201,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
html += "</th>\n";
}
}
if (options.mode == 'select') {
if (options.mode == 'select' || options.mode == 'lookup') {
html += "<th>Select</th>";
}
else if (options.mode == 'edit') {
@ -213,7 +213,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
// table body
html += "<tbody>\n";
html += "<tr ";
html += (options.mode == 'lookup' || options.mode == 'select') ? "ng-class=\"" + list.iterator + "_\{\{ " + list.iterator + ".id \}\}_class\" " : "";
html += (options.mode == 'lookup' || options.mode == 'select') ? "ng-class=\"" + list.iterator + ".success_class\" " : "";
html += "class=\"" + list.iterator + "_class\" ng-repeat=\"" + list.iterator + " in " + list.name;
html += (list.orderBy) ? " | orderBy:'" + list.orderBy + "'" : "";
html += (list.filterBy) ? " | filter: " + list.filterBy : "";
@ -234,8 +234,12 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
}
}
if (options.mode == 'select' ) {
html += "<td><input type=\"checkbox\" name=\"check_{{" + list.iterator + ".id}}\" id=\"check_{{" + list.iterator + ".id}}\" /></td>";
if (options.mode == 'select' || options.mode == 'lookup') {
//html += "<td><input type=\"checkbox\" name=\"check_{{" + list.iterator + ".id }}\" id=\"check_{{" + list.iterator + ".id}}\" /></td>";
html += "<td><input type=\"checkbox\" ng-model=\"" + list.iterator + ".checked\" name=\"check_{{" +
list.iterator + ".id }}\" ng-true-value=\"1\" ng-false-value=\"0\" id=\"check_{{" + list.iterator + ".id}}\" /></td>";
//ng-click=\"toggle_" + list.iterator +
// "({{ " + list.iterator + ".id }}, true)\"
}

View File

@ -87,6 +87,7 @@
<script src="{{ STATIC_URL }}js/helpers/ProjectPath.js"></script>
<script src="{{ STATIC_URL }}js/helpers/md5.js"></script>
<script src="{{ STATIC_URL }}js/helpers/Access.js"></script>
<script src="{{ STATIC_URL }}js/helpers/Selection.js"></script>
{% endif %}
<!-- <script src="{{ STATIC_URL }}lib/angular/http-auth-interceptor.js"></script> -->
</head>