Latest UI changes. Credential List and Edit working -need to add ask pw option and validation around team vs. user. Lookup dialog is now a generic helper that can be shared by all controllers. Credentials controller is first to use api-loader which reads the \/api and \/api\/v1 to determine base set of urls. And more...

This commit is contained in:
chouseknecht
2013-05-09 23:49:51 -04:00
parent 2cbed11034
commit fdceb46c12
25 changed files with 1218 additions and 65 deletions

View File

@@ -0,0 +1,56 @@
/*********************************************
* Copyright (c) 2013 AnsibleWorks, Inc.
*
*
* Read /api and /api/X to discover all the base paths needed
* to access the primary model objects.
*
*/
angular.module('ApiLoader', ['ngCookies'])
.factory('LoadBasePaths', ['$http', '$rootScope', '$cookieStore', 'ProcessErrors',
function($http, $rootScope, $cookieStore, ProcessErrors) {
return function() {
$http.get('/api/')
.success( function(data, status, headers, config) {
var base = data.current_version;
$http.get(base)
.success( function(data, status, headers, config) {
data['base'] = base;
$rootScope['defaultUrls'] = data;
$cookieStore.remove('api');
$cookieStore.put('api',data); //Preserve in cookie to prevent against
//loss during browser refresh
})
.error ( function(data, status, headers, config) {
$rootScope['defaultUrls'] = { status: 'error' };
ProcessErrors(null, data, status, null,
{ hdr: 'Error', msg: 'Failed to read ' + base + '. GET status: ' + status });
});
})
.error( function(data, status, headers, config) {
$rootScope['defaultUrls'] = { status: 'error' };
ProcessErrors(null, data, status, null,
{ hdr: 'Error', msg: 'Failed to read /api. GET status: ' + status });
});
}
}])
.factory('GetBasePath', ['$rootScope', '$cookieStore', 'LoadBasePaths',
function($rootScope, $cookieStore, LoadBasePaths) {
return function(set) {
var answer;
if ($rootScope['defaultUrls'] == null || $rootScope['defaultUrls'] == undefined) {
// browser refresh must have occurred. use what's in session cookie and refresh
answer = $cookieStore.get('api')[set];
LoadBasePaths();
}
else {
answer = $rootScope['defaultUrls'][set];
}
return answer;
}
}]);

View File

@@ -14,7 +14,8 @@ angular.module('AWDirectives', [])
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift( function(viewValue) {
var password = $('input[name="password"]').val();
var associated = attrs.awpassmatch;
var password = $('input[name="' + associated + '"]').val();
if (viewValue == password) {
// it is valid
ctrl.$setValidity('awpassmatch', true);

View File

@@ -96,6 +96,9 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
if (this.scope[this.form.name + '_form'][fld]) {
this.scope[this.form.name + '_form'][fld].$setPristine();
}
if (this.form.fields[fld].awPassMatch) {
this.scope[this.form.name + '_form'][fld].$setValidity('awpassmatch', true);
}
}
if (this.mode == 'add') {
this.applyDefaults();
@@ -171,7 +174,7 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly) ? "readonly " : "";
html += (field.awPassMatch) ? "awpassmatch " : "";
html += (field.awPassMatch) ? "awpassmatch=\"" + field.associated + "\" " : "";
html += (field.capitalize) ? "capitalize " : "";
html += "/><br />\n";
// Add error messages
@@ -193,6 +196,36 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
}
}
//text type fields
if (field.type == 'textarea') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
html += "<div class=\"control-group\""
html += (field.ngShow) ? this.attr(field,'ngShow') : "";
html += ">\n";
html += "<label class=\"control-label\" for=\"" + fld + '">' + field.label + '</label>' + "\n";
html += "<div class=\"controls\">\n";
html += "<textarea ";
html += this.attr(field, 'rows');
html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" ';
html += (field.ngChange) ? this.attr(field,'ngChange') : "";
html += (field.id) ? this.attr(field,'id') : "";
html += (field.placeholder) ? this.attr(field,'placeholder') : "";
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += (field.readonly) ? "readonly " : "";
html += "></textarea><br />\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
this.form.name + '_form.' + fld + ".$error.required\">A value is required!</span>\n";
}
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
html += "</div>\n";
html += "</div>\n";
}
}
//checkbox
if (field.type == 'checkbox') {
if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
@@ -238,7 +271,7 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
html += (options.mode == 'edit' && field.editRequired) ? "required " : "";
html += (options.mode == 'add' && field.addRequired) ? "required " : "";
html += " readonly />\n";
html += "</div>\n";
html += "</div><br />\n";
// Add error messages
if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
html += "<span class=\"error\" ng-show=\"" + this.form.name + '_form.' + fld + ".$dirty && " +
@@ -294,6 +327,8 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
html += this.buildCollections();
}
console.log(html);
return html;
},

