diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js index 77cdc152f7..3f0b8e1c5e 100644 --- a/awx/ui/static/js/controllers/Inventories.js +++ b/awx/ui/static/js/controllers/Inventories.js @@ -311,12 +311,13 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa InventoriesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList', - 'OrganizationList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'GetBasePath', 'ParseTypeChange', 'Wait']; + 'OrganizationList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'GetBasePath', 'ParseTypeChange', 'Wait' + ]; -function InventoriesEdit ($scope, $location, $routeParams, GenerateList, ClearScope, InventoryGroups, InventoryHosts, BuildTree, Wait, - UpdateStatusMsg, InjectHosts, HostsReload, GroupsAdd, GroupsEdit) +function InventoriesEdit ($scope, $location, $routeParams, $compile, GenerateList, ClearScope, InventoryGroups, InventoryHosts, BuildTree, Wait, + UpdateStatusMsg, InjectHosts, HostsReload, GroupsAdd, GroupsEdit, Breadcrumbs, LoadBreadCrumbs) { ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. @@ -327,20 +328,35 @@ function InventoriesEdit ($scope, $location, $routeParams, GenerateList, ClearSc $scope.inventory_id = $routeParams.inventory_id; + LoadBreadCrumbs(); + if ($scope.removeSearchTreeReady) { $scope.removeSearchTreeReady(); } $scope.removeSearchTreeReady = $scope.$on('searchTreeReady', function(e, inventory_name, groups) { // After the tree data loads, generate the groups list - generator.inject(list, { mode: 'edit', id: 'groups-container', breadCrumbs: false, searchSize: 'col-lg-5' }); + var e = angular.element(document.getElementById('breadcrumbs')); + e.html(Breadcrumbs({ list: list, mode: 'edit' })); + $compile(e)($scope); + generator.inject(list, { mode: 'edit', id: 'groups-container', breadCrumbs: false, searchSize: 'col-lg-5 col-md-5 col-sm-5' }); $scope.groups = groups; $scope.inventory_name = inventory_name; InjectHosts({ scope: $scope, inventory_id: $scope.inventory_id }); Wait('stop'); }); - - $scope.showHosts = function(group_id) { + + $scope.showHosts = function(tree_id, group_id) { // Clicked on group + //$scope.groups[tree_id].selected_class = 'selected'; + $scope.selected_tree_id = tree_id; + $scope.selected_group_id = group_id; + for (var i=0; i < $scope.groups.length; i++) { + $scope.groups[i].selected_class = ($scope.groups[i].id == tree_id) ? 'selected' : ''; + if ($scope.groups[i].id == tree_id) { + $scope.selected_group_name = $scope.groups[i].name; + } + } + $scope.search_place_holder='Search ' + $scope.selected_group_name; HostsReload({ scope: $scope, group_id: group_id, inventory_id: $scope.inventory_id }); } @@ -355,7 +371,8 @@ function InventoriesEdit ($scope, $location, $routeParams, GenerateList, ClearSc BuildTree({ scope: $scope, inventory_id: $scope.inventory_id }); } -InventoriesEdit.$inject = [ '$scope','$location', '$routeParams', 'GenerateList', 'ClearScope', 'InventoryGroups', 'InventoryHosts', 'BuildTree', - 'Wait', 'UpdateStatusMsg', 'InjectHosts', 'HostsReload', 'GroupsAdd', 'GroupsEdit' +InventoriesEdit.$inject = [ '$scope', '$location', '$routeParams', '$compile', 'GenerateList', 'ClearScope', 'InventoryGroups', 'InventoryHosts', + 'BuildTree', 'Wait', 'UpdateStatusMsg', 'InjectHosts', 'HostsReload', 'GroupsAdd', 'GroupsEdit', 'Breadcrumbs', + 'LoadBreadCrumbs' ]; diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index 3047bffd57..eff8acc03b 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -39,7 +39,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H var inventory_id = params.inventory_id; var generator = GenerateList; - generator.inject(InventoryHosts, { mode: 'edit', id: 'hosts-container', breadCrumbs: false, searchSize: 'col-lg-5' }); + generator.inject(InventoryHosts, { mode: 'edit', id: 'hosts-container', breadCrumbs: false, searchSize: 'col-lg-6 col-md-6 col-sm-6' }); HostsReload({ scope: scope, group_id: null, inventory_id: inventory_id }); } }]) diff --git a/awx/ui/static/js/helpers/search.js b/awx/ui/static/js/helpers/search.js index 237897796b..8376262ce4 100644 --- a/awx/ui/static/js/helpers/search.js +++ b/awx/ui/static/js/helpers/search.js @@ -83,10 +83,21 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) scope[iterator + 'ShowStartBtn' + modifier] = true; scope[iterator + 'HideAllStartBtn' + modifier] = false; - scope[iterator + 'SearchPlaceholder' + modifier] = - (list.fields[scope[iterator + 'SearchField' + modifier]] && - list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) ? - list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder : 'Search'; + if (list.fields[scope[iterator + 'SearchField' + modifier]] && + list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) { + if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) { + // if set to a scope variable + scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]; + } + else { + // Set to a string value in the list definition + scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder; + } + } + else { + // Default value + scope[iterator + 'SearchPlaceholder' + modifier] = 'Search'; + } scope[iterator + 'InputDisable' + modifier] = (list.fields[scope[iterator + 'SearchField' + modifier]] && @@ -128,9 +139,24 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper']) scope[iterator + 'HideSearchType' + modifier] = false; scope[iterator + 'InputHide' + modifier] = false; scope[iterator + 'SearchType' + modifier] = 'icontains'; - scope[iterator + 'SearchPlaceholder' + modifier] = (list.fields[fld].searchPlaceholder) ? list.fields[fld].searchPlaceholder : 'Search'; scope[iterator + 'InputDisable' + modifier] = (list.fields[fld].searchObject == 'all') ? true : false; scope[iterator + 'ShowStartBtn' + modifier] = true; + + if (list.fields[scope[iterator + 'SearchField' + modifier]] && + list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) { + if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) { + // if set to a scope variable + scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]; + } + else { + // Set to a string value in the list definition + scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder; + } + } + else { + // Default value + scope[iterator + 'SearchPlaceholder' + modifier] = 'Search'; + } if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') { scope[iterator + "InputDisable" + modifier] = true; diff --git a/awx/ui/static/js/lists/InventoryGroups.js b/awx/ui/static/js/lists/InventoryGroups.js index f0e6fca589..c416840650 100644 --- a/awx/ui/static/js/lists/InventoryGroups.js +++ b/awx/ui/static/js/lists/InventoryGroups.js @@ -24,8 +24,8 @@ angular.module('InventoryGroupsDefinition', []) name: { label: 'Group', key: true, - ngClick: "\{\{ 'showHosts(' + group.id + ')' \}\}", - //ngClass: "\{\{ 'level' + group.level \}\}", + ngClick: "\{\{ 'showHosts(' + group.id + ',' + group.group_id + ')' \}\}", + ngClass: "group.selected_class", hasChildren: true }, status: { diff --git a/awx/ui/static/js/lists/InventoryHosts.js b/awx/ui/static/js/lists/InventoryHosts.js index 5d7ec94d2b..cb79a59630 100644 --- a/awx/ui/static/js/lists/InventoryHosts.js +++ b/awx/ui/static/js/lists/InventoryHosts.js @@ -24,7 +24,8 @@ angular.module('InventoryHostsDefinition', []) name: { key: true, label: 'Name', - ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')" + ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')", + searchPlaceholder: "search_place_holder" }, active_failures: { label: 'Job Status', @@ -55,7 +56,8 @@ angular.module('InventoryHostsDefinition', []) searchable: true, sourceModel: 'groups', sourceField: 'name', - nosort: true + nosort: true, + searchPlaceholder: "search_place_holder" }, enabled: { label: 'Disabled?', diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 87af45f22f..393e9d0163 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -14,7 +14,8 @@ @red-hover: #AE3F3A; @green: #5bb75b; @blue: #1778c3; /* logo blue */ -@blue-link: #0088cc; +@blue-link: #1778c3; +@blue-dark: #2a6496; /* link hover */ @grey: #A9A9A9; @well: #f5f5f5; /* well background color */ @green: #5bb75b; @@ -35,6 +36,7 @@ body { color: @black; } + /* Helper Classes */ .pad-right-sm { padding-right: 10px; } .pad-left-md { padding-left: 30px; } @@ -47,6 +49,17 @@ body { .text-center { text-align: center !important; } +a { + color: @blue; + text-decoration: none; +} + +a:hover, +a:focus { + color: @blue-dark; + text-decoration: none; +} + /* Old style TB default button with grey background */ .btn-grey { color: #333; @@ -66,6 +79,15 @@ body { box-shadow: none; } +/* Bring primary (blue) buttons in line with link colors */ +.btn-primary { + background-color: @blue; +} + +.btn-primary:hover { + background-color: @blue-dark; +} + /* List Actions column */ .actions { a { @@ -320,10 +342,6 @@ dd { max-width: 260px; } -a:hover { - text-decoration: none; -} - .help-link, .help-link:active, .help-link:visited { @@ -517,10 +535,7 @@ select.page-size { } /* Search Widget */ - .search-widget { - margin-bottom: 20px; - } - + .search-widget label { display: inline-block; padding-right: 15px; @@ -658,7 +673,7 @@ input[type="checkbox"].checkbox-no-label { /* Display list actions next to search widget */ .list-actions { text-align: right; - margin-bottom: 15px; + margin-bottom: 25px; button { margin-left: 4px; @@ -897,9 +912,9 @@ input[type="checkbox"].checkbox-no-label { font-weight: bold; } - .form-items .search-widget { + /*.form-items .search-widget { margin-top: 15px; - } + }*/ .form-items .item-count { display: inline-block; @@ -955,237 +970,19 @@ input[type="checkbox"].checkbox-no-label { } } + +/* Inventory Edit */ + +.selected { + font-weight: bold; + color: @blue-dark; +} + .inventory-title { font-size: 16px; font-weight: bold; } -/* Inventory-> Groups */ - - .inventory-passwd-msg { - font-size: 14px; - margin-bottom: 25px; - margin-left: 10px; - } - - .groups-issue { - margin-bottom: 10px; - } - - .inventory-content { - padding: 15px; - border: 1px solid #ddd; - border-radius: 6px; - } - - /* - .tree-view-container { - padding: 0 0 10px 0; - - .col-lg-4 { - padding-right: 10px; - } - } - */ - - #tree-view { - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - - /*border: 1px solid #e3e3e3; - border-radius: 6px; - background-color: #e3e3e3; - */ - padding-top: 10px; - padding-left: 10px; - padding-bottom: 10px; - min-height: 100px; - - .title { - color: #888; - padding-bottom: 5px; - margin-left: 5px; - } - } - - #tree-form { - display: none; - /*padding: 15px 10px 10px 10px; - margin-top: 5px; - border: 1px solid #e3e3e3; - background-color: #e3e3e3; - border-radius: 6px;*/ - - .form-title { - color: #888; - padding-left: 0; - } - - hr { - background-color: #ccc; - height: 1px; - margin-top: 5px; - margin-bottom: 15px; - } - } - -/* Inventory-> Hosts */ - - .hosts-well { - padding-top: 5px; - - .search-widget { - margin-top: 10px; - } - - .list-actions { - padding-top: 10px; - } - - .title { - color: #888; - font-size: 14px; - font-weight: bold; - margin-bottom: 10px; - } - } - - .hosts-title p { - font-size: 12px; - } - - .hosts-title h4 { - margin: 5px 0; - } - - .host-groups { - margin-top: 15px; - - select { - height: 150px; - } - } - - .host-group-buttons { - margin-top: 20px; - text-align: center; - - p { - padding-top: 10px; - font-size: 12px; - font-weight: normal; - } - } - - /* Allow tree node title to float above surrounding elements on hover */ - #search-tree-target { - z-index: 10; - } - - .search-tree { - - padding: 10px 3px 10px 10px; - - .title { - color: @grey; - font-weight: normal; - margin-bottom: 5px; - margin-top: 0; - } - - .icon-sitemap { - color: @grey; - } - - ul { - list-style-type: none; - padding-left: 15px; - } - - .tree-root { - padding-left: 0; - } - - .activate { - display: block; - padding: 2px 3px 1px 3px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - height: 23px; - } - - .activate:hover { - display: inline-block; - overflow: visible; - background-color: #ddd; - cursor: pointer; - } - - .active { - font-weight: bold; - box-shadow: 3px 3px 3px 0 @grey; - border-bottom: 1px solid @grey; - border-right: 1px solid @grey; - background-color: #fff; - - .activate:hover { - background-color: #fff; - } - } - - .expand-container, - .badge-container, - .title-container { - display: inline-block; - vertical-align: middle; - border-bottom: 2px solid @well; - } - - .expand-container { - width: 14px; - text-align: left; - } - - .badge-container { - vertical-align: none; - padding-top: 2px; - padding-bottom: 2px; - margin-left: 3px; - } - - #root-badge-container { - margin-right: -2px; - margin-left: 3px; - } - - .expand { - padding: 3px; - } - - .title-container { - height: 25px; - } - - .expand-container:hover { - background-color: #ddd; - } - - .field-badge { - font-size: 10px; - line-height: normal; - /*vertical-align: baseline;*/ - } - - } - - .host-failure-filter { - padding: 10px; - } - .disabled { color: @grey; } diff --git a/awx/ui/static/lib/ansible/InventoryTree.js b/awx/ui/static/lib/ansible/InventoryTree.js index f63a2f6316..a5e0d337a2 100644 --- a/awx/ui/static/lib/ansible/InventoryTree.js +++ b/awx/ui/static/lib/ansible/InventoryTree.js @@ -177,15 +177,16 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper']) var inventory_id = params.inventory_id; var scope = params.scope; + //var selected_id = params. var groups = []; - var id = 1; + var id = 0; function buildGroups(tree_data, parent, level) { var sorted = SortNodes(tree_data); for (var i=0; i < sorted.length; i++) { - var currentId= id; - var stat = UpdateStatusMsg({ status: sorted[i].status }); + var currentId = id; + var stat = UpdateStatusMsg({ status: sorted[i].summary_fields.inventory_source.status }); var group = { name: sorted[i].name, has_active_failures: sorted[i].has_active_failures, @@ -203,7 +204,8 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper']) related: { children: (sorted[i].children.length > 0) ? sorted[i].related.children : '' }, status: sorted[i].summary_fields.inventory_source.status, status_badge_class: stat['class'], - status_badge_tooltip: stat['tooltip'] + status_badge_tooltip: stat['tooltip'], + selected_class: '' } groups.push(group); id++; @@ -266,6 +268,12 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper']) scope.groups[i][p] = properties[p]; } } + if (scope.groups[i].id == scope.selected_tree_id) { + //Make sure potential group name change gets reflected throughout the page + scope.selected_group_name = scope.groups[i].name; + scope.search_place_holder = 'Search ' + scope.groups[i].name; + scope.hostSearchPlaceholder = 'Search ' + scope.groups[i].name; + } } } }]) diff --git a/awx/ui/static/lib/ansible/form-generator.js b/awx/ui/static/lib/ansible/form-generator.js index 8c5566261e..ff2396dc7d 100644 --- a/awx/ui/static/lib/ansible/form-generator.js +++ b/awx/ui/static/lib/ansible/form-generator.js @@ -1461,6 +1461,8 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies', 'Utilities']) } html += "
| # | \n"; - } - for (var fld in list.fields) { - if ( (list.fields[fld].searchOnly == undefined || list.fields[fld].searchOnly == false) && - !(options.mode == 'lookup' && list.fields[fld].excludeModal !== undefined && list.fields[fld].excludeModal == true) ) { - html += "";
- html += list.fields[fld].label;
- if (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) {
- html += " \n";
+ html += "\n";
+ html += "| # | \n";
+ }
+ for (var fld in list.fields) {
+ if ( (list.fields[fld].searchOnly == undefined || list.fields[fld].searchOnly == false) &&
+ !(options.mode == 'lookup' && list.fields[fld].excludeModal !== undefined && list.fields[fld].excludeModal == true) ) {
+ html += "";
+ html += list.fields[fld].label;
+ if (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) {
+ html += " ";
- }
- html += " | \n";
- }
+ html += "fa-sort";
+ }
+ html += "\">";
+ }
+ html += "\n";
+ }
}
if (options.mode == 'select' || options.mode == 'lookup') {
- html += "Select | ";
+ html += "Select | ";
}
else if (options.mode == 'edit') {
- html += "Actions | \n";
+ html += "Actions | \n";
}
html += " | {{ $index + (" + list.iterator + "Page * " + list.iterator + "PageSize) + 1 }}. | \n"; + html += "{{ $index + (" + list.iterator + "Page * " + list.iterator + "PageSize) + 1 }}. | \n"; } var cnt = 2; var base = (list.base) ? list.base : list.name; diff --git a/awx/ui/static/partials/inventory-edit.html b/awx/ui/static/partials/inventory-edit.html index ec434b22bb..2b8c8e93d1 100644 --- a/awx/ui/static/partials/inventory-edit.html +++ b/awx/ui/static/partials/inventory-edit.html @@ -1,8 +1,14 @@
|---|