From c7f096f16b1a3c9c0f76f22b7fd952a31b9b8d45 Mon Sep 17 00:00:00 2001 From: chouseknecht Date: Wed, 2 Oct 2013 17:26:47 -0400 Subject: [PATCH] AC-503 latest UI work on cloud inventory --- awx/ui/static/css/bootstrap.css | 2 +- awx/ui/static/js/controllers/Groups.js | 3 +- awx/ui/static/js/controllers/Home.js | 1 - awx/ui/static/js/helpers/Groups.js | 24 +++++- awx/ui/static/js/helpers/JobSubmission.js | 86 ++++++++++++++++++- awx/ui/static/js/helpers/inventory.js | 79 +++++++++++++---- awx/ui/static/js/lists/InventorySummary.js | 24 ++++-- awx/ui/static/less/ansible-ui.less | 41 ++++++++- awx/ui/static/lib/ansible/form-generator.js | 2 +- .../static/lib/ansible/generator-helpers.js | 64 +++++++++----- awx/ui/static/lib/ansible/list-generator.js | 26 ++++-- 11 files changed, 286 insertions(+), 66 deletions(-) diff --git a/awx/ui/static/css/bootstrap.css b/awx/ui/static/css/bootstrap.css index bbda4eed4a..e34f1e1710 100644 --- a/awx/ui/static/css/bootstrap.css +++ b/awx/ui/static/css/bootstrap.css @@ -11,7 +11,7 @@ /*! normalize.css v2.1.0 | MIT License | git.io/normalize */ article, -aside, +aside,.table details, figcaption, figure, diff --git a/awx/ui/static/js/controllers/Groups.js b/awx/ui/static/js/controllers/Groups.js index abb803b8df..7f1ef84a9c 100644 --- a/awx/ui/static/js/controllers/Groups.js +++ b/awx/ui/static/js/controllers/Groups.js @@ -163,7 +163,8 @@ function InventoryGroups ($scope, $rootScope, $compile, $location, $log, $routeP scope.groupDeleteHide = true; scope.createButtonShow = false; scope.group_id = null; - InventoryStatus(); + scope.inventory_name = node.attr('name'); + InventoryStatus({ scope: scope }); $('#tree-form').show(); } diff --git a/awx/ui/static/js/controllers/Home.js b/awx/ui/static/js/controllers/Home.js index ae9ffdf623..afaecfbb4a 100644 --- a/awx/ui/static/js/controllers/Home.js +++ b/awx/ui/static/js/controllers/Home.js @@ -27,7 +27,6 @@ function Home ($routeParams, $scope, $rootScope, $location, Wait, ObjectCount, C $rootScope.$on('WidgetLoaded', function() { // Once all the widget report back 'loaded', turn off Wait widget - console.log('got here!'); loadedCount++; if ( loadedCount == waitCount ) { Wait('stop'); diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index f56e45d06d..1ee89bea74 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -9,7 +9,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'GroupsHelper', - 'InventoryHelper', 'SelectionHelper' + 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper' ]) .factory('getSourceTypeOptions', [ function() { @@ -233,9 +233,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' }]) .factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', - 'Prompt', 'ProcessErrors', 'GetBasePath', 'RefreshGroupName', 'ParseTypeChange', 'getSourceTypeOptions', + 'Prompt', 'ProcessErrors', 'GetBasePath', 'RefreshGroupName', 'ParseTypeChange', 'getSourceTypeOptions', 'InventoryUpdate', function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath, RefreshGroupName, ParseTypeChange, getSourceTypeOptions) { + GetBasePath, RefreshGroupName, ParseTypeChange, getSourceTypeOptions, InventoryUpdate) { return function(params) { var group_id = params.group_id; @@ -348,7 +348,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' scope[fld] = data[fld]; master[fld] = scope[fld]; } - } + } + scope['group_update_url'] = data.related['update']; }) .error( function(data, status, headers, config) { scope.source = null; @@ -564,6 +565,21 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', ' scope[form.name + '_form'][associated].$setValidity('awpassmatch', true); scope[form.name + '_form'].$setDirty(); } + + // Start the update process + scope.updateGroup = function() { + if (scope['source'] == null || scope['source'] == '') { + Alert('Missing Configuration', 'The selected group is not configured for updates. You must first edit the group, provide Source settings, ' + + 'and then run an update.', 'alert-info'); + } + else { + InventoryUpdate({ + scope: scope, + group_id: group_id, + url: scope['group_update_url'] + }); + } + } // Cancel scope.formReset = function() { diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 653b0574c7..14dd7aed1d 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -5,7 +5,7 @@ * */ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition', - 'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper']) + 'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper', 'GroupFormDefinition']) .factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', 'ProjectsForm', '$compile', 'Rest', '$location', 'ProcessErrors', 'GetBasePath', 'Alert', @@ -350,7 +350,89 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Failed to get job template details. GET returned status: ' + status }); + { hdr: 'Error!', msg: 'Failed to get project update details: ' + url + ' GET status: ' + status }); + }); + }; + }]) + + + // Sumbit Inventory Update request + .factory('InventoryUpdate',['PromptPasswords', '$compile', 'Rest', '$location', 'GetBasePath', 'ProcessErrors', 'Alert', 'GroupForm', + function(PromptPasswords, $compile, Rest, $location, GetBasePath, ProcessErrors, Alert, GroupForm) { + return function(params) { + + var scope = params.scope; + var inventory_id = params.inventory_id; + var url = params.url; + + if (scope.removeUpdateSubmitted) { + scope.removeUpdateSubmitted(); + } + scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function() { + // Refresh the project list after update request submitted + scope.refresh(); + }); + + if (scope.removeInventorySubmit) { + scope.removeInventorySubmit(); + } + scope.removeInventorySubmit = scope.$on('InventorySubmit', function(e, passwords_needed_to_update, extra_html) { + // After the call to update, kick off the job. + PromptPasswords({ + scope: scope, + passwords: passwords_needed_to_update, + start_url: url, + form: GroupForm, + extra_html: extra_html + }); + }); + + // Check to see if we have permission to perform the update and if any passwords are needed + Rest.setUrl(url); + Rest.get() + .success( function(data, status, headers, config) { + if (data.can_update) { + var extra_html = ''; + /* + for (var i=0; i < scope.projects.length; i++) { + if (scope.projects[i].id == project_id) { + extra_html += "
\n"; + extra_html += "\n"; + extra_html += "
\n"; + extra_html += "\n"; + extra_html += "\n"; + extra_html += "
\n"; + extra_html += "= total) { + scope.$emit('GroupsLoaded'); + } + }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, null, @@ -716,11 +756,12 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi Rest.setUrl(url); Rest.get() .success( function(data, status, headers, config) { + total = data.count; for (var i=0; i < data.results.length; i++) { if (data.results[i].related.inventory_source) { checkSource(data.results[i].related.inventory_source); } - } + } }) .error( function(data, status, headers, config) { ProcessErrors(scope, data, status, null, diff --git a/awx/ui/static/js/lists/InventorySummary.js b/awx/ui/static/js/lists/InventorySummary.js index 905320fa56..3f8745b136 100644 --- a/awx/ui/static/js/lists/InventorySummary.js +++ b/awx/ui/static/js/lists/InventorySummary.js @@ -12,26 +12,40 @@ angular.module('InventorySummaryDefinition', []) name: 'groups', iterator: 'group', - editTitle: 'Inventory Summary', + editTitle: 'Inventory Summary: {{ inventory_name }}', + showTitle: true, + well: false, index: false, hover: true, fields: { name: { key: true, - label: 'Name' + label: 'Group', + noLink: true, + badges: [ + { //Active Failures + icon: "\{\{ 'icon-failures-' + group.has_active_failures \}\}", + toolTip: 'Indicates if inventory contains hosts with active failures', + toolTipPlacement: 'bottom' + }, + { //Cloud Status + icon: "\{\{ 'icon-cloud-' + group.status \}\}", + toolTip: 'Indicates if inventory contains hosts with active failures', + toolTipPlacement: 'bottom' + }] }, failures: { - label: 'Hosts Failures' + label: 'Active
Failures' }, source: { label: 'Source' }, last_update: { - label: 'Last Update' + label: 'Last
Updated' }, status: { - label: 'Update Status' + label: 'Update
Status' } }, diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 1b6d5d5cba..3acfc60036 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -10,6 +10,7 @@ @black: #171717; @warning: #FF9900; @red: #FF0000; +@green: #5bb75b; @blue: #1778c3; /* logo blue */ @blue-link: #0088cc; @grey: #A9A9A9; @@ -591,6 +592,19 @@ select.field-mini-height { background-color: #dff0d8; } +.table-summary thead > tr > th, +.table-summary tbody > tr > th, +.table-summary tfoot > tr > th, +.table-summary thead > tr > td, +.table-summary tbody > tr > td, +.table-summary tfoot > tr > td { + border-top: 1px solid #ccc; +} + +.table-summary thead > tr > th { + border-bottom: 1px solid #ccc; +} + /* Jobs pages */ .job-error, @@ -646,6 +660,31 @@ select.field-mini-height { content: "\f111"; } + +/* Cloud inventory status. i.e. inventory_source.status values */ + + .icon-cloud-na:before, + .icon-cloud-never:before, + .icon-cloud-updating:before, + .icon-cloud-failed:before, + .icon-cloud-success:before { + content: "\f0c2"; + } + .icon-cloud-na { + color: #e3e3e3; + } + .icon-cloud-never { + color: #888; + } + .icon-cloud-updating, + .icon-cloud-success { + color: #5bb75b; + } + .icon-cloud-failed { + color: @red; + } + + .field-success { color: #5bb75b; } @@ -813,7 +852,7 @@ select.field-mini-height { background-color: #ccc; height: 1px; margin-top: 5px; - margin-bottom: 30px; + margin-bottom: 15px; } } diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js index 0cc4c70e50..20ccb59ad0 100644 --- a/awx/ui/static/lib/ansible/form-generator.js +++ b/awx/ui/static/lib/ansible/form-generator.js @@ -1220,7 +1220,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies']) html += "\n"; html += "\n"; html += "\n"; + } + html += "
\n"; + html += "
\n"; + } if (options.mode !== 'summary') { @@ -226,9 +234,9 @@ angular.module('ListGenerator', ['GeneratorHelpers']) html += "