View File

@@ -100,9 +100,8 @@ angular.module('GeneratorHelpers', [])
html += "</select>\n";
}
html += "<div class=\"";
html += (mode != "lookup") ? "page-number pull-right" : "page-number-small";
html += "\" >Page: {{ " + iterator + "Page + 1 }} of {{ " + iterator + "PageCount }}</div>\n";
html += "<div class=\"page-number-small\"";
html += ">Page: {{ " + iterator + "Page + 1 }} of {{ " + iterator + "PageCount }}</div>\n";
html += "</form>\n";
html += "</div>\n";

View File

@@ -7,9 +7,9 @@
*
*/
angular.module('ListGenerator', ['GeneratorHelpers'])
.factory('GenerateList', [ '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget',
function($compile, $rootScope, SearchWidget, PaginateWidget) {
angular.module('ListGenerator', ['GeneratorHelpers',])
.factory('GenerateList', [ '$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget',
function($location, $compile, $rootScope, SearchWidget, PaginateWidget) {
return {
setList: function(list) {
@@ -102,21 +102,17 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
}
//select instructions
if (options.mode == 'select') {
if (list.selectInstructions) {
html += "<div class=\"alert alert-info alert-block\">\n";
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">&times;</button>\n";
html += "<strong>Hint: </strong>" + list.selectInstructions + "\n";
html += "</div>\n"
}
if (options.mode == 'select' && list.selectInstructions) {
html += "<div class=\"alert alert-info alert-block\">\n";
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">&times;</button>\n";
html += "<strong>Hint: </strong>" + list.selectInstructions + "\n";
html += "</div>\n"
}
else {
if (options.mode == 'edit' && list.editInstructions) {
html += "<div class=\"alert alert-info alert-block\">\n";
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">&times;</button>\n";
html += "<strong>Hint: </strong>" + list.editInstructions + "\n";
html += "</div>\n";
}
else if (options.mode == 'edit' && list.editInstructions) {
html += "<div class=\"alert alert-info alert-block\">\n";
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">&times;</button>\n";
html += "<strong>Hint: </strong>" + list.editInstructions + "\n";
html += "</div>\n";
}
if (options.mode != 'lookup') {
@@ -132,13 +128,16 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
if (options.mode != 'lookup') {
//actions
base = $location.path().replace(/^\//,'').split('/')[0];
html += "<div class=\"text-right\">\n";
for (action in list.actions) {
if (list.actions[action].mode == 'all' || list.actions[action].mode == options.mode) {
html += "<button " + this.attr(list.actions[action], 'ngClick') +
this.attr(list.actions[action], 'class');
html += (list.actions[action].awToolTip) ? this.attr(list.actions[action],'awToolTip') : "";
html += " >" + this.icon(list.actions[action].icon) + "</button> ";
if (list.basePaths && list.basePaths.indexOf(base) > -1) {
html += "<button " + this.attr(list.actions[action], 'ngClick') +
this.attr(list.actions[action], 'class');
html += (list.actions[action].awToolTip) ? this.attr(list.actions[action],'awToolTip') : "";
html += " >" + this.icon(list.actions[action].icon) + "</button> ";
}
}
}
if (options.mode == 'select') {
@@ -227,7 +226,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
else {
html += PaginateWidget({ set: list.name, iterator: list.iterator, mini: true });
}
return html;
}

View File

@@ -23,7 +23,9 @@ angular.module('PromptDialog', [])
var scope = dialog.scope();
scope.promptHeader = params.hdr;
scope.promptBody = params.body;
scope.promptBtnClass = (params.class == null || params.class == undefined) ? 'btn-danger' : params.class;
var cls = (params.class == null || params.class == undefined) ? 'btn-danger' : params.class;
$('#prompt-action-btn').addClass(cls); //Use jquery because django template engine conflicts with Angular's
// use of {{...}}
scope.id = params.id;
scope.url = params.url;
scope.promptAction = params.action;

View File

@@ -25,7 +25,7 @@ angular.module('RestServices',['ngCookies','AuthService'])
this.url = this.url.replace(rgx,this.params[key]);
delete this.params[key];
}
}
}
},
get: function(args) {