AC-213 Fixed confusing project path messages, labels and help text.

This commit is contained in:
chouseknecht 2013-07-15 02:24:58 -04:00
parent c6b6198926
commit 1d5cf7fd8c
7 changed files with 111 additions and 48 deletions

View File

@ -389,6 +389,10 @@
color: #da4f49;
}
.job-event-status {
padding-top: 5px;
}
.job-new, input[type="text"].job-new,
.job-canceled, input[type="text"].job-canceled {
color: #778899;

View File

@ -4,7 +4,7 @@
*
* awx-min.js
*
* master-bf73e20, Sat Jul 13 05:56:49 2013 -0400
* master-e27ab4f, Sat Jul 13 06:23:40 2013 -0400
*
*/
var urlPrefix="/static/";
@ -64,8 +64,8 @@ b,c,e){d(u,a,b,f,{hdr:"Error!",msg:"Failed to retrieve event detail: "+p.event_i
y({scope:t,list:e,url:k});t.search(e.iterator);a();t.showEvents=function(b,d){p.setUrl(d);p.get().success(function(d,c,f,e){a({path:"/jobs/"+d.id,title:d.name});h.url("/jobs/"+d.id+"/job_events/?host="+escape(b))}).error(function(a,b,c,f){u(t,a,b,form,{hdr:"Error!",msg:"Failed to lookup last job: "+d+". GET status: "+b})})};t.refresh=function(){t.search(e.iterator)};t.jobDetails=function(){h.path("/jobs/"+c.id)};t.jobEvents=function(){h.path("/jobs/"+c.id+"/job_events")}}
JobHostSummaryList.$inject="$scope $rootScope $location $log $routeParams Rest Alert JobHostList GenerateList LoadBreadCrumbs Prompt SearchInit PaginateInit ReturnToCaller ClearScope ProcessErrors GetBasePath".split(" ");function JobsListCtrl(k,m,h,g,c,p,f,e,l,a,d,b,y,v,A,u,C,t,r,n){A("htmlTemplate");var B=C("jobs");h.path().replace(/^\//,"").split("/");var q=l.inject(e,{mode:"edit"});m.flashMessage=null;q.selected=[];q.PostRefreshRemove&&q.PostRefreshRemove();q.PostRefreshRemove=q.$on("PostRefresh",function(){$("tr.success").each(function(a){a=$(this).attr("ng-class");q[a]=""});for(var a,b=0;b<q[e.name].length;b++)a=new Date(q[e.name][b].created),q[e.name][b].created=n(a)});b({scope:q,set:"jobs",list:e,url:B});y({scope:q,
list:e,url:B});c.inventory__int&&(q[e.iterator+"SearchField"]="inventory",q[e.iterator+"SearchValue"]=c.inventory__int,q[e.iterator+"SearchFieldLabel"]="Inventory ID");q.search(e.iterator);a();q.refreshJob=function(){q.search(e.iterator)};q.editJob=function(b,d){a({path:"/jobs/"+b,title:d});h.path(h.path()+"/"+b)};q.viewEvents=function(b,d){a({path:"/jobs/"+b,title:d});h.path(h.path()+"/"+b+"/job_events")};q.viewSummary=function(b,d){a({path:"/jobs/"+b,title:d});h.path(h.path()+"/"+b+"/job_host_summaries")};
q.deleteJob=function(a,b){p.setUrl(B+a+"/");p.get().success(function(b,c,f,n){var l,g;"pending"==b.status||"running"==b.status?(l=b.related.cancel,g="cancel",b="Cancel Job"):(l=B+a+"/",g="delete",b="Delete Job");d({hdr:b,body:"Are you sure you want to "+g+" job "+a+"?",action:function(){p.setUrl(l);"cancel"==g?p.post().success(function(a,b,d,c){$("#prompt-modal").modal("hide");q.search(e.iterator)}).error(function(a,b,d,c){$("#prompt-modal").modal("hide");u(q,a,b,null,{hdr:"Error!",msg:"Call to "+
l+" failed. POST returned status: "+b})}):p.destroy().success(function(a,b,d,c){$("#prompt-modal").modal("hide");q.search(e.iterator)}).error(function(a,b,d,c){$("#prompt-modal").modal("hide");u(q,a,b,null,{hdr:"Error!",msg:"Call to "+l+" failed. DELETE returned status: "+b})})}})}).error(function(a,b,d,c){u(q,a,b,null,{hdr:"Error!",msg:"Failed to get job details. GET returned status: "+b})})};q.submitJob=function(a,b){r({scope:q,id:a,template:b})}}JobsListCtrl.$inject="$scope $rootScope $location $log $routeParams Rest Alert JobList GenerateList LoadBreadCrumbs Prompt SearchInit PaginateInit ReturnToCaller ClearScope ProcessErrors GetBasePath LookUpInit SubmitJob FormatDate".split(" ");
q.deleteJob=function(a,b){p.setUrl(B+a+"/");p.get().success(function(b,c,f,l){var n,g;"pending"==b.status||"running"==b.status?(n=b.related.cancel,g="cancel",b="Cancel Job"):(n=B+a+"/",g="delete",b="Delete Job");d({hdr:b,body:"Are you sure you want to "+g+" job "+a+"?",action:function(){p.setUrl(n);"cancel"==g?p.post().success(function(a,b,d,c){$("#prompt-modal").modal("hide");q.search(e.iterator)}).error(function(a,b,d,c){$("#prompt-modal").modal("hide");u(q,a,b,null,{hdr:"Error!",msg:"Call to "+
n+" failed. POST returned status: "+b})}):p.destroy().success(function(a,b,d,c){$("#prompt-modal").modal("hide");q.search(e.iterator)}).error(function(a,b,d,c){$("#prompt-modal").modal("hide");u(q,a,b,null,{hdr:"Error!",msg:"Call to "+n+" failed. DELETE returned status: "+b})})}})}).error(function(a,b,d,c){u(q,a,b,null,{hdr:"Error!",msg:"Failed to get job details. GET returned status: "+b})})};q.submitJob=function(a,b){r({scope:q,id:a,template:b})}}JobsListCtrl.$inject="$scope $rootScope $location $log $routeParams Rest Alert JobList GenerateList LoadBreadCrumbs Prompt SearchInit PaginateInit ReturnToCaller ClearScope ProcessErrors GetBasePath LookUpInit SubmitJob FormatDate".split(" ");
function JobsEdit(k,m,h,g,c,p,f,e,l,a,d,b,y,v,A,u,C,t,r,n,B,q,w,z){function E(a){if(null!==a&&""!==a&&void 0!==a){var b=q("projects")+a+"/playbooks/";l.setUrl(b);l.get().success(function(a,b,d,c){s.playbook_options=[];for(b=0;b<a.length;b++)s.playbook_options.push(a[b])}).error(function(a,c,f,e){d(s,a,c,D,{hdr:"Error!",msg:"Failed to get playbook list for "+b+". GET returned status: "+c})})}}u("htmlTemplate");var F=q("jobs"),D=f,s=e.inject(D,{mode:"edit",related:!0});e.reset();var K=g.path().replace(/^\//,
"").split("/")[0],G={},J=p.id,H={};s.statusSearchSpin=!1;s.selectPlaybookUnregister&&s.selectPlaybookUnregister();s.selectPlaybookUnregister=s.$watch("project_name",function(a,b){a!==b&&(""!==b&&null!==b&&void 0!==b)&&(s.playbook=null,E(s.project))});s.jobLoadedRemove&&s.jobLoadedRemove();s.jobLoadedRemove=s.$on("jobLoaded",function(){s[D.name+"ReadOnly"]="new"==s.status?!1:!0;for(var a in H)s.search(H[a].iterator);E(s.project);$("#forks-slider").slider("option","value",s.forks);$("#forks-slider").slider("disable");
l.setUrl(s.template_url);l.get().success(function(a,b,d,c){b=a.host_config_key?"true":"false";s.host_config_key=a.host_config_key;w({scope:s,master:G,check_field:"allow_callbacks",default_val:b});s.callback_url=a.related.callback;$('input[type="checkbox"]').attr("disabled","disabled");$("#host_config_key-gen-btn").attr("disabled","disabled")}).error(function(a,b,c,f){d(s,a,b,D,{hdr:"Error!",msg:"Failed to retrieve job: "+p.id+". GET status: "+b})})});s.job_type_options=[{value:"run",label:"Run"},
@ -150,8 +150,9 @@ label:"Name",type:"text",addRequired:!0,editRequired:!0,capitalize:!1,column:1},
"default":"---",awPopOver:'<p>Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.</p><p>View JSON examples at <a href="http://www.json.org" target="_blank">www.json.org</a></p><p>View YAML examples at <a href="http://www.ansibleworks.com/docs/YAMLSyntax.html" target="_blank">ansibleworks.com</a></p>',dataTitle:"Inventory Variables",dataPlacement:"bottom",column:2}},buttons:{save:{label:"Save",icon:"icon-ok","class":"btn-success",ngClick:"formSave()",ngDisabled:!0},
reset:{ngClick:"formReset()",label:"Reset",icon:"icon-remove",ngDisabled:!0}},related:{groups:{type:"tree",open:!0,actions:{}},hosts:{type:"treeview",title:"{{ groupTitle }}",iterator:"host",actions:{select:{ngClick:"selectHost()",icon:"icon-check",label:"Add Existing Host",awToolTip:"Select existing host",ngHide:"createButtonShow == false","class":"btn btn-pad"},create:{ngClick:"createHost()",icon:"icon-plus",label:"Create New Host",awToolTip:"Create a new host",ngHide:"createButtonShow == false",
"class":"btn-success"}},fields:{name:{key:!0,label:"Host Name",ngClick:"editHost({{ host.id }}, '{{ host.name }}')"},has_active_failures:{label:"Failed jobs?",showValue:!1,ngClick:"showEvents('{{ host.name }}', '{{ host.related.last_job }}')",ngShow:"{{ host.has_active_failures }}",icon:"icon-exclamation-sign","class":"active-failures-{{ host.has_active_failures }}",text:"View failures",searchField:"has_active_failures",searchType:"boolean",searchOptions:[{name:"No",value:0},{name:"Yes",value:1}]}},
fieldActions:{edit:{ngClick:"editHost({{ host.id }}, '{{ host.name }}')",icon:"icon-edit",label:"Edit","class":"btn-success",awToolTip:"Edit host"},"delete":{ngClick:"deleteHost({{ host.id }}, '{{ host.name }}')",icon:"icon-remove",label:"Delete","class":"btn-danger",awToolTip:"Remove host"}}}}});angular.module("JobEventFormDefinition",[]).value("JobEventForm",{editTitle:"{{ id }} - {{ event }}",name:"job_events","class":"horizontal-narrow",well:!1,fields:{event_display:{label:"Event",type:"text",readonly:!0},created:{label:"Created",type:"text",readonly:!0,"class":"span3"},status:{label:"Status",type:"text","class":"job-{{ event_status }}",readonly:!0},host:{label:"Host",type:"text",readonly:!0},status:{label:"Status",type:"text","class":"job-{{ event_status }}",readonly:!0},event_data:{label:"Event Data",
type:"textarea","class":"modal-input-xlarge",rows:10,readonly:!0}},buttons:{},related:{}});angular.module("JobFormDefinition",[]).value("JobForm",{addTitle:"Create Job",editTitle:"{{ name }}",name:"jobs",well:!0,twoColumns:!0,fields:{name:{label:"Name",type:"text",addRequired:!0,editRequired:!0,column:1},description:{label:"Description",type:"text",addRequired:!1,editRequired:!1,column:1},job_type:{label:"Job Type",type:"select",ngOptions:"type.label for type in job_type_options","default":"run",addRequired:!0,editRequired:!0,awPopOver:"<p>When this template is submitted as a job, setting the type to <em>run</em> will execute the playbook, running tasks on the selected hosts.</p> <p>Setting the type to <em>check</em> will not execute the playbook. Instead, ansible will check playbook syntax, test environment setup and report problems.</p>",
fieldActions:{edit:{ngClick:"editHost({{ host.id }}, '{{ host.name }}')",icon:"icon-edit",label:"Edit","class":"btn-success",awToolTip:"Edit host"},"delete":{ngClick:"deleteHost({{ host.id }}, '{{ host.name }}')",icon:"icon-remove",label:"Delete","class":"btn-danger",awToolTip:"Remove host"}}}}});angular.module("JobEventFormDefinition",[]).value("JobEventForm",{editTitle:"{{ id }} - {{ event }}",name:"job_events","class":"horizontal-narrow",well:!1,fields:{created:{label:"Created",type:"text",readonly:!0,"class":"span3",section:"Event Info"},status:{labelClass:"job-{{ status }}",icon:"icon-circle",type:"custom",control:'<div class="job-event-status job-{{ status }}">{{ status }}</div>',section:"Event"},host:{label:"Host",type:"text",readonly:!0,section:"Event"},task:{label:"Task",type:"text",
readonly:!0,section:"Event"},conditional:{label:"Conditional?",type:"checkbox",readonly:!0},msg:{label:"Message",type:"textarea",readonly:!0,section:"Results",rows:5},stdout:{label:"Standard Out",type:"textarea",readonly:!0,section:"Results",rows:5},stderr:{label:"Standard Error",type:"textarea",readonly:!0,section:"Results",rows:5},start:{label:"Start",type:"text",readonly:!0,section:"Timing"},end:{label:"End",type:"text",readonly:!0,section:"Timing"},delta:{label:"Elapsed",type:"text",readonly:!0,
section:"Timing"},module_name:{label:"Name",type:"text",readonly:!0,section:"Module"},module_args:{label:"Arguments",type:"text",readonly:!0,section:"Module"}},buttons:{},related:{}});angular.module("JobFormDefinition",[]).value("JobForm",{addTitle:"Create Job",editTitle:"{{ name }}",name:"jobs",well:!0,twoColumns:!0,fields:{name:{label:"Name",type:"text",addRequired:!0,editRequired:!0,column:1},description:{label:"Description",type:"text",addRequired:!1,editRequired:!1,column:1},job_type:{label:"Job Type",type:"select",ngOptions:"type.label for type in job_type_options","default":"run",addRequired:!0,editRequired:!0,awPopOver:"<p>When this template is submitted as a job, setting the type to <em>run</em> will execute the playbook, running tasks on the selected hosts.</p> <p>Setting the type to <em>check</em> will not execute the playbook. Instead, ansible will check playbook syntax, test environment setup and report problems.</p>",
dataTitle:"Job Type",dataPlacement:"right",column:1},inventory:{label:"Inventory",type:"lookup",sourceModel:"inventory",sourceField:"name",addRequired:!0,editRequired:!0,ngClick:"lookUpInventory()",column:1},project:{label:"Project",type:"lookup",sourceModel:"project",sourceField:"name",addRequired:!0,editRequired:!0,ngClick:"lookUpProject()",column:1},playbook:{label:"Playbook",type:"select",ngOptions:"book for book in playbook_options",id:"playbook-select",addRequired:!0,editRequired:!0,column:1},
credential:{label:"Credential",type:"lookup",sourceModel:"credential",sourceField:"name",ngClick:"lookUpCredential()",addRequired:!1,editRequired:!1,column:2},forks:{label:"Forks",id:"forks-number",type:"number",integer:!0,min:0,max:100,slider:!0,"class":"input-mini","default":"0",addRequired:!1,editRequired:!1,column:2,awPopOver:"<p>The number of parallel or simultaneous processes to use while executing the playbook. Provide a value between 0 and 100. A value of zero will use the ansible default setting of 5 parallel processes.</p>",
dataTitle:"Forks",dataPlacement:"left"},limit:{label:"Limit",type:"text",addRequired:!1,editRequired:!1,column:2,awPopOver:'<p>Provide a host pattern to further constrain the list of hosts that will be managed or affected by the playbook. Multiple patterns can be separated by &#59; &#58; or &#44;</p><p>For more information and examples see the <a href="http://ansible.cc/docs/patterns.html#selecting-targets" target="_blank">Selecting Targets section</a> under Inventory and Patterns in the Ansible documentation.</p>',
@ -175,8 +176,8 @@ title:"Users",iterator:"user",open:!1,actions:{add:{ngClick:"add('users')",label
"class":"btn-danger",awToolTip:"Remove user"}}},admins:{type:"collection",title:"Administrators",iterator:"admin",open:!1,base:"/users",actions:{add:{ngClick:"add('admins')",icon:"icon-plus",label:"Add",awToolTip:"Add new administrator"}},fields:{username:{key:!0,label:"Username"},first_name:{label:"First Name"},last_name:{label:"Last Name"}},fieldActions:{edit:{label:"Edit",ngClick:"edit('users', {{ admin.id }}, '{{ admin.username }}')",icon:"icon-edit","class":"btn-success",awToolTip:"Edit administrator"},
"delete":{label:"Delete",ngClick:"delete('admins', {{ admin.id }}, '{{ admin.username }}', 'administrators')",icon:"icon-remove","class":"btn-danger",awToolTip:"Remove administrator"}}}}});angular.module("PermissionFormDefinition",[]).value("PermissionsForm",{addTitle:"Add Permission",editTitle:"{{ name }}",name:"permission",well:!0,fields:{category:{label:"Permission Type",type:"radio",options:[{label:"Inventory",value:"Inventory"},{label:"Deployment",value:"Deploy"}],ngChange:"selectCategory()"},name:{label:"Name",type:"text",addRequired:!0,editRequired:!0,capitalize:!0},description:{label:"Description",type:"text",addRequired:!1,editRequired:!1},user:{label:"User",type:"hidden"},
team:{label:"Team",type:"hidden"},project:{label:"Project",type:"lookup",sourceModel:"project",sourceField:"name",ngShow:"category == 'Deploy'",ngClick:"lookUpProject()",awRequiredWhen:{variable:"projectrequired",init:"false"}},inventory:{label:"Inventory",type:"lookup",sourceModel:"inventory",sourceField:"name",ngClick:"lookUpInventory()",awRequiredWhen:{variable:"inventoryrequired",init:"true"}},permission_type:{label:"Permission",type:"radio",options:[{label:"Admin",value:"admin",ngShow:"category == 'Inventory'"},
{label:"Read",value:"read",ngShow:"category == 'Inventory'"},{label:"Write",value:"write",ngShow:"category == 'Inventory'"},{label:"Run",value:"run",ngShow:"category == 'Deploy'"},{label:"Check",value:"check",ngShow:"category == 'Deploy'"}],addRequired:!0,editRequired:!0}},buttons:{save:{label:"Save",icon:"icon-ok","class":"btn-success",ngClick:"formSave()",ngDisabled:!0},reset:{ngClick:"formReset()",label:"Reset",icon:"icon-remove",ngDisabled:!0}},related:{}});angular.module("ProjectFormDefinition",[]).value("ProjectsForm",{addTitle:"Create Project",editTitle:"{{ name }}",name:"project",well:!0,fields:{name:{label:"Name",type:"text",addRequired:!0,editRequired:!0,capitalize:!0},description:{label:"Description",type:"text",addRequired:!1,editRequired:!1},base_dir:{label:"Project Base Path",type:"textarea","class":"span6",showonly:!0,awPopOver:"<p>Base path used for locating playbooks. Directories found inside this path will be listed in the Project Path drop-down. Together the base path and selected project path provide the full path used to locate playbooks for this project.</p><p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>",
dataTitle:"Project Base Path",dataPlacement:"right"},local_path:{label:"Project Path",type:"select",id:"local-path-select",ngOptions:"path for path in project_local_paths",addRequired:!0,editRequired:!0,awPopOver:"<p>Select from the list of directories found in the base path.Together the base path and selected project path provide the full path used to locate playbooks for this project.</p><p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>",dataTitle:"Project Path",
{label:"Read",value:"read",ngShow:"category == 'Inventory'"},{label:"Write",value:"write",ngShow:"category == 'Inventory'"},{label:"Run",value:"run",ngShow:"category == 'Deploy'"},{label:"Check",value:"check",ngShow:"category == 'Deploy'"}],addRequired:!0,editRequired:!0}},buttons:{save:{label:"Save",icon:"icon-ok","class":"btn-success",ngClick:"formSave()",ngDisabled:!0},reset:{ngClick:"formReset()",label:"Reset",icon:"icon-remove",ngDisabled:!0}},related:{}});angular.module("ProjectFormDefinition",[]).value("ProjectsForm",{addTitle:"Create Project",editTitle:"{{ name }}",name:"project",well:!0,fields:{name:{label:"Name",type:"text",addRequired:!0,editRequired:!0,capitalize:!0},description:{label:"Description",type:"text",addRequired:!1,editRequired:!1},base_dir:{label:"Project Base Path",type:"textarea","class":"span6",showonly:!0,awPopOver:"<p>Base path used for locating playbooks. Directories found inside this path will be listed in the playbook directory drop-down. Together the base path and selected playbook directory provide the full path used to locate playbooks.</p><p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>",
dataTitle:"Project Base Path",dataPlacement:"right"},local_path:{label:"Playbook Directory",type:"select",id:"local-path-select",ngOptions:"path for path in project_local_paths",addRequired:!0,editRequired:!0,awPopOver:"<p>Select from the list of directories found in the base path.Together the base path and the playbook directory provide the full path used to locate playbooks.</p><p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>",dataTitle:"Project Path",
dataPlacement:"right"}},buttons:{save:{label:"Save",icon:"icon-ok","class":"btn-success",ngClick:"formSave()",ngDisabled:!0},reset:{ngClick:"formReset()",label:"Reset",icon:"icon-remove",ngDisabled:!0}},related:{}});angular.module("TeamFormDefinition",[]).value("TeamForm",{addTitle:"Create Team",editTitle:"{{ name }}",name:"team",well:!0,collapse:!0,collapseTitle:"Team Settings",collapseMode:"edit",collapseOpen:!0,fields:{name:{label:"Name",type:"text",addRequired:!0,editRequired:!0,capitalize:!0},description:{label:"Description",type:"text",addRequired:!1,editRequired:!1},organization:{label:"Organization",type:"lookup",sourceModel:"organization",sourceField:"name",addRequired:!0,editRequired:!0,ngClick:"lookUpOrganization()"}},
buttons:{save:{label:"Save",icon:"icon-ok","class":"btn-success",ngClick:"formSave()",ngDisabled:!0},reset:{ngClick:"formReset()",label:"Reset",icon:"icon-remove",ngDisabled:!0}},related:{credentials:{type:"collection",title:"Credentials",iterator:"credential",open:!1,actions:{add:{ngClick:"add('credentials')",icon:"icon-plus",label:"Add",add:"Add a new credential"}},fields:{name:{key:!0,label:"Name"},description:{label:"Description"}},fieldActions:{edit:{label:"Edit",ngClick:"edit('credentials', {{ credential.id }}, '{{ credential.name }}')",
icon:"icon-edit","class":"btn-success",awToolTip:"Modify the credential"},"delete":{label:"Delete",ngClick:"delete('credentials', {{ credential.id }}, '{{ credential.name }}', 'credentials')",icon:"icon-remove","class":"btn-danger",awToolTip:"Remove the credential"}}},permissions:{type:"collection",title:"Permissions",iterator:"permission",open:!1,actions:{add:{ngClick:"add('permissions')",icon:"icon-plus",label:"Add",awToolTip:"Add a permission for this user"}},fields:{name:{key:!0,label:"Name",
@ -196,8 +197,8 @@ a})}));e||m("Access Denied","You do not have access to this function. Please con
0>=parseInt(g.free_instances)&&h("License Warning",'Your AnsibleWorks AWX License has reached capacity for the number of managed hosts allowed. You will not be able to add any additional hosts. To extend your license, please visit <a href="http://ansibleworks.com/ansibleworks-awx" target="_blank"><strong>ansibleworks.com/ansibleworks-awx.</strong></a>, or contact <a href="mailto:info@ansibleworks.com"><strong>info@ansibleworks.com</strong></a> for more information.',"alert-info",null,!0))}}]);angular.module("APIDefaults",["RestServices","Utilities"]).factory("GetAPIDefaults",["Alert","Rest","$rootScope",function(k,m,h){return function(g){function c(c){var a={};for(id in h.apiDefaults)if(id==c||id.iterator==c){a[id]=defaults[id];break}return a}function k(){if(f=={}&&5>e)e++,setTimeout(1E3,k());else if("success"==f.status)return c(g)}var f={},e=0;return null==h.apiDefaults||void 0==h.apiDefaults?(f={},m.setUrl("/api/v1"),m.get().success(function(c,a,d,b){defaults=c;for(var e in defaults)switch(e){case "organizations":dafaults[e].iterator=
"organization";break;case "jobs":defaults[e].iterator="job";break;case "users":defaults[e].iterator="user";break;case "teams":defaults[e].iterator="team";break;case "hosts":defaults[e].iterator="host";break;case "groups":defaults[e].iterator="group";break;case "projects":defaults[e].iterator="project"}h.apiDefaults=defaults;f={status:"success"}}).error(function(c,a,d,b){f={status:"error",msg:"Call to /api/v1 failed. GET returned status: "+a}}),k()):c(g)}}]);angular.module("ChildrenHelper",["RestServices","Utilities"]).factory("ToggleChildren",["Alert","Rest","GetBasePath","ProcessErrors","FormatDate",function(k,m,h,g,c){return function(c){function f(b){a[b].ngicon="icon-collapse-alt";for(var d=b+1;d<a.length;d++)a[d].parent==a[b].id&&(a[d].show=!0)}function e(b){a[b].ngicon="icon-expand-alt";for(var d=b+1;d<a.length;d++)a[d].parent==a[b].id&&(a[d].show=!1,a[d].related.children&&e(d))}var l=c.id,a=c.scope[c.list.name],d;c=!1;for(var b=0;b<a.length&&!1==
c;b++)a[b].id==l&&(d=b,c=!0);"icon-expand-alt"==a[d].ngicon?f(d):e(d)}}]);angular.module("EventsHelper",["RestServices","Utilities","JobEventFormDefinition"]).factory("EventView",["$rootScope","$location","$log","$routeParams","Rest","Alert","JobEventForm","GenerateForm","Prompt","ProcessErrors","GetBasePath","FormatDate",function(k,m,h,g,c,p,f,e,l,a,d,b){return function(l){var g=l.event_id;l=d("base")+"job_events/"+g+"/";var k=e.inject(f,{mode:"edit",modal:!0,related:!1});e.reset();k.formModalAction=function(){$("#form-modal").modal("hide")};k.formModalActionLabel="OK";
k.formModalHeader="View Event";k.formModalCancelShow=!1;$("#form-modal .btn-success").removeClass("btn-success").addClass("btn-none");c.setUrl(l);c.get().success(function(a,d,c,e){for(var l in f.fields)"status"==l?k.status=a.failed?"error":"success":"event_data"==l?k.event_data=JSON.stringify(a.event_data,void 0,"\t"):"host"==l?a.summary_fields&&a.summary_fields.host&&(k.host=a.summary_fields.host.name):"event_display"==l?k.event_display=a.event_display.replace(/^\u00a0*/g,""):"created"==l?k.created=
b(new Date(a.created)):a[l]&&(k[l]=a[l])}).error(function(b,d,c,e){a(k,b,d,f,{hdr:"Error!",msg:"Failed to retrieve host: "+g+". GET status: "+d})});k.$$phase||k.$digest()}}]);angular.module("GroupsHelper","RestServices Utilities ListGenerator GroupListDefinition SearchHelper PaginateHelper ListGenerator AuthService GroupsHelper InventoryHelper".split(" ")).factory("GroupsList",["$rootScope","$location","$log","$routeParams","Rest","Alert","GroupList","GenerateList","Prompt","SearchInit","PaginateInit","ProcessErrors","GetBasePath","GroupsAdd","RefreshTree",function(k,m,h,g,c,p,f,e,l,a,d,b,y,v,A){return function(b){var l=b.inventory_id,k=void 0!==b.group_id?b.group_id:
k.formModalCancelShow=!1;$("#form-modal .btn-success").removeClass("btn-success").addClass("btn-none");c.setUrl(l);c.get().success(function(a,d,c,e){for(var l in f.fields)"status"==l?k.status=a.failed?"error":a.changed?"changed":"success":"event_data"==l?k.event_data=JSON.stringify(a.event_data,void 0,"\t"):"host"==l?a.summary_fields&&a.summary_fields.host&&(k.host=a.summary_fields.host.name):"created"==l?k.created=b(new Date(a.created)):a[l]&&(k[l]=a[l]);k.formModalHeader=a.event_display.replace(/^\u00a0*/g,
"")}).error(function(b,d,c,e){a(k,b,d,f,{hdr:"Error!",msg:"Failed to retrieve host: "+g+". GET status: "+d})});k.$$phase||k.$digest()}}]);angular.module("GroupsHelper","RestServices Utilities ListGenerator GroupListDefinition SearchHelper PaginateHelper ListGenerator AuthService GroupsHelper InventoryHelper".split(" ")).factory("GroupsList",["$rootScope","$location","$log","$routeParams","Rest","Alert","GroupList","GenerateList","Prompt","SearchInit","PaginateInit","ProcessErrors","GetBasePath","GroupsAdd","RefreshTree",function(k,m,h,g,c,p,f,e,l,a,d,b,y,v,A){return function(b){var l=b.inventory_id,k=void 0!==b.group_id?b.group_id:
null;b=y("inventory")+l+"/groups/";var h=e.inject(f,{id:"form-modal-body",mode:"select",breadCrumbs:!1,selectButton:!1});h.formModalActionLabel="Select";h.formModalHeader="Add Groups";h.formModalCancelShow=!0;h.formModalActionClass="btn btn-success";$(".popover").remove();$("#form-modal .btn-none").removeClass("btn-none").addClass("btn-success");$("#form-modal").modal({backdrop:"static",keyboard:!1});h.selected=[];h.PostRefreshRemove&&h.PostRefreshRemove();h.PostRefreshRemove=h.$on("PostRefresh",
function(){$("tr.success").each(function(a){a=$(this).attr("ng-class");h[a]=""});if(g.group_id)for(var a=0;a<h.groups.length;a++)h.groups[a].id==g.group_id&&h.groups.splice(a,1)});a({scope:h,set:"groups",list:f,url:b});d({scope:h,list:f,url:b,mode:"lookup"});h.search(f.iterator);h.$$phase||h.$digest();h.formModalAction=function(){var a=k?y("groups")+k+"/children/":y("inventory")+l+"/groups/";c.setUrl(a);h.queue=[];h.callFinishedRemove&&h.callFinishedRemove();h.callFinishedRemove=h.$on("callFinished",
function(){if(h.queue.length==h.selected.length){$('input[type="checkbox"]').prop("checked",!1);h.selected=[];for(var a=0,b=0;b<h.queue.length;b++)"error"==h.queue[b].result&&a++;0<a?p("Error","There was an error while adding one or more of the selected groups."):($("#form-modal").modal("hide"),A({scope:h}))}});if(0<h.selected.length)for(var b=0;b<h.selected.length;b++){for(var a=null,d=0;d<h.groups.length;d++)h.groups[d].id==h.selected[b]&&(a=h.groups[d]);null!==a&&c.post(a).success(function(a,b,
@ -211,7 +212,7 @@ y(t);$("#form-modal .btn-none").removeClass("btn-none").addClass("btn-success");
if("object"!==typeof e)throw"failed to return an object!";var l={},n;for(n in f.fields)l[n]=t[n];l.inventory=k;c.setUrl(m);c.put(l).success(function(l,n,g,h){t.variables?(c.setUrl(d("groups")+l.id+"/variable_data/"),c.put(e).success(function(a,d,c,e){$("#form-modal").modal("hide");b({scope:t})}).error(function(b,d,c,e){a(t,b,d,f,{hdr:"Error!",msg:"Failed to update group varaibles. PUT returned status: "+d})})):($("#form-modal").modal("hide"),b({scope:t}))}).error(function(b,d,c,e){a(t,b,d,f,{hdr:"Error!",
msg:"Failed to update group: "+h+". PUT status: "+d})})}catch(g){p("Error","Error parsing group variables. Parser returned: "+g)}};t.formReset=function(){e.reset();for(var a in r)t[a]=r[a];t.parseType="yaml"}}}]).factory("GroupsDelete",["$rootScope","$location","$log","$routeParams","Rest","Alert","GroupForm","GenerateForm","Prompt","ProcessErrors","GetBasePath",function(k,m,h,g,c,p,f,e,l,a,d){return function(b){var e=b.scope,f=b.group_id;b=b.inventory_id;var l=$('#tree-view li[group_id="'+f+'"]'),
g="LI"==l.parent().last().prop("tagName")?l.parent().last():l.parent().parent().last(),h;h="group"==g.attr("type")?d("base")+"groups/"+g.attr("group_id")+"/children/":d("inventory")+b+"/groups/";$("#prompt-header").text("Delete Group");$("#prompt-body").text("Are you sure you want to remove group "+$(l).attr("name")+" from "+$(g).attr("name")+"?");$("#prompt-action-btn").addClass("btn-danger");e.promptAction=function(){c.setUrl(h);c.post({id:f,disassociate:1}).success(function(a,b,d,c){$("#prompt-modal").modal("hide");
$("#tree-view").jstree("delete_node",l)}).error(function(b,d,c,l){$("#prompt-modal").modal("hide");RefreshTree({scope:e});a(e,b,d,null,{hdr:"Error!",msg:"Call to "+h+" failed. DELETE returned status: "+d})})};$("#prompt-modal").modal({backdrop:"static",keyboard:!0,show:!0})}}]);angular.module("HostsHelper","RestServices Utilities ListGenerator HostListDefinition SearchHelper PaginateHelper ListGenerator AuthService HostsHelper InventoryHelper RelatedSearchHelper RelatedPaginateHelper InventoryFormDefinition".split(" ")).factory("HostsList",["$rootScope","$location","$log","$routeParams","Rest","Alert","HostList","GenerateList","Prompt","SearchInit","PaginateInit","ProcessErrors","GetBasePath","HostsAdd","HostsReload",function(k,m,h,g,c,p,f,e,l,a,d,b,y,v,A){return function(b){var l=
$("#tree-view").jstree("delete_node",l)}).error(function(b,d,c,f){$("#prompt-modal").modal("hide");RefreshTree({scope:e});a(e,b,d,null,{hdr:"Error!",msg:"Call to "+h+" failed. DELETE returned status: "+d})})};$("#prompt-modal").modal({backdrop:"static",keyboard:!0,show:!0})}}]);angular.module("HostsHelper","RestServices Utilities ListGenerator HostListDefinition SearchHelper PaginateHelper ListGenerator AuthService HostsHelper InventoryHelper RelatedSearchHelper RelatedPaginateHelper InventoryFormDefinition".split(" ")).factory("HostsList",["$rootScope","$location","$log","$routeParams","Rest","Alert","HostList","GenerateList","Prompt","SearchInit","PaginateInit","ProcessErrors","GetBasePath","HostsAdd","HostsReload",function(k,m,h,g,c,p,f,e,l,a,d,b,y,v,A){return function(b){var l=
b.inventory_id,g=b.group_id;f.iterator="subhost";f.name="subhosts";var h=y("inventory")+l+"/hosts/",n=e.inject(f,{id:"form-modal-body",mode:"select",breadCrumbs:!1,selectButton:!1});n.formModalActionLabel="Select";n.formModalHeader="Select Hosts";n.formModalCancelShow=!0;n.removeHostsReload&&n.removeHostsReload();n.removeHostsReload=n.$on("hostsReload",function(){A(b)});$(".popover").remove();$("#form-modal .btn-none").removeClass("btn-none").addClass("btn-success");$("#form-modal").modal({backdrop:"static",
keyboard:!1});n.selected=[];n.PostRefreshRemove&&n.PostRefreshRemove();n.PostRefreshRemove=n.$on("PostRefresh",function(){$("tr.success").each(function(a){a=$(this).attr("ng-class");n[a]=""})});a({scope:n,set:"subhosts",list:f,url:h});d({scope:n,list:f,url:h,mode:"lookup"});n.search(f.iterator);n.$$phase||n.$digest();n.formModalAction=function(){var a=y("groups")+g+"/hosts/";c.setUrl(a);n.queue=[];n.callFinishedRemove&&n.callFinishedRemove();n.callFinishedRemove=n.$on("callFinished",function(){if(n.queue.length==
n.selected.length){$('input[type="checkbox"]').prop("checked",!1);n.selected=[];for(var a=0,b=0;b<n.queue.length;b++)"error"==n.queue[b].result&&a++;0<a&&p("Error","There was an error while adding one or more of the selected hosts.");$("#form-modal").modal("hide");n.$emit("hostsReload")}});if(0<n.selected.length)for(var b=0;b<n.selected.length;b++){for(var a=null,d=0;d<n.subhosts.length;d++)n.subhosts[d].id==n.selected[b]&&(a=n.subhosts[d]);null!==a&&c.post(a).success(function(a,b,d,c){n.queue.push({result:"success",
@ -248,8 +249,8 @@ d})}))}).error(function(a,d,c,e){l(b,a,d,null,{hdr:"Error!",msg:"Failed to creat
f[d.name][c][l.fields[b].sourceField],e[l.name+"_form"][l.fields[b].sourceModel+"_"+l.fields[b].sourceField]&&e[l.name+"_form"][l.fields[b].sourceModel+"_"+l.fields[b].sourceField].$setValidity("awlookup",!0)),e[l.name+"_form"]&&e[l.name+"_form"].$setDirty(),h.hide());!1==a?k("Missing Selection","Oops, you failed to make a selection. Click on a row to make your selection, and then click the Select button."):m&&m()};f["toggle_"+d.iterator]=function(a){if(f[d.name])for(var b=0;b<f[d.name].length;b++)f[d.iterator+
"_"+f[d.name][b].id+"_class"]="";null!=a&&void 0!=a&&(f[d.iterator+"_"+a+"_class"]="success")};g({scope:f,set:d.name,list:d,url:A});c({scope:f,list:d,url:A,mode:"lookup"});f.search(d.iterator);if(a)f["toggle_"+d.iterator](a)}}}]);angular.module("md5Helper",["RestServices","Utilities"]).factory("md5Setup",["Alert","Rest","GetBasePath","ProcessErrors",function(k,m,h,g){return function(c){var g=c.scope,f=c.master,e=c.check_field;c=c.default_val;g[e]=c;f[e]=c;g.genMD5=function(c){g[c]=$.md5("AnsibleWorks"+(new Date).getTime())};g.toggleCallback=function(c){"false"==g.allow_callbacks&&(g[c]=null)};g.selectAll=function(c){$('input[name="'+c+'"]').focus().select()}}}]);angular.module("PaginateHelper",["RefreshHelper","ngCookies"]).factory("PaginateInit",["Refresh","$cookieStore",function(k,m){return function(h){var g=h.scope,c=h.list,c=h.iterator?h.iterator:c.iterator,p=h.url,f=h.mode?h.mode:null,e=m.get(c+"PageSize");g[c+"Page"]=0;g[c+"PageSize"]=e&&"lookup"!=f?e:h.pageSize?h.pageSize:"lookup"==f?5:20;g.nextSet=function(c,a){g[a+"NextUrl"]&&(g[a+"Page"]++,k({scope:g,set:c,iterator:a,url:g[a+"NextUrl"]}))};g.prevSet=function(c,a){g[a+"PrevUrl"]&&(g[a+"Page"]--,
k({scope:g,set:c,iterator:a,url:g[a+"PrevUrl"]}))};g.changePageSize=function(c,a){m.put(a+"PageSize",g[a+"PageSize"]);g[a+"Page"]=0;var d=p.replace(/\?page_size\=\d+/,""),b=/\/$/.test(d)?"?":"&",d=d+(g[a+"SearchParams"]?b+g[a+"SearchParams"]+"&page_size="+g[a+"PageSize"]:+b+"page_size="+g[a+"PageSize"]);k({scope:g,set:c,iterator:a,url:d})}}}]);angular.module("ParseHelper",[]).factory("ParseTypeChange",[function(){return function(k,m,h){var g=m?m:"variables";m=h?h:"parseType";k.blockParseTypeWatch=!1;k.blockVariableDataWatch=!1;k.removeParseTypeWatch&&k.removeParseTypeWatch();k.removeParseTypeWatch=k.$watch(m,function(c,h){if(c!==h)if("json"==c)if(k[g]&&!/^---$/.test(k[g]))try{var f=jsyaml.load(k[g]);k[g]=JSON.stringify(f,null," ")}catch(e){}else k[g]="{}";else if(k[g]&&!/^\{\}$/.test(k[g]))try{f=JSON.parse(k[g]),k[g]=jsyaml.safeDump(f)}catch(l){}else k[g]=
"---"})}}]);angular.module("ProjectPathHelper",["RestServices","Utilities"]).factory("GetProjectPath",["Alert","Rest","GetBasePath","ProcessErrors",function(k,m,h,g){return function(c){var p=c.scope,f=c.master;m.setUrl(h("config"));m.get().success(function(c,l,a,d){l=[];for(a=0;a<c.project_local_paths.length;a++)l.push(c.project_local_paths[a]);p.local_path&&l.push(p.local_path);p.project_local_paths=l;p.base_dir=c.project_base_dir;f.base_dir=p.base_dir;0==l.length&&k("Missing project path","All of the project paths have been assigned to existing projects, or there are no directories found in the base path. You will need to add a project path before creating a new project.",
"alert-info")}).error(function(c,l,a,d){g(p,c,l,null,{hdr:"Error!",msg:"Failed to access API config. GET status: "+l})})}}]);angular.module("RefreshRelatedHelper",["RestServices","Utilities"]).factory("RefreshRelated",["Alert","Rest",function(k,m){return function(h){var g=h.scope,c=h.set,p=h.iterator;m.setUrl(h.url);m.get().success(function(f,e,l,a){g[c]=f.results;g[p+"NextUrl"]=f.next;g[p+"PrevUrl"]=f.previous;g[p+"Count"]=f.count;g[p+"PageCount"]=Math.ceil(f.count/g[p+"PageSize"]);g[p+"SearchSpin"]=!1;g[p+"Loading"]=!1}).error(function(f,e,l,a){g[p+"SearchSpin"]=!0;k("Error!","Failed to retrieve related set: "+c+". GET returned status: "+
"---"})}}]);angular.module("ProjectPathHelper",["RestServices","Utilities"]).factory("GetProjectPath",["Alert","Rest","GetBasePath","ProcessErrors",function(k,m,h,g){return function(c){var p=c.scope,f=c.master;m.setUrl(h("config"));m.get().success(function(c,l,a,d){l=[];for(a=0;a<c.project_local_paths.length;a++)l.push(c.project_local_paths[a]);p.local_path&&l.push(p.local_path);p.project_local_paths=l;p.base_dir=c.project_base_dir;f.base_dir=p.base_dir;0==l.length&&k("Missing Playbooks","<p>There are no unassigned playbook directories in the base project path ("+
p.base_dir+"). Either the project directory is empty, or all of the contents are already assigned to other AWX projects.</p><p>To fix this, log into the AWX server and check out another playbook project from your SCM repository into "+p.base_dir+".</p>","alert-info")}).error(function(c,l,a,d){g(p,c,l,null,{hdr:"Error!",msg:"Failed to access API config. GET status: "+l})})}}]);angular.module("RefreshRelatedHelper",["RestServices","Utilities"]).factory("RefreshRelated",["Alert","Rest",function(k,m){return function(h){var g=h.scope,c=h.set,p=h.iterator;m.setUrl(h.url);m.get().success(function(f,e,l,a){g[c]=f.results;g[p+"NextUrl"]=f.next;g[p+"PrevUrl"]=f.previous;g[p+"Count"]=f.count;g[p+"PageCount"]=Math.ceil(f.count/g[p+"PageSize"]);g[p+"SearchSpin"]=!1;g[p+"Loading"]=!1}).error(function(f,e,l,a){g[p+"SearchSpin"]=!0;k("Error!","Failed to retrieve related set: "+c+". GET returned status: "+
e)})}}]);angular.module("RefreshHelper",["RestServices","Utilities"]).factory("Refresh",["Alert","Rest",function(k,m){return function(h){var g=h.scope,c=h.set,p=h.iterator;m.setUrl(h.url);m.get().success(function(f,e,l,a){g[p+"NextUrl"]=f.next;g[p+"PrevUrl"]=f.previous;g[p+"Count"]=f.count;g[p+"PageCount"]=Math.ceil(f.count/g[p+"PageSize"]);g[p+"SearchSpin"]=!1;g[p+"Loading"]=!1;g[c]=f.results;g.$emit("PostRefresh")}).error(function(f,e,l,a){g[p+"SearchSpin"]=!1;k("Error!","Failed to retrieve "+c+". GET returned status: "+
e)})}}]);angular.module("RelatedPaginateHelper",["RefreshRelatedHelper","ngCookies"]).factory("RelatedPaginateInit",["RefreshRelated","$cookieStore",function(k,m){return function(h){var g=h.scope,c=h.relatedSets,p;for(p in c)(cookieSize=m.get(c[p].iterator+"PageSize"))?g[c[p].iterator+"PageSize"]=cookieSize:(g[c[p].iterator+"Page"]=0,g[c[p].iterator+"PageSize"]=10);g.nextSet=function(c,e){g[e+"Page"]++;k({scope:g,set:c,iterator:e,url:g[e+"NextUrl"]})};g.prevSet=function(c,e){g[e+"Page"]--;k({scope:g,set:c,
iterator:e,url:g[e+"PrevUrl"]})};g.changePageSize=function(f,e){var l;g[e+"Page"]=0;for(var a in c)if(a==f){l=c[a].url;break}m.put(e+"PageSize",g[e+"PageSize"]);l=l.replace(/\/\?.*$/,"/");l+=g[e+"SearchParams"]?g[e+"SearchParams"]+"&page_size="+g[e+"PageSize"]:"?page_size="+g[e+"PageSize"];k({scope:g,set:f,iterator:e,url:l})}}}]);angular.module("RelatedSearchHelper",["RestServices","Utilities","RefreshRelatedHelper"]).factory("RelatedSearchInit",["Alert","Rest","RefreshRelated",function(k,m,h){return function(g){var c=g.scope,k=g.relatedSets,f=g.form,e,l;for(l in f.related)if("tree"!=f.related[l].type){g=f.related[l].iterator;for(var a in f.related[l].fields)if(f.related[l].fields[a].key){c[g+"SearchField"]=a;c[g+"SearchFieldLabel"]=f.related[l].fields[a].label;break}c[g+"SortOrder"]=null;c[g+"SearchType"]="contains";c[g+
@ -327,9 +328,9 @@ if("radio"==a.type&&(!a.readonly||a.readonly&&"edit"==d.mode)){for(var b=b+'<div
c+'_api_error"></span></p>\n';b+="</div>\n";b+="</div>\n"}if("hidden"==a.type&&("edit"==d.mode&&a.includeOnEdit||"add"==d.mode&&a.includeOnAdd))b+='<input type="hidden" ng-model="'+c+'" name="'+c+'" />';if("lookup"==a.type&&(void 0==a.excludeMode||a.excludeMode!=d.mode)){b+='<div class="control-group"';b+=a.ngShow?this.attr(a,"ngShow"):"";b+=">\n";b+='<label class="control-label" for="'+c+'">';b+=a.awPopOver?this.attr(a,"awPopOver"):"";b+=a.label+"</label>\n";b+='<div class="controls">\n';b+='<div class="input-prepend">\n';
b+='<button class="lookup-btn btn" '+this.attr(a,"ngClick")+'><i class="icon-search"></i></button>\n';b+='<input class="input-medium" type="text" ';b+='ng-model="'+a.sourceModel+"_"+a.sourceField+'" ';b+='name="'+a.sourceModel+"_"+a.sourceField+'" ';b+=a.ngChange?this.attr(a,"ngChange"):"";b+=a.id?this.attr(a,"id"):"";b+=a.placeholder?this.attr(a,"placeholder"):"";b+="edit"==d.mode&&a.editRequired?"required ":"";b+=a.awRequiredWhen?'data-awrequired-init="'+a.awRequiredWhen.init+'" aw-required-when="'+
a.awRequiredWhen.variable+'" ':"";b+=" awlookup />\n";b+="</div><br />\n";if("add"==d.mode&&a.addRequired||"edit"==d.mode&&a.editRequired||a.awRequiredWhen)b+='<span class="error" ng-show="'+this.form.name+"_form."+a.sourceModel+"_"+a.sourceField+".$dirty && "+this.form.name+"_form."+a.sourceModel+"_"+a.sourceField+'.$error.required">A value is required!</span>\n';b+='<span class="error" ng-show="'+this.form.name+"_form."+a.sourceModel+"_"+a.sourceField+".$dirty && "+this.form.name+"_form."+a.sourceModel+
"_"+a.sourceField+'.$error.awlookup">Value not found</span>\n';b+='<span class="error api-error" ng-bind="'+a.sourceModel+"_"+a.sourceField+'_api_error"></span>\n';b+="</div>\n";b+="</div>\n"}if("custom"==a.type&&(!a.readonly||a.readonly&&"edit"==d.mode))b+='<div class="control-group"',b+=a.ngShow?this.attr(a,"ngShow"):"",b+=">\n",b+='<label class="control-label',b+=a.labelClass?" "+a.labelClass:"",b+='" for="'+c+'">',b+=a.awPopOver?this.attr(a,"awPopOver"):"",b+=a.icon?this.icon(a.icon):"",b+=a.label+
"</label>\n",b+='<div class="controls">\n',b+=a.control,b+="</div>\n",b+="</div>\n";return b},build:function(c){var a="";this.modal||(a+='<div class="nav-path">\n<ul class="breadcrumb">\n',a+='<li ng-repeat="crumb in breadcrumbs"><a href="{{ \'#\' + crumb.path }}">{{ crumb.title | capitalize }}</a> <span class="divider">/</span></li>\n',a+='<li class="active">',a="edit"==c.mode?a+this.form.editTitle:a+this.form.addTitle,a+="</li>\n</ul>\n</div>\n");if(!this.modal&&this.form.statusFields){a+='<div class="well">\n';
if(this.form.statusActions){var a=a+'<div class="status-actions">\n',d;for(action in this.form.statusActions)d=this.form.statusActions[action],a+="<button "+this.attr(d,"ngClick")+'class="btn btn-small',a+=d["class"]?" "+d["class"]:"",a+='" ',a+=d.awToolTip?this.attr(d,"awToolTip"):"",a+=d.awToolTip?'data-placement="top" ':"",a+=" >"+this.icon(d.icon),a+=d.label?d.label:"",a+="</button> ";a+="</div>\n";a+='<div class="status-spin"><i class="icon-spinner icon-spin" ng-show="statusSearchSpin == true"></i></div>\n'}var a=
"_"+a.sourceField+'.$error.awlookup">Value not found</span>\n';b+='<span class="error api-error" ng-bind="'+a.sourceModel+"_"+a.sourceField+'_api_error"></span>\n';b+="</div>\n";b+="</div>\n"}if("custom"==a.type&&(!a.readonly||a.readonly&&"edit"==d.mode))b+='<div class="control-group"',b+=a.ngShow?this.attr(a,"ngShow"):"",b+=">\n",b+='<label class="control-label',b+=a.labelClass?" "+a.labelClass:"",b+='" for="'+c+'">',b+=a.awPopOver?this.attr(a,"awPopOver"):"",b+=a.icon?this.icon(a.icon):"",b+=a.label?
a.label:"",b+="</label>\n",b+='<div class="controls">\n',b+=a.control,b+="</div>\n",b+="</div>\n";return b},build:function(c){var a="";this.modal||(a+='<div class="nav-path">\n<ul class="breadcrumb">\n',a+='<li ng-repeat="crumb in breadcrumbs"><a href="{{ \'#\' + crumb.path }}">{{ crumb.title | capitalize }}</a> <span class="divider">/</span></li>\n',a+='<li class="active">',a="edit"==c.mode?a+this.form.editTitle:a+this.form.addTitle,a+="</li>\n</ul>\n</div>\n");if(!this.modal&&this.form.statusFields){a+=
'<div class="well">\n';if(this.form.statusActions){var a=a+'<div class="status-actions">\n',d;for(action in this.form.statusActions)d=this.form.statusActions[action],a+="<button "+this.attr(d,"ngClick")+'class="btn btn-small',a+=d["class"]?" "+d["class"]:"",a+='" ',a+=d.awToolTip?this.attr(d,"awToolTip"):"",a+=d.awToolTip?'data-placement="top" ':"",a+=" >"+this.icon(d.icon),a+=d.label?d.label:"",a+="</button> ";a+="</div>\n";a+='<div class="status-spin"><i class="icon-spinner icon-spin" ng-show="statusSearchSpin == true"></i></div>\n'}var a=
a+'<div class="status-fields">\n',b;for(b in this.form.statusFields)d=this.form.statusFields[b],a+=this.buildField(b,d,c);a+="</div>\x3c!-- status fields --\x3e\n";a+="</div>\x3c!-- well --\x3e\n"}if(this.form.fieldsAsHeader){a+='<div class="well">\n';a+='<form class="form-inline" name="'+this.form.name+'_form" id="'+this.form.name+'" novalidate >\n';for(b in this.form.fields)d=this.form.fields[b],a+=this.headerField(b,d,c);a+="</form>\n";a+="</div>\n"}else{this.form.collapse&&this.form.collapseMode==
c.mode&&(a+='<div id="'+this.form.name+'-collapse-0" ',a+=this.form.collapseOpen?'data-open="true" ':"",a+='class="jqui-accordion">\n',a+="<h3>"+this.form.collapseTitle+"<h3>\n",a+="<div>\n");this.has("well")&&(a+='<div class="well">\n');a+='<form class="form-horizontal';a+=this.form["class"]?" "+this.form["class"]:"";a+='" name="'+this.form.name+'_form" id="'+this.form.name+'" autocomplete="false" novalidate>\n';a+='<div ng-show="flashMessage != null && flashMessage != undefined" class="alert alert-info">{{ flashMessage }}</div>\n';
if(this.form.twoColumns){a+='<div class="row-fluid">\n';a+='<div class="span6">\n';for(b in this.form.fields)d=this.form.fields[b],1==d.column&&(a+=this.buildField(b,d,c));a+="</div>\x3c!-- column 1 --\x3e\n";a+='<div class="span6">\n';for(b in this.form.fields)d=this.form.fields[b],2==d.column&&(a+=this.buildField(b,d,c));a+="</div>\x3c!-- column 2 --\x3e\n";a+="</div>\x3c!-- inner row --\x3e\n"}else for(b in this.form.fields)d=this.form.fields[b],a+=this.buildField(b,d,c);if(!this.modal){this.has("buttons")&&

View File

@ -16,40 +16,87 @@ angular.module('JobEventFormDefinition', [])
well: false,
fields: {
event_display: {
label: 'Event',
type: 'text',
readonly: true
},
created: {
label: 'Created',
type: 'text',
readonly: true,
"class": 'span3'
"class": 'span3',
section: 'Event Info'
},
status: {
label: 'Status',
type: 'text',
"class": 'job-\{\{ event_status \}\}',
readonly: true
status: {
labelClass: 'job-\{\{ status \}\}',
icon: 'icon-circle',
type: 'custom',
control: '<div class=\"job-event-status job-\{\{ status \}\}\">\{\{ status \}\}</div>',
section: 'Event'
},
host: {
label: 'Host',
type: 'text',
readonly: true
readonly: true,
section: 'Event'
},
status: {
label: 'Status',
task: {
label: 'Task',
type: 'text',
"class": 'job-\{\{ event_status \}\}',
readonly: true,
section: 'Event'
},
conditional: {
label: 'Conditional?',
type: 'checkbox',
readonly: true
},
event_data: {
label: 'Event Data',
msg: {
label: 'Message',
type: 'textarea',
"class": "modal-input-xlarge",
rows: 10,
readonly: true
readonly: true,
section: 'Results',
rows: 5
},
stdout: {
label: 'Standard Out',
type: 'textarea',
readonly: true,
section: 'Results',
rows: 5
},
stderr: {
label: 'Standard Error',
type: 'textarea',
readonly: true,
section: 'Results',
rows: 5
},
start: {
label: 'Start',
type: 'text',
readonly: true,
section: 'Timing'
},
end: {
label: 'End',
type: 'text',
readonly: true,
section: 'Timing'
},
delta: {
label: 'Elapsed',
type: 'text',
readonly: true,
section: 'Timing'
},
module_name: {
label: 'Name',
type: 'text',
readonly: true,
section: 'Module'
},
module_args: {
label: 'Arguments',
type: 'text',
readonly: true,
section: 'Module'
}
},

View File

@ -35,21 +35,21 @@ angular.module('ProjectFormDefinition', [])
type: 'textarea',
"class": 'span6',
showonly: true,
awPopOver: '<p>Base path used for locating playbooks. Directories found inside this path will be listed in the Project Path drop-down. ' +
'Together the base path and selected project path provide the full path used to locate playbooks for this project.</p>' +
awPopOver: '<p>Base path used for locating playbooks. Directories found inside this path will be listed in the playbook directory drop-down. ' +
'Together the base path and selected playbook directory provide the full path used to locate playbooks.</p>' +
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
dataTitle: 'Project Base Path',
dataPlacement: 'right'
},
local_path: {
label: 'Project Path',
label: 'Playbook Directory',
type: 'select',
id: 'local-path-select',
ngOptions: 'path for path in project_local_paths',
addRequired: true,
editRequired: true,
awPopOver: '<p>Select from the list of directories found in the base path.' +
'Together the base path and selected project path provide the full path used to locate playbooks for this project.</p>' +
'Together the base path and the playbook directory provide the full path used to locate playbooks.</p>' +
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
dataTitle: 'Project Path',
dataPlacement: 'right'

View File

@ -25,7 +25,7 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventFormDefini
}
scope.formModalActionLabel = 'OK';
scope.formModalHeader = 'View Event';
//scope.formModalHeader = 'View Event';
scope.formModalCancelShow = false;
$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
@ -36,7 +36,15 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventFormDefini
.success( function(data, status, headers, config) {
for (var fld in form.fields) {
if (fld == 'status') {
scope['status'] = (data.failed) ? 'error' : 'success';
if (data['failed']) {
scope['status'] = 'error';
}
else if (data['changed']) {
scope['status'] = 'changed';
}
else {
scope['status'] = 'success';
}
}
else if (fld == 'event_data') {
scope['event_data'] = JSON.stringify(data['event_data'], undefined, '\t');
@ -46,9 +54,6 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventFormDefini
scope['host'] = data['summary_fields']['host']['name'];
}
}
else if (fld == 'event_display') {
scope['event_display'] = data.event_display.replace(/^\u00a0*/g,'')
}
else {
if (fld == 'created') {
var cDate = new Date(data['created']);
@ -61,6 +66,9 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventFormDefini
}
}
}
scope['formModalHeader'] = data.event_display.replace(/^\u00a0*/g,'');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,

View File

@ -32,9 +32,11 @@ angular.module('ProjectPathHelper', ['RestServices', 'Utilities'])
master.base_dir = scope.base_dir; // Keep in master object so that it doesn't get
// wiped out on form reset.
if (opts.length == 0) {
Alert('Missing project path', 'All of the project paths have been assigned to existing projects, or ' +
'there are no directories found in the base path. You will need to add a project path before creating ' +
'a new project.', 'alert-info');
Alert('Missing Playbooks',
'<p>There are no unassigned playbook directories in the base project path (' + scope.base_dir + '). ' +
'Either the project directory is empty, or all of the contents are already assigned to other AWX projects.</p>' +
'<p>To fix this, log into the AWX server and check out another playbook project from your SCM repository into ' +
scope.base_dir + '.</p>', 'alert-info');
}
})
.error( function(data, status, headers, config) {

View File

@ -505,7 +505,8 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "\" for=\"" + fld + '">';
html += (field.awPopOver) ? this.attr(field, 'awPopOver') : "";
html += (field.icon) ? this.icon(field.icon) : "";
html += field.label + '</label>' + "\n";
html += (field.label) ? field.label : '';
html += '</label>' + "\n";
html += "<div class=\"controls\">\n";
html += field.control;
html += "</div>\n";