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(" ") + ">" + tagName + ">";
+
+ 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 = "";
- html += (btn.img) ? "
" : "";
-
- 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 @@