diff --git a/awx/ui/static/js/controllers/Home.js b/awx/ui/static/js/controllers/Home.js index 73f978b026..e3a8c2dd38 100644 --- a/awx/ui/static/js/controllers/Home.js +++ b/awx/ui/static/js/controllers/Home.js @@ -27,43 +27,11 @@ */ export function Home($scope, $compile, $routeParams, $rootScope, $location, $log, Wait, DashboardCounts, DashboardJobs, - ClearScope, Stream, Rest, GetBasePath, ProcessErrors, Button, $window, graphData){ + ClearScope, Stream, Rest, GetBasePath, ProcessErrors, $window, graphData){ ClearScope('home'); - var buttons, html, e, borderStyles; - - // Add buttons to the top of the Home page. We're using lib/ansible/generator_helpers.js-> Buttons() - // to build buttons dynamically and insure all styling and icons match the rest of the application. - buttons = { - refresh: { - mode: 'all', - awToolTip: "Refresh the page", - ngClick: "refresh()", - ngShow:"socketStatus == 'error'" - }, - stream: { - ngClick: "showActivity()", - awToolTip: "View Activity Stream", - mode: 'all' - } - }; - - html = Button({ - btn: buttons.refresh, - action: 'refresh', - toolbar: true - }); - - html += Button({ - btn: buttons.stream, - action: 'stream', - toolbar: true - }); - - e = angular.element(document.getElementById('home-list-actions')); - e.html(html); - $compile(e)($scope); + var borderStyles; if (!$routeParams.login) { // If we're not logging in, start the Wait widget. Otherwise, it's already running. @@ -136,7 +104,7 @@ export function Home($scope, $compile, $routeParams, $rootScope, $location, $log } Home.$inject = ['$scope', '$compile', '$routeParams', '$rootScope', '$location', '$log','Wait', 'DashboardCounts', 'DashboardJobs', - 'ClearScope', 'Stream', 'Rest', 'GetBasePath', 'ProcessErrors', 'Button', '$window', 'graphData' + 'ClearScope', 'Stream', 'Rest', 'GetBasePath', 'ProcessErrors', '$window', 'graphData' ]; diff --git a/awx/ui/static/js/controllers/Portal.js b/awx/ui/static/js/controllers/Portal.js index 7fc9b4bb4e..3af4a2234d 100644 --- a/awx/ui/static/js/controllers/Portal.js +++ b/awx/ui/static/js/controllers/Portal.js @@ -25,47 +25,15 @@ * */ export function PortalController($scope, $compile, $routeParams, $rootScope, $location, $log, Wait, ClearScope, Stream, Rest, GetBasePath, ProcessErrors, - Button, PortalJobsWidget, GenerateList, PortalJobTemplateList, SearchInit, PaginateInit, PlaybookRun){ + PortalJobsWidget, GenerateList, PortalJobTemplateList, SearchInit, PaginateInit, PlaybookRun){ ClearScope('portal'); - var html, - e, - jobs_scope, + var jobs_scope, list = PortalJobTemplateList, view= GenerateList, defaultUrl = GetBasePath('job_templates'), - max_rows, - buttons = { - refresh: { - mode: 'all', - awToolTip: "Refresh the page", - ngClick: "refresh()", - ngShow:"socketStatus == 'error'" - } - // , - // stream: { - // ngClick: "showActivity()", - // awToolTip: "View Activity Stream", - // mode: 'all' - // } - }; - - html = Button({ - btn: buttons.refresh, - action: 'refresh', - toolbar: true - }); - - // html += Button({ - // btn: buttons.stream, - // action: 'stream', - // toolbar: true - // }); - - e = angular.element(document.getElementById('portal-list-actions')); - e.html(html); - $compile(e)($scope); + max_rows; if ($scope.removeLoadPortal) { $scope.removeLoadPortal(); @@ -176,5 +144,5 @@ export function PortalController($scope, $compile, $routeParams, $rootScope, $lo } PortalController.$inject = ['$scope', '$compile', '$routeParams', '$rootScope', '$location', '$log','Wait', 'ClearScope', 'Stream', 'Rest', 'GetBasePath', 'ProcessErrors', - 'Button', 'PortalJobsWidget', 'generateList' , 'PortalJobTemplateList', 'SearchInit', 'PaginateInit', 'PlaybookRun' + 'PortalJobsWidget', 'generateList' , 'PortalJobTemplateList', 'SearchInit', 'PaginateInit', 'PlaybookRun' ]; diff --git a/awx/ui/static/js/shared/form-generator.js b/awx/ui/static/js/shared/form-generator.js index 4d27d4c918..9affa6dcd8 100644 --- a/awx/ui/static/js/shared/form-generator.js +++ b/awx/ui/static/js/shared/form-generator.js @@ -139,9 +139,9 @@ export default angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerator.name]) .factory('GenerateForm', ['$rootScope', '$location', '$compile', 'generateList', 'SearchWidget', 'PaginateWidget', 'Attr', - 'Icon', 'Column', 'NavigationLink', 'HelpCollapse', 'Button', 'DropDown', 'Empty', 'SelectIcon', 'Store', + 'Icon', 'Column', 'NavigationLink', 'HelpCollapse', 'DropDown', 'Empty', 'SelectIcon', 'Store', function ($rootScope, $location, $compile, GenerateList, SearchWidget, PaginateWidget, Attr, Icon, Column, NavigationLink, - HelpCollapse, Button, DropDown, Empty, SelectIcon, Store) { + HelpCollapse, DropDown, Empty, SelectIcon, Store) { return { setForm: function (form) { this.form = form; }, @@ -553,7 +553,50 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat } }, - button: Button, + button: function(params) { + var tagName = "button"; + var options = params.btn; + var tagParts = + [ tagName, + "toolbar-button" + ]; + + var attrNames = _.keys(options); + + function isSupportedKey(keyName) { + if (keyName === 'icon') { + //TODO: Let's add a depecrated logger to our logging helper to output the below message + // + // The form action key "icon" is deprecated in favor of using the name of the field as the icon name or the iconClass option. + return false; + } + + return true; + } + + var attrs = attrNames + .filter(function(name) { + + return isSupportedKey(name) && + !_.isEmpty(options[name]); + + }).map(function(name) { + return Attr(options, name); + }); + + tagParts = + tagParts + .concat(attrs) + .concat( + Attr(params, 'iconName'), + Attr(params, 'toolbar') + ); + + var html = "<" + tagParts.join(" ") + ">"; + + return html; + + }, navigationLink: NavigationLink, @@ -1346,7 +1389,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat var html = "
\n", action; for (action in this.form.actions) { if (this.form.actions[action].mode === 'all' || this.form.actions[action].mode === options.mode) { - html += this.button({ btn: this.form.actions[action], action: action, toolbar: true }); + html += this.button({ btn: this.form.actions[action], iconName: action, toolbar: true }); } } html += "
\n"; @@ -1722,7 +1765,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat action = collection.actions[act]; html += this.button({ btn: action, - action: act, + iconName: act, toolbar: true }); } diff --git a/awx/ui/static/js/shared/generator-helpers.js b/awx/ui/static/js/shared/generator-helpers.js index 061503300b..a68844e7a7 100644 --- a/awx/ui/static/js/shared/generator-helpers.js +++ b/awx/ui/static/js/shared/generator-helpers.js @@ -55,6 +55,12 @@ angular.module('GeneratorHelpers', [systemStatus.name]) case 'columnShow': result = "ng-show=\"" + value + "\" "; break; + case 'iconName': + result = "icon-name=\"" + value + "\" "; + break; + case 'iconSize': + result = "icon-size=\"" + value + "\" "; + break; case 'icon': // new method of constructing icon tag. Replaces Icon method. result = "" : ""; - - if (btn.iconClass) { - html += ""; - } - else { - html += SelectIcon({ - action: action, - size: btn.iconSize - }); - } - - html += (btn.label) ? " " + btn.label : ""; - html += " "; - - return html; - }; - } -]) - - .factory('NavigationLink', ['Attr', 'Icon', function (Attr, Icon) { return function (link) { diff --git a/awx/ui/static/js/shared/list-generator/list-actions.partial.html b/awx/ui/static/js/shared/list-generator/list-actions.partial.html new file mode 100644 index 0000000000..498d1dd316 --- /dev/null +++ b/awx/ui/static/js/shared/list-generator/list-actions.partial.html @@ -0,0 +1,31 @@ + + + + diff --git a/awx/ui/static/js/shared/list-generator/list-generator.factory.js b/awx/ui/static/js/shared/list-generator/list-generator.factory.js index f88c4d2c6a..a57a2cfc09 100644 --- a/awx/ui/static/js/shared/list-generator/list-generator.factory.js +++ b/awx/ui/static/js/shared/list-generator/list-generator.factory.js @@ -1,7 +1,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon', - 'Column', 'DropDown', 'NavigationLink', 'Button', 'SelectIcon', 'Breadcrumbs', + 'Column', 'DropDown', 'NavigationLink', 'SelectIcon', 'Breadcrumbs', function ($location, $compile, $rootScope, SearchWidget, PaginateWidget, Attr, Icon, Column, DropDown, NavigationLink, - Button, SelectIcon, Breadcrumbs) { + SelectIcon, Breadcrumbs) { return { setList: function (list) { @@ -24,8 +24,6 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate $('#lookup-modal').modal('hide'); }, - button: Button, - buildHTML: function(list, options) { this.setList(list); return this.build(options); @@ -71,6 +69,52 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate } this.scope.list = list; + this.scope.mode = options.mode; + + this.scope.isHiddenByOptions = function(options) { + var hiddenByNgHide = false, shownByNgShow = false; + + // If neither ngHide nor ngShow are specified we + // know it.s not hidden by options + // + if (!options.ngHide && !options.ngShow) { + return false; + } + + // If ngHide option is passed && evals to true + // it's hidden + if (options.ngHide && this.scope.$eval(options.ngHide)) { + return true; + } + + // If ngShow option is passed && evals to false + // it's hidden + if (options.ngShow && !this.scope.$eval(options.ngShow)) { + return true; + } + + // Otherwise, it's not hidden + return false; + }.bind(this); + + this.scope.hiddenOnCurrentPage = function(actionPages) { + var base = $location.path().replace(/^\//, '').split('/')[0]; + + if (!actionPages) { + return false; + } else if (actionPages.indexOf(base) > -1) { + return false; + } else { + return true; + } + + }; + + this.scope.hiddenInCurrentMode = function(actionMode) { + if (options.mode === actionMode || actionMode === 'all') { + return false; + } + }; $compile(element)(this.scope); @@ -120,7 +164,7 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate // var html = '', list = this.list, - base, size, action, btn, fld, cnt, field_action, fAction, itm; + base, size, action, fld, cnt, field_action, fAction, itm; if (options.activityStream) { // Breadcrumbs for activity stream widget @@ -203,7 +247,6 @@ export default ['$location', '$compile', '$rootScope', 'SearchWidget', 'Paginate if (options.mode !== 'lookup') { //actions - base = $location.path().replace(/^\//, '').split('/')[0]; html += "
\n"; - html += "
\n"; - // Add toolbar buttons or 'actions' - 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({ - btn: list.actions[action], - action: action, - toolbar: true - }); - } - } - } + html += "
\n"; - //select instructions - if (options.mode === 'select' && list.selectInstructions) { - btn = { - awPopOver: list.selectInstructions, - dataPlacement: 'left', - dataContainer: 'body', - 'class': 'btn-xs btn-help', - awToolTip: 'Click for help', - dataTitle: 'Help', - iconSize: 'fa-lg' - }; - //html += this.button(btn, 'select'); - html += this.button({ - btn: btn, - action: 'help', - toolbar: true - }); - } + for (action in list.actions) { + list.actions[action] = + _.defaults(list.actions[action], + { dataPlacement: "top" + }); + } + + html += "
\n"; - html += "
\n"; html += "
\n"; } else { //lookup diff --git a/awx/ui/static/js/shared/list-generator/main.js b/awx/ui/static/js/shared/list-generator/main.js index dba9519d25..1af299d520 100644 --- a/awx/ui/static/js/shared/list-generator/main.js +++ b/awx/ui/static/js/shared/list-generator/main.js @@ -1,5 +1,8 @@ import generateList from './list-generator.factory'; +import toolbarButton from './toolbar-button.directive'; +import generatorHelpers from 'tower/shared/generator-helpers'; export default - angular.module('listGenerator', []) - .factory('generateList', generateList); + angular.module('listGenerator', [generatorHelpers.name]) + .factory('generateList', generateList) + .directive('toolbarButton', toolbarButton); diff --git a/awx/ui/static/js/shared/list-generator/toolbar-button.directive.js b/awx/ui/static/js/shared/list-generator/toolbar-button.directive.js new file mode 100644 index 0000000000..a997ab0776 --- /dev/null +++ b/awx/ui/static/js/shared/list-generator/toolbar-button.directive.js @@ -0,0 +1,60 @@ +export default ['$compile', 'Attr', 'SelectIcon', function($compile, Attr, SelectIcon) { + return { + restrict: 'A', + scope: {}, + link: function(scope, element, attrs) { + + var toolbar = attrs.toolbar; + + if (toolbar) { + //if this is a toolbar button, set some defaults + attrs.class = 'btn-xs btn-primary'; + attrs.iconSize = 'fa-lg'; + } + + element.addClass('btn'); + + // If no class specified, default + // to btn-sm + if (_.isEmpty(attrs.class)) { + element.addClass("btn-sm"); + } else { + element.addClass(attrs.class); + } + + if (attrs.awPopOver) { + element.addClass("help-link-white"); + } + + if (attrs.iconName && _.isEmpty(attrs.id)) { + element.attr("id",attrs.iconName + "_btn"); + } + + if (!_.isEmpty(attrs.img)) { + $("") + .attr("src", $basePath + "img/" + attrs.img) + .css({ width: "12px", height: "12px" }) + .appendTo(element); + } + + if (!_.isEmpty(attrs.iconClass)) { + $("") + .addClass(attrs.iconClass) + .appendTo(element); + } + else { + var icon = SelectIcon({ + action: attrs.iconName, + size: attrs.iconSize + }); + + $(icon).appendTo(element); + } + + if (!toolbar && !_.isEmpty(attrs.label)) { + element.text(attrs.label); + } + + } + }; +}]; diff --git a/awx/ui/static/partials/home.html b/awx/ui/static/partials/home.html index dc70714683..421c2c2b6d 100644 --- a/awx/ui/static/partials/home.html +++ b/awx/ui/static/partials/home.html @@ -4,6 +4,24 @@
+ + +
diff --git a/awx/ui/static/partials/portal.html b/awx/ui/static/partials/portal.html index 604d36bacf..077eed49e3 100644 --- a/awx/ui/static/partials/portal.html +++ b/awx/ui/static/partials/portal.html @@ -3,6 +3,14 @@
+