From f1b99f12b6508f9763567a29ce20bd49164c38b5 Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Fri, 6 Dec 2013 03:06:15 +0000 Subject: [PATCH] Start of inventory re-write --- awx/ui/static/js/app.js | 16 +- awx/ui/static/js/controllers/Inventories.js | 78 ++--- awx/ui/static/js/helpers/JobSubmission.js | 8 +- awx/ui/static/js/helpers/inventory.js | 2 +- awx/ui/static/js/lists/CloudCredentials.js | 6 +- awx/ui/static/js/lists/Credentials.js | 8 +- awx/ui/static/js/lists/Groups.js | 6 +- awx/ui/static/js/lists/HomeGroups.js | 2 +- awx/ui/static/js/lists/HomeHosts.js | 2 +- awx/ui/static/js/lists/Hosts.js | 4 +- awx/ui/static/js/lists/Inventories.js | 41 ++- awx/ui/static/js/lists/InventoryGroups.js | 186 ++++++++++++ awx/ui/static/js/lists/JobEvents.js | 2 +- awx/ui/static/js/lists/JobHosts.js | 4 +- awx/ui/static/js/lists/JobTemplates.js | 4 +- awx/ui/static/js/lists/Jobs.js | 2 +- awx/ui/static/js/lists/Organizations.js | 4 +- awx/ui/static/js/lists/Permissions.js | 4 +- awx/ui/static/js/lists/Projects.js | 8 +- awx/ui/static/js/lists/Streams.js | 4 +- awx/ui/static/js/lists/Teams.js | 4 +- awx/ui/static/js/lists/Users.js | 4 +- awx/ui/static/less/ansible-ui.less | 82 +++-- awx/ui/static/lib/ansible/InventoryTree.js | 284 ++++++++++++++++++ awx/ui/static/lib/ansible/directives.js | 2 +- .../static/lib/ansible/generator-helpers.js | 9 +- awx/ui/static/lib/ansible/list-generator.js | 97 +++--- awx/ui/static/partials/inventory-edit.html | 8 + awx/ui/templates/ui/index.html | 8 +- 29 files changed, 676 insertions(+), 213 deletions(-) create mode 100644 awx/ui/static/js/lists/InventoryGroups.js create mode 100644 awx/ui/static/lib/ansible/InventoryTree.js create mode 100644 awx/ui/static/partials/inventory-edit.html diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index e905f7b6c2..c2415e21e7 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -32,7 +32,7 @@ angular.module('ansible', [ 'InventoryHelper', 'InventoryHostsFormDefinition', 'InventoryGroupsFormDefinition', - 'InventorySummaryDefinition', + 'InventoryGroupsDefinition', 'AWFilters', 'HostFormDefinition', 'HostListDefinition', @@ -59,8 +59,6 @@ angular.module('ansible', [ 'JobEventsListDefinition', 'JobEventDataDefinition', 'JobHostDefinition', - 'GroupsHelper', - 'HostsHelper', 'ParseHelper', 'ChildrenHelper', 'EventsHelper', @@ -80,7 +78,7 @@ angular.module('ansible', [ 'InventoryStatusDefinition', 'InventorySummaryHelpDefinition', 'InventoryHostsHelpDefinition', - 'TreeSelector', + 'InventoryTree', 'CredentialsHelper', 'TimerService', 'StreamListDefinition', @@ -138,14 +136,8 @@ angular.module('ansible', [ when('/inventories/add', { templateUrl: urlPrefix + 'partials/inventories.html', controller: InventoriesAdd }). - when('/inventories/:id', - { templateUrl: urlPrefix + 'partials/inventories.html', controller: InventoriesEdit }). - - when('/inventories/:inventory_id/hosts', - { templateUrl: urlPrefix + 'partials/inventories.html', controller: InventoryHosts }). - - when('/inventories/:inventory_id/groups', - { templateUrl: urlPrefix + 'partials/inventories.html', controller: InventoryGroups }). + when('/inventories/:inventory_id', + { templateUrl: urlPrefix + 'partials/inventory-edit.html', controller: InventoriesEdit }). when('/organizations', { templateUrl: urlPrefix + 'partials/organizations.html', controller: OrganizationsList }). diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js index 9bad5b65df..fd738c7e79 100644 --- a/awx/ui/static/js/controllers/Inventories.js +++ b/awx/ui/static/js/controllers/Inventories.js @@ -198,14 +198,6 @@ function InventoriesList ($scope, $rootScope, $location, $log, $routeParams, Res scope.viewFailedJobs = function(id) { $location.url('/jobs/?inventory__int=' + id + '&status=failed'); } - - scope.editHosts = function(id) { - $location.url('/inventories/' + id + '/hosts'); - } - - scope.editGroups = function(id) { - $location.url('/inventories/' + id + '/groups'); - } } InventoriesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'InventoryList', 'GenerateList', @@ -322,67 +314,31 @@ InventoriesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$lo 'OrganizationList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'GetBasePath', 'ParseTypeChange', 'Wait']; -function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, InventoryForm, - GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, - RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, OrganizationList, - GetBasePath, LoadInventory, ParseTypeChange, EditInventory, SaveInventory, PostLoadInventory, - Stream - ) +function InventoriesEdit ($rootScope, $location, $routeParams, GenerateList, ClearScope, InventoryGroups, BuildTree, Wait) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. - var generator = GenerateForm; - var form = InventoryForm; - var defaultUrl=GetBasePath('inventory'); - var scope = generator.inject(form, { mode: 'edit', related: true }); - var base = $location.path().replace(/^\//,'').split('/')[0]; - var id = $routeParams.id; + var generator = GenerateList; + var list = InventoryGroups; + var base = $location.path().replace(/^\//,'').split('/')[0]; + var scope = $rootScope.$new(); + var groupScope; - scope['inventoryParseType'] = 'yaml'; - scope['inventory_id'] = id; - - ParseTypeChange(scope,'inventory_variables', 'inventoryParseType'); - - // Retrieve each related sets and any lookups - if (scope.inventoryLoadedRemove) { - scope.inventoryLoadedRemove(); - } - scope.inventoryLoadedRemove = scope.$on('inventoryLoaded', function() { - LoadBreadCrumbs({ path: '/inventories/' + id, title: scope.inventory_name }); - PostLoadInventory({ scope: scope }); - }); + scope.$on('searchTreeReady', function(e, inventory_name, groups) { + // After the tree data loads, generate the groups list + groupScope = generator.inject(list, { mode: 'edit', id: 'groups-container', breadCrumbs: false, searchSize: 'col-lg-5' }); + Wait('stop'); + groupScope.groups = groups; + groupScope.inventory_name = inventory_name; + groupScope.inventory_id = $routeParams.inventory_id; + }); - LoadInventory({ scope: scope, doPostSteps: false }); - - scope.showActivity = function() { Stream(); } - - // Cancel - scope.formReset = function() { - generator.reset(); - for (var fld in scope.master) { - scope[fld] = scope.master[fld]; - } - }; - - if (scope.removeInventorySaved) { - scope.removeInventorySaved(); - } - scope.removeInventorySaved = scope.$on('inventorySaved', function() { - $location.path('/inventories'); - }); - - scope.formSave = function() { - generator.clearApiErrors(); - SaveInventory({ scope: scope }); - } + BuildTree({ scope: scope, inventory_id: $routeParams.inventory_id }); } -InventoriesEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryForm', - 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', - 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', - 'OrganizationList', 'GetBasePath', 'LoadInventory', 'ParseTypeChange', 'EditInventory', - 'SaveInventory', 'PostLoadInventory', 'Stream' +InventoriesEdit.$inject = [ '$rootScope','$location', '$routeParams', 'GenerateList', 'ClearScope', 'InventoryGroups', 'BuildTree', + 'Wait' ]; diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 6ee2ecb091..bda26dfdd4 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -5,11 +5,11 @@ * */ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition', - 'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper', 'GroupFormDefinition', 'GroupsHelper' ]) + 'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper' ]) - .factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', 'GroupForm', 'ProjectsForm', '$compile', 'Rest', '$location', 'ProcessErrors', + .factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', '$compile', 'Rest', '$location', 'ProcessErrors', 'GetBasePath', 'Alert', 'Empty', 'Wait', - function(CredentialForm, JobTemplateForm, ProjectsForm, GroupForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty, + function(CredentialForm, JobTemplateForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty, Wait) { return function(params) { @@ -115,12 +115,14 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential if (form.fields[passwords[i]]) { current_form = form; } + /* else if (ProjectsForm.fields[passwords[i]]) { current_form = ProjectsForm; } else if (GroupForm.fields[passwords[i]]) { current_form = GroupForm; } + */ else { // No match found. Abandon ship! Alert('Form Not Found', 'Could not locate form for: ' + passwords[i], 'alert-danger'); diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js index b0df8c0e2c..71442af893 100644 --- a/awx/ui/static/js/helpers/inventory.js +++ b/awx/ui/static/js/helpers/inventory.js @@ -11,7 +11,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationListDefinition', 'SearchHelper', 'PaginateHelper', 'ListGenerator', 'AuthService', 'InventoryHelper', 'RelatedSearchHelper', 'RelatedPaginateHelper', - 'InventoryFormDefinition', 'ParseHelper', 'InventorySummaryDefinition' + 'InventoryFormDefinition', 'ParseHelper' ]) .factory('LoadRootGroups', ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) { diff --git a/awx/ui/static/js/lists/CloudCredentials.js b/awx/ui/static/js/lists/CloudCredentials.js index 1a129dfe5c..9212baf550 100644 --- a/awx/ui/static/js/lists/CloudCredentials.js +++ b/awx/ui/static/js/lists/CloudCredentials.js @@ -50,7 +50,7 @@ angular.module('CloudCredentialsListDefinition', []) label: 'Create New', mode: 'all', // One of: edit, select, all ngClick: 'addCredential()', - "class": 'btn-success btn-xs', + "class": 'btn-sm', awToolTip: 'Create a new credential' } }, @@ -60,7 +60,7 @@ angular.module('CloudCredentialsListDefinition', []) ngClick: "editCredential(\{\{ credential.id \}\})", icon: 'icon-edit', label: 'Edit', - "class": 'btn-xs btn-default', + "class": 'btn-sm', awToolTip: 'View/Edit credential' }, @@ -68,7 +68,7 @@ angular.module('CloudCredentialsListDefinition', []) ngClick: "deleteCredential(\{\{ credential.id \}\},'\{\{ credential.name \}\}')", icon: 'icon-trash', label: 'Delete', - "class": 'btn-xs btn-danger', + "class": 'btn-sm', awToolTip: 'Delete credential' } } diff --git a/awx/ui/static/js/lists/Credentials.js b/awx/ui/static/js/lists/Credentials.js index fb8194840f..d8b4dbb383 100644 --- a/awx/ui/static/js/lists/Credentials.js +++ b/awx/ui/static/js/lists/Credentials.js @@ -59,11 +59,11 @@ angular.module('CredentialsListDefinition', []) label: 'Create New', mode: 'all', // One of: edit, select, all ngClick: 'addCredential()', - "class": 'btn-success btn-xs', + "class": 'btn-sm', awToolTip: 'Create a new credential' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-sm activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", @@ -79,7 +79,7 @@ angular.module('CredentialsListDefinition', []) ngClick: "editCredential(\{\{ credential.id \}\})", icon: 'icon-edit', label: 'Edit', - "class": 'btn-xs btn-default', + "class": 'btn-sm', awToolTip: 'View/Edit credential' }, @@ -87,7 +87,7 @@ angular.module('CredentialsListDefinition', []) ngClick: "deleteCredential(\{\{ credential.id \}\},'\{\{ credential.name \}\}')", icon: 'icon-trash', label: 'Delete', - "class": 'btn-xs btn-danger', + "class": 'btn-sm', awToolTip: 'Delete credential' } } diff --git a/awx/ui/static/js/lists/Groups.js b/awx/ui/static/js/lists/Groups.js index c0e92d600e..569a301ae9 100644 --- a/awx/ui/static/js/lists/Groups.js +++ b/awx/ui/static/js/lists/Groups.js @@ -35,7 +35,7 @@ angular.module('GroupListDefinition', []) dataContainer: '#form-modal .modal-content', icon: "icon-question-sign", mode: 'all', - 'class': 'btn-xs btn-info btn-help pull-right', + 'class': 'btn-xs btn-help pull-right', awToolTip: 'Click for help', dataTitle: 'Adding Groups', iconSize: 'large' @@ -47,7 +47,7 @@ angular.module('GroupListDefinition', []) label: 'Edit', ngClick: "editGroup(\{\{ group.id \}\})", icon: 'icon-edit', - "class": 'btn-xs btn-default', + "class": 'btn-xs', awToolTip: 'View/Edit group' }, @@ -55,7 +55,7 @@ angular.module('GroupListDefinition', []) label: 'Delete', ngClick: "deleteGroup(\{\{ group.id \}\},'\{\{ group.name \}\}')", icon: 'icon-trash', - "class": 'btn-xs btn-danger', + "class": 'btn-xs', awToolTip: 'Delete group' } } diff --git a/awx/ui/static/js/lists/HomeGroups.js b/awx/ui/static/js/lists/HomeGroups.js index 80a293fd70..3ebaab4f99 100644 --- a/awx/ui/static/js/lists/HomeGroups.js +++ b/awx/ui/static/js/lists/HomeGroups.js @@ -111,7 +111,7 @@ angular.module('HomeGroupListDefinition', []) actions: { stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/js/lists/HomeHosts.js b/awx/ui/static/js/lists/HomeHosts.js index 0891c97b80..0ca6968282 100644 --- a/awx/ui/static/js/lists/HomeHosts.js +++ b/awx/ui/static/js/lists/HomeHosts.js @@ -82,7 +82,7 @@ angular.module('HomeHostListDefinition', []) actions: { stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/js/lists/Hosts.js b/awx/ui/static/js/lists/Hosts.js index 15057aa220..37b414299c 100644 --- a/awx/ui/static/js/lists/Hosts.js +++ b/awx/ui/static/js/lists/Hosts.js @@ -47,7 +47,7 @@ angular.module('HostListDefinition', []) label: 'Edit', ngClick: "editHost(\{\{ host.id \}\})", icon: 'icon-edit', - "class": 'btn-xs btn-default', + "class": 'btn-xs', awToolTip: 'View/Edit host' }, @@ -55,7 +55,7 @@ angular.module('HostListDefinition', []) label: 'Delete', ngClick: "deleteHost(\{\{ host.id \}\},'\{\{ host.name \}\}')", icon: 'icon-trash', - "class": 'btn-xs btn-danger', + "class": 'btn-xs', awToolTip: 'Delete host' } } diff --git a/awx/ui/static/js/lists/Inventories.js b/awx/ui/static/js/lists/Inventories.js index c7ba2b425a..75a590ac5f 100644 --- a/awx/ui/static/js/lists/Inventories.js +++ b/awx/ui/static/js/lists/Inventories.js @@ -82,28 +82,39 @@ angular.module('InventoriesListDefinition', []) actions: { add: { - label: 'Create New', + label: 'Add', icon: 'icon-plus', mode: 'all', // One of: edit, select, all ngClick: 'addInventory()', - "class": 'btn-xs btn-success', awToolTip: 'Create a new inventory' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + label: 'Activity', ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", icon: "icon-comments-alt", mode: 'all', - iconSize: 'large', ngShow: "user_is_superuser" } }, fieldActions: { - - dropdown: { + edit: { + label: 'Edit', + ngClick: "editInventory(\{\{ inventory.id \}\})", + icon: 'icon-edit', + "class": 'btn-xs btn-default', + awToolTip: 'Edit inventory' + }, + "delete": { + label: 'Delete', + ngClick: "deleteInventory(\{\{ inventory.id \}\},'\{\{ inventory.name \}\}')", + icon: 'icon-trash', + "class": 'btn-xs btn-danger', + awToolTip: 'Delete inventory' + }, + dropdown: { type: 'DropDown', label: 'Jobs', icon: 'icon-zoom-in', @@ -112,24 +123,6 @@ angular.module('InventoriesListDefinition', []) { ngClick: 'viewJobs(\{\{ inventory.id \}\})', label: 'All' }, { ngClick: "viewFailedJobs(\{\{ inventory.id \}\})", label: 'Failed' } ] - }, - edit: { - type: 'DropDown', - label: 'Edit', - icon: 'icon-edit', - 'class': 'btn-default btn-xs', - options: [ - { ngClick: "editInventory(\{\{ inventory.id \}\})", label: 'Properties' }, - { ngClick: "editHosts(\{\{ inventory.id \}\})", label: 'Hosts' }, - { ngClick: "editGroups(\{\{ inventory.id \}\})", label: 'Groups' } - ] - }, - "delete": { - label: 'Delete', - ngClick: "deleteInventory(\{\{ inventory.id \}\},'\{\{ inventory.name \}\}')", - icon: 'icon-trash', - "class": 'btn-xs btn-danger', - awToolTip: 'Delete inventory' } } }); diff --git a/awx/ui/static/js/lists/InventoryGroups.js b/awx/ui/static/js/lists/InventoryGroups.js new file mode 100644 index 0000000000..7ba3d7d8e7 --- /dev/null +++ b/awx/ui/static/js/lists/InventoryGroups.js @@ -0,0 +1,186 @@ +/********************************************* + * Copyright (c) 2013 AnsibleWorks, Inc. + * + * InventorySummary.js + * + * Summary of groups contained within an inventory + * + */ +angular.module('InventoryGroupsDefinition', []) + .value( + 'InventoryGroups', { + + name: 'groups', + iterator: 'group', + editTitle: '{{ inventory_name | capitalize }}', + showTitle: false, + well: true, + index: false, + hover: true, + hasChildren: true, + class: 'table-condensed', + + fields: { + name: { + key: true, + label: 'name', + ngClick: "\{\{ 'GroupsEdit(' + group.id + ')' \}\}", + //ngClass: "\{\{ 'level' + group.level \}\}", + hasChildren: true + }, + status: { + label: 'Sync Status', + ngClick: "viewUpdateStatus(\{\{ group.id \}\})", + searchType: 'select', + badgeIcon: "\{\{ 'icon-cloud-' + group.status_badge_class \}\}", + badgeToolTip: "\{\{ group.status_badge_tooltip \}\}", + awToolTip: "\{\{ group.status_badge_tooltip \}\}", + dataPlacement: 'top', + badgeTipPlacement: 'top', + badgePlacement: 'left', + searchOptions: [ + { name: "failed", value: "failed" }, + { name: "never", value: "never updated" }, + { name: "n/a", value: "none" }, + { name: "successful", value: "successful" }, + { name: "updating", value: "updating" }], + sourceModel: 'inventory_source', + sourceField: 'status' + }, + failed_hosts: { + label: 'Failed Hosts', + ngHref: "\{\{ group.failed_hosts_link \}\}", + badgeIcon: "\{\{ 'icon-failures-' + group.failed_hosts_class \}\}", + badgeNgHref: "\{\{ group.failed_hosts_link \}\}", + badgePlacement: 'left', + badgeToolTip: "\{\{ group.failed_hosts_tip \}\}", + badgeTipPlacement: 'top', + awToolTip: "\{\{ group.failed_hosts_tip \}\}", + dataPlacement: "top", + searchable: false, + excludeModal: true, + sortField: "hosts_with_active_failures" + }, + source: { + label: 'Source', + searchType: 'select', + searchOptions: [ + { name: "ec2", value: "ec2" }, + { name: "none", value: "" }, + { name: "rax", value: "rax" }], + sourceModel: 'inventory_source', + sourceField: 'source', + searchOnly: true + }, + has_external_source: { + label: 'Has external source?', + searchType: 'in', + searchValue: 'ec2,rax', + searchOnly: true, + sourceModel: 'inventory_source', + sourceField: 'source' + }, + has_active_failures: { + label: 'Has failed hosts?', + searchSingleValue: true, + searchType: 'boolean', + searchValue: 'true', + searchOnly: true + }, + last_update_failed: { + label: 'Update failed?', + searchType: 'select', + searchSingleValue: true, + searchValue: 'failed', + searchOnly: true, + sourceModel: 'inventory_source', + sourceField: 'status' + } + }, + + actions: { + create: { + label: 'Add', + mode: 'all', + icon: 'icon-plus', + 'class': "btn-sm", + ngClick: "createGroup()", + ngHide: "groupCreateHide", + ngDisabled: 'grpBtnDisabled', + awToolTip: "Create a new top-level group", + dataPlacement: 'top', + iconSize: 'large' + }, + refresh: { + label: 'Refresh', + dataPlacement: 'top', + icon: "icon-refresh", + mode: 'all', + 'class': 'btn-sm', + awToolTip: "Refresh the page", + ngClick: "refresh()", + iconSize: 'large' + }, + stream: { + label: 'Activity', + 'class': "btn-sm activity-btn", + ngClick: "showActivity()", + awToolTip: "View Activity Stream", + dataPlacement: "top", + icon: "icon-comments-alt", + mode: 'all', + iconSize: 'large', + ngShow: "user_is_superuser" + }, + help: { + label: 'Help', + dataPlacement: 'top', + icon: "icon-question-sign", + mode: 'all', + 'class': 'btn-sm btn-help', + awToolTip: + //"
" + + //"

Need help getting started creating your inventory?

Click here for help.

", + "

Need help getting started creating your inventory?

Click here for help.

", + iconSize: 'large', + ngClick: "showHelp()", + id: "inventory-summary-help" + } + }, + + fieldActions: { + group_update: { + label: 'Update', + icon: 'icon-cloud-download', + "class": 'btn-xs btn-primary', + ngClick: 'updateGroup(\{\{ group.id \}\})', + awToolTip: "\{\{ group.update_tooltip \}\}", + ngClass: "group.update_class", + awToolTip: "Start inventory sync" + }, + cancel: { + label: 'Cancel', + icon: 'icon-minus-sign', + ngClick: "cancelUpdate(\{\{ group.id \}\}, '\{\{ group.name \}\}')", + "class": 'btn-xs btn-primary', + awToolTip: "\{\{ group.cancel_tooltip \}\}", + ngClass: "group.cancel_class", + ngShow: "group.status == 'running' || group.status == 'pending'" + }, + edit: { + label: 'Edit', + ngClick: "editGroup(\{\{ group.id \}\})", + icon: 'icon-edit', + "class": 'btn-xs btn-primary', + awToolTip: 'Edit group' + }, + "delete": { + label: 'Delete', + ngClick: "deleteGroup(\{\{ group.id \}\},'\{\{ group.name \}\}')", + icon: 'icon-trash', + "class": 'btn-xs btn-primary', + awToolTip: 'Delete group' + } + } + }); + \ No newline at end of file diff --git a/awx/ui/static/js/lists/JobEvents.js b/awx/ui/static/js/lists/JobEvents.js index d24d174755..68de6326e4 100644 --- a/awx/ui/static/js/lists/JobEvents.js +++ b/awx/ui/static/js/lists/JobEvents.js @@ -89,7 +89,7 @@ angular.module('JobEventsListDefinition', []) dataPlacement: 'top', icon: "icon-refresh", mode: 'all', - 'class': 'btn-xs btn-primary', + 'class': 'btn-xs', awToolTip: "Refresh the page", ngClick: "refresh()", iconSize: 'large' diff --git a/awx/ui/static/js/lists/JobHosts.js b/awx/ui/static/js/lists/JobHosts.js index 8b710a8d75..6c3fc1d18d 100644 --- a/awx/ui/static/js/lists/JobHosts.js +++ b/awx/ui/static/js/lists/JobHosts.js @@ -113,7 +113,7 @@ angular.module('JobHostDefinition', []) dataContainer: "body", icon: "icon-question-sign", mode: 'all', - 'class': 'btn-info btn-xs btn-help', + 'class': 'btn-xs btn-help', awToolTip: 'Click for help', dataTitle: 'Job Host Summary', id: 'jobhost-help-button', @@ -123,7 +123,7 @@ angular.module('JobHostDefinition', []) dataPlacement: 'top', icon: "icon-refresh", mode: 'all', - 'class': 'btn-xs btn-primary', + 'class': 'btn-xs', awToolTip: "Refresh the page", ngClick: "refresh()", iconSize: 'large', diff --git a/awx/ui/static/js/lists/JobTemplates.js b/awx/ui/static/js/lists/JobTemplates.js index fde8d1d784..e7053efd5a 100644 --- a/awx/ui/static/js/lists/JobTemplates.js +++ b/awx/ui/static/js/lists/JobTemplates.js @@ -34,12 +34,12 @@ angular.module('JobTemplatesListDefinition', []) icon: 'icon-plus', mode: 'all', // One of: edit, select, all ngClick: 'addJobTemplate()', - "class": 'btn-success btn-xs', + "class": 'btn-xs', basePaths: ['job_templates'], awToolTip: 'Create a new template' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/js/lists/Jobs.js b/awx/ui/static/js/lists/Jobs.js index 8475f4e056..d4b5e898d5 100644 --- a/awx/ui/static/js/lists/Jobs.js +++ b/awx/ui/static/js/lists/Jobs.js @@ -79,7 +79,7 @@ angular.module('JobsListDefinition', []) dataPlacement: 'top', icon: "icon-refresh", mode: 'all', - 'class': 'btn-xs btn-primary', + 'class': 'btn-xs', awToolTip: "Refresh the page", ngClick: "refresh()", iconSize: 'large' diff --git a/awx/ui/static/js/lists/Organizations.js b/awx/ui/static/js/lists/Organizations.js index e936b56fe7..d6bb6f1fa0 100644 --- a/awx/ui/static/js/lists/Organizations.js +++ b/awx/ui/static/js/lists/Organizations.js @@ -33,11 +33,11 @@ angular.module('OrganizationListDefinition', []) icon: 'icon-plus', mode: 'all', // One of: edit, select, all ngClick: 'addOrganization()', - "class": 'btn-success btn-xs', + "class": 'btn-xs', awToolTip: 'Create a new organization' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/js/lists/Permissions.js b/awx/ui/static/js/lists/Permissions.js index 92296fc367..f0696630f2 100644 --- a/awx/ui/static/js/lists/Permissions.js +++ b/awx/ui/static/js/lists/Permissions.js @@ -47,12 +47,12 @@ angular.module('PermissionListDefinition', []) label: 'Create New', mode: 'all', // One of: edit, select, all ngClick: 'addPermission()', - "class": 'btn-success btn-xs', + "class": 'btn-xs', awToolTip: 'Add a new permission', ngShow: 'PermissionAddAllowed' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/js/lists/Projects.js b/awx/ui/static/js/lists/Projects.js index 141ec8bb7a..d27d5be93a 100644 --- a/awx/ui/static/js/lists/Projects.js +++ b/awx/ui/static/js/lists/Projects.js @@ -61,7 +61,7 @@ angular.module('ProjectsListDefinition', []) icon: 'icon-plus', mode: 'all', // One of: edit, select, all ngClick: 'addProject()', - "class": 'btn-success btn-xs', + "class": 'btn-xs', awToolTip: 'Create a new project' }, help: { @@ -77,7 +77,7 @@ angular.module('ProjectsListDefinition', []) dataContainer: 'body', icon: "icon-question-sign", mode: 'all', - 'class': 'btn-xs btn-info btn-help', + 'class': 'btn-xs btn-help', awToolTip: 'Click for help', awTipPlacement: 'top', dataTitle: 'Project Status', @@ -87,13 +87,13 @@ angular.module('ProjectsListDefinition', []) dataPlacement: 'top', icon: "icon-refresh", mode: 'all', - 'class': 'btn-xs btn-primary', + 'class': 'btn-xs', awToolTip: "Refresh the page", ngClick: "refresh()", iconSize: 'large' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/js/lists/Streams.js b/awx/ui/static/js/lists/Streams.js index 3c284ea8f6..2b6c38d8e3 100644 --- a/awx/ui/static/js/lists/Streams.js +++ b/awx/ui/static/js/lists/Streams.js @@ -208,7 +208,7 @@ angular.module('StreamListDefinition', []) dataPlacement: 'top', icon: "icon-refresh", mode: 'all', - 'class': 'btn-xs btn-primary', + 'class': 'btn-xs', awToolTip: "Refresh the page", ngClick: "refreshStream()", iconSize: 'large' @@ -217,7 +217,7 @@ angular.module('StreamListDefinition', []) dataPlacement: 'top', icon: "icon-arrow-left", mode: 'all', - 'class': 'btn-xs btn-primary', + 'class': 'btn-xs', awToolTip: "Close Activity Stream view", ngClick: "closeStream()", iconSize: 'large' diff --git a/awx/ui/static/js/lists/Teams.js b/awx/ui/static/js/lists/Teams.js index 3e3d871fac..d665928fb6 100644 --- a/awx/ui/static/js/lists/Teams.js +++ b/awx/ui/static/js/lists/Teams.js @@ -40,11 +40,11 @@ angular.module('TeamsListDefinition', []) icon: 'icon-plus', mode: 'all', // One of: edit, select, all ngClick: 'addTeam()', - "class": 'btn-xs btn-success', + "class": 'btn-xs', awToolTip: 'Create a new team' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/js/lists/Users.js b/awx/ui/static/js/lists/Users.js index 46b10403e1..1195b9a645 100644 --- a/awx/ui/static/js/lists/Users.js +++ b/awx/ui/static/js/lists/Users.js @@ -40,11 +40,11 @@ angular.module('UserListDefinition', []) mode: 'all', // One of: edit, select, all ngClick: 'addUser()', basePaths: ['organizations','users'], // base path must be in list, or action not available - "class": 'btn-success btn-xs', + "class": 'btn-xs', awToolTip: 'Create a new user' }, stream: { - 'class': "btn-primary btn-xs activity-btn", + 'class': "btn-xs activity-btn", ngClick: "showActivity()", awToolTip: "View Activity Stream", dataPlacement: "top", diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 069214f5d6..9c2f81780d 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -45,6 +45,43 @@ body { .grey-txt { color: @grey; } .text-center { text-align: center !important; } + +/* Old style TB default button with grey background */ +.btn-grey { + color: #333; + background-color: #ccc; + border-color: #ccc; +} + +.btn-grey:hover { + background-color: #FFF; +} + +/* Make button appear to be disabled, but allow mouse events */ +.btn-disabled { + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} + +/* List Actions column */ +.actions { + a { + font-size: 14px; + margin-left: 15px; + } + a:first-child { + margin-left: 0; + } + a:hover { + cursor: pointer; + } + .dropdown { + margin-left: 15px; + } +} + .success-badge { color: #ffffff; background-color: #5cb85c; @@ -117,15 +154,6 @@ textarea { margin-bottom: 15px; } -/* Make button appear to be disabled, but allow mouse events */ - .btn-disabled { - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; - } - - hr { border-color: #e3e3e3; } @@ -174,11 +202,6 @@ td.actions { } .dropdown-toggle, -.btn-default { - color: #333; - background-color: #ccc; - border-color: #ccc; -} .dropdown-toggle:hover, .btn-default:visited, @@ -631,6 +654,7 @@ input[type="checkbox"].checkbox-no-label { /* Display list actions next to search widget */ .list-actions { text-align: right; + margin-bottom: 15px; button { margin-left: 4px; @@ -767,7 +791,7 @@ input[type="checkbox"].checkbox-no-label { line-height: 1; } - /* Inventory job status badge */ +/* Inventory job status badge */ .failures-true { background-color: @red; color: #fff; @@ -885,18 +909,17 @@ input[type="checkbox"].checkbox-no-label { color: @black; cursor: default; } - - .level-1 { - padding-left: 24px; - } - - .level-2 { - padding-left: 48px; - } - - .level-3 { - padding-left: 72px; - } + /* Padding levels used on job events and inventory groups */ + .level-1 { padding-left: 20px; } + .level-2 { padding-left: 40px; } + .level-3 { padding-left: 60px; } + .level-4 { padding-left: 80px; } + .level-5 { padding-left: 100px; } + .level-6 { padding-left: 120px; } + .level-7 { padding-left: 140px; } + .level-8 { padding-left: 160px; } + .level-9 { padding-left: 180px; } + .level-10 { padding-left: 200px; } .level-3-detail { padding-left: 72px; @@ -930,6 +953,11 @@ input[type="checkbox"].checkbox-no-label { } } +.inventory-title { + font-size: 16px; + font-weight: bold; +} + /* Inventory-> Groups */ .inventory-passwd-msg { diff --git a/awx/ui/static/lib/ansible/InventoryTree.js b/awx/ui/static/lib/ansible/InventoryTree.js new file mode 100644 index 0000000000..203ae1cf4f --- /dev/null +++ b/awx/ui/static/lib/ansible/InventoryTree.js @@ -0,0 +1,284 @@ + +/************************************ + * + * Copyright (c) 2013 AnsibleWorks, Inc. + * + * InventoryTree.js + * + * Build data for the tree selector table used on inventory detail page. + * + */ + +angular.module('InventoryTree', ['Utilities', 'RestServices']) + + .factory('SortNodes', [ function() { + return function(data) { + //Sort nodes by name + var names = []; + var newData = []; + for (var i=0; i < data.length; i++) { + names.push(data[i].name); + } + names.sort(); + for (var j=0; j < names.length; j++) { + for (i=0; i < data.length; i++) { + if (data[i].name == names[j]) { + newData.push(data[i]); + } + } + } + return newData; + } + }]) + + // Figure out the group level tool tip + .factory('GetToolTip', [ 'FormatDate', function(FormatDate) { + return function(params) { + + var node = params.node; + + var tip = ''; + var link = ''; + var html_class = ''; + var active_failures = node.hosts_with_active_failures; + var total_hosts = node.total_hosts; + var source = node.summary_fields.inventory_source.source; + var status = node.summary_fields.inventory_source.status; + + // Return values for the status indicator + var status_date = node.summary_fields.inventory_source.last_updated + var last_update = ( status_date == "" || status_date == null ) ? null : FormatDate(new Date(status_date)); + + switch (status) { + case 'never updated': + html_class = 'na'; + tip = '

Inventory update has not been performed.

'; + link = ''; + break; + case 'failed': + tip = '

Inventory update failed! Click to view process output.

'; + link = '/#/inventories/' + node.inventory + '/groups?name=' + node.name; + html_class = true; + break; + case 'successful': + tip = '

Inventory update completed on ' + last_update + '.

'; + html_class = false; + link = ''; + break; + case 'updating': + tip = '

Inventory update process running now. Click to view status.

'; + link = '/#/inventories/' + node.inventory + '/groups?name=' + node.name; + html_class = false; + break; + } + + if (status !== 'failed' && status !== 'updating') { + // update status will not override job status + if (active_failures > 0) { + tip += "

Contains " + active_failures + + [ (active_failures == 1) ? ' host' : ' hosts' ] + ' with failed jobs. Click to view the offending ' + + [ (active_failures == 1) ? ' host' : ' hosts' ] + '.

'; + link = '/#/inventories/' + node.inventory + '/hosts?has_active_failures=true'; + html_class = 'true'; + } + else { + if (total_hosts == 0) { + // no hosts + tip += "

There are no hosts in this group. It's a sad empty shell.

"; + html_class = (html_class == '') ? 'na' : html_class; + } + else if (total_hosts == 1) { + // on host with 0 failures + tip += "

The 1 host in this group is happy! It does not have a job failure.

"; + html_class = 'false'; + } + else { + // many hosts with 0 failures + tip += "

All " + total_hosts + " hosts in this group are happy! None of them have " + + " job failures.

"; + html_class = 'false'; + } + } + } + + return { tooltip: tip, url: link, 'class': html_class }; + + } + }]) + + .factory('GetInventoryToolTip', [ 'FormatDate', function(FormatDate) { + return function(params) { + + var node = params.node; + + var tip = ''; + var link = ''; + var html_class = ''; + var active_failures = node.hosts_with_active_failures; + var total_hosts = node.total_hosts; + var group_failures = node.groups_with_active_failures; + var total_groups = node.total_groups; + var inventory_sources = node.total_inventory_sources; + + if (group_failures > 0) { + tip += "Has " + group_failures + + [ (group_failures == 1) ? ' group' : ' groups' ] + ' with failed inventory updates. ' + + 'Click to view the offending ' + + [ (group_failures == 1) ? ' group.' : ' groups.' ]; + link = '/#/inventories/' + node.id + '/groups?status=failed'; + html_class = 'true'; + } + else if (inventory_sources == 1) { + // on host with 0 failures + tip += "

1 group with an inventory source is happy! No updates have failed.

"; + link = ''; + html_class = 'false'; + } + else if (inventory_sources > 0) { + tip += "

" + inventory_sources + " groups with an inventory source are happy! No updates have failed.

"; + link = 0; + html_class = 'false'; + } + + if (html_class !== 'true') { + // Add job status + if (active_failures > 0) { + tip += "

Contains " + scope.inventories[i].hosts_with_active_failures + + [ (active_failures == 1) ? ' host' : ' hosts' ] + ' with job failures. Click to view the offending ' + + [ (active_failures == 1) ? ' host' : ' hosts' ] + '.

'; + link = '/#/inventories/' + node.id + '/hosts?has_active_failures=true'; + html_class = 'true'; + } + else if (total_hosts == 0) { + tip += "

There are no hosts in this inventory. It's a sad empty shell.

"; + link = ""; + html_class = (html_class == '') ? 'na' : html_class; + } + else if (total_hosts == 1) { + tip += "

The 1 host found in this inventory is happy! There are no job failures.

"; + link = ""; + html_class = "false"; + } + else if (total_hosts > 0) { + tip += "

All " + total_hosts + " hosts are happy! There are no job failures."; + link = ""; + html_class = "false"; + } + } + + return { tooltip: tip, url: link, 'class': html_class }; + + } + }]) + + .factory('BuildTree', ['Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', + function(Rest, GetBasePath, ProcessErrors, SortNodes, Wait) { + return function(params) { + + var inventory_id = params.inventory_id; + var scope = params.scope; + + var groups = []; + var id = 1; + + function buildGroups(tree_data, parent, level) { + var sorted = SortNodes(tree_data); + for(var i=0; i < sorted.length; i++) { + var currentId= id; + var group = { + name: sorted[i].name, + has_active_failures: sorted[i].has_active_failures, + total_hosts: sorted[i].total_hosts, + hosts_with_active_failures: sorted[i].hosts_with_active_failures, + total_groups: sorted[i].total_groups, + groups_with_active_failures: sorted[i].groups_with_active_failures, + parent: parent, + has_children: (sorted[i].children.length > 0) ? true : false, + id: id, + event_level: level, + ngicon: (sorted[i].children.length > 0) ? 'icon-collapse-alt' : null, + related: { children: (sorted[i].children.length > 0) ? sorted[i].related.children : '' } + } + groups.push(group); + id++; + if (sorted[i].children.length > 0) { + buildGroups(sorted[i].children, currentId, level + 1); + } + } + } + + // Build the HTML for our tree + if (scope.buildAllGroupsRemove) { + scope.buildAllGroupsRemove(); + } + scope.buildAllGroupsRemove = scope.$on('buildAllGroups', function(e, inventory_name, inventory_tree) { + Rest.setUrl(inventory_tree); + Rest.get() + .success( function(data, status, headers, config) { + buildGroups(data, 0, 0); + scope.$emit('searchTreeReady', inventory_name, groups); + }) + .error( function(data, status, headers, config) { + Wait('stop'); + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status }); + }); + }); + + + function loadTreeData() { + // Load the inventory root node + Wait('start'); + Rest.setUrl (GetBasePath('inventory') + inventory_id + '/'); + Rest.get() + .success( function(data, status, headers, config) { + scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups); + }) + .error( function(data, status, headers, config) { + Wait('stop'); + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status }); + }); + } + + loadTreeData(); + + } + }]) + + // Set node name and description after an update to Group properties. + .factory('SetNodeName', [ function() { + return function(params) { + var scope = params.scope; + var name = params.name; + var descr = params.description; + var group_id = (params.group_id !== undefined) ? params.group_id : null; + var inventory_id = (params.inventory_id != undefined) ? params.inventory_id : null; + + if (group_id !== null) { + $('#inventory-tree').find('li [data-group-id="' + group_id + '"]').each(function(idx) { + $(this).attr('data-name',name); + $(this).attr('data-description',descr); + $(this).find('.activate').first().text(name); + }); + } + + if (inventory_id !== null) { + $('#inventory-root-node').attr('data-name', name).attr('data-description', descr).find('.activate').first().text(name); + } + } + }]) + + .factory('ClickNode', [ function() { + return function(params) { + var selector = params.selector; //jquery selector string to find the correct

  • + $(selector + ' .activate').first().click(); + } + }]) + + .factory('DeleteNode', [ function() { + return function(params) { + var selector = params.selector; //jquery selector string to find the correct
  • + $(selector).first().detach(); + } + }]); \ No newline at end of file diff --git a/awx/ui/static/lib/ansible/directives.js b/awx/ui/static/lib/ansible/directives.js index 43f90f4e30..bae1fb05e1 100644 --- a/awx/ui/static/lib/ansible/directives.js +++ b/awx/ui/static/lib/ansible/directives.js @@ -8,7 +8,7 @@ var INTEGER_REGEXP = /^\-?\d*$/; -angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'HostsHelper']) +angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService']) // awpassmatch: Add to password_confirm field. Will test if value // matches that of 'input[name="password"]' .directive('awpassmatch', function() { diff --git a/awx/ui/static/lib/ansible/generator-helpers.js b/awx/ui/static/lib/ansible/generator-helpers.js index 468712c3d4..92102e0731 100644 --- a/awx/ui/static/lib/ansible/generator-helpers.js +++ b/awx/ui/static/lib/ansible/generator-helpers.js @@ -109,9 +109,10 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers']) html += " "; if (btn['awRefresh']) { html += '{{ refreshMsg }}\n'; @@ -492,7 +493,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers']) for (var i=1; i <= searchWidgets; i++) { var modifier = (i == 1) ? '' : i; html += "
    \n"; html += "
    \n"; } - /* - if (list.editTitle.match(/^Inventory Summary/)) { - html += "
    \n"; - html += "
    \n"; - html += "\n"; - html += "
    \n"; - html += "
    \n"; - } - */ - - if (options.searchSize) { - html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize, - searchWidgets: list.searchWidgets }); - } - else if (options.mode == 'summary') { - html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-6' }); - } - else if (options.mode == 'lookup' || options.id != undefined) { - html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-8' }); + if (list.name == 'groups') { + // Inventory groups + html += "
    \n"; + html += "
    " + list.editTitle + "
    \n"; } else { - html += SearchWidget({ iterator: list.iterator, template: list, mini: true }); + if (options.searchSize) { + html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize, + searchWidgets: list.searchWidgets }); + } + else if (options.mode == 'summary') { + html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-6' }); + } + else if (options.mode == 'lookup' || options.id != undefined) { + html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-8' }); + } + else { + html += SearchWidget({ iterator: list.iterator, template: list, mini: true }); + } } - + if (options.mode != 'lookup') { //actions var base = $location.path().replace(/^\//,'').split('/')[0]; @@ -241,12 +237,18 @@ angular.module('ListGenerator', ['GeneratorHelpers']) html += "\">\n"; html += "
    \n"; - // all but refresh button + for (action in list.actions) { if (list.actions[action].mode == 'all' || list.actions[action].mode == options.mode) { if ( (list.actions[action].basePaths == undefined) || (list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1) ) { - html += this.button(list.actions[action], action); + list.actions[action]['class'] = 'btn-xs btn-primary'; + list.actions[action]['iconSize'] = 'large'; + delete list.actions[action]['label']; + if (action == 'stream') { + list.actions[action]['icon'] = 'icon-time'; + } + html += this.button(list.actions[action], action); } } } @@ -258,7 +260,7 @@ angular.module('ListGenerator', ['GeneratorHelpers']) dataPlacement: 'left', dataContainer: 'body', icon: "icon-question-sign", - 'class': 'btn-xs btn-help btn-info', + 'class': 'btn-xs btn-help', awToolTip: 'Click for help', dataTitle: 'Help', iconSize: 'large' @@ -286,7 +288,8 @@ angular.module('ListGenerator', ['GeneratorHelpers']) html += "\n"; + html += "\n"; } html += "\n"; html += "\n"; @@ -378,7 +381,19 @@ angular.module('ListGenerator', ['GeneratorHelpers']) }); } else { - html += this.button(list.fieldActions[action]); + //list.fieldActions[action]['class'] = 'btn-xs btn-default'; + //list.fieldActions[action]['iconSize'] = 'large'; + //html += this.button(list.fieldActions[action]); + var fAction = list.fieldActions[action]; + html += "\n"; - html += " \n"; - html += "\n"; + html += "
    \n"; + html += " \n"; + html += "
    \n"; } if (options.mode != 'lookup' && (list.well == undefined || list.well == true)) { - html += "\n"; //well - } - - if ( options.mode == 'lookup' || (options.id && options.id == "form-modal-body") ) { - html += PaginateWidget({ set: list.name, iterator: list.iterator, mini: true, mode: 'lookup' }); - } - else { - html += PaginateWidget({ set: list.name, iterator: list.iterator, mini: true }); + html += "\n"; //well } + if (list.name !== 'groups') { + if ( options.mode == 'lookup' || (options.id && options.id == "form-modal-body") ) { + html += PaginateWidget({ set: list.name, iterator: list.iterator, mini: true, mode: 'lookup' }); + } + else { + html += PaginateWidget({ set: list.name, iterator: list.iterator, mini: true }); + } + } + return html; } diff --git a/awx/ui/static/partials/inventory-edit.html b/awx/ui/static/partials/inventory-edit.html new file mode 100644 index 0000000000..ec434b22bb --- /dev/null +++ b/awx/ui/static/partials/inventory-edit.html @@ -0,0 +1,8 @@ +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index feb1fb29a8..7f3db4683e 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -43,7 +43,7 @@ - + @@ -51,8 +51,6 @@ - - @@ -86,7 +84,7 @@ - + @@ -108,8 +106,6 @@ - -
    Actions