Skip to content

Commit 17f79d0

Browse files
author
Dan Clarizio
authored
Merge pull request #9753 from karelhala/toolbarAngular
Replace ruby generated toolbar with angular's
2 parents eb1d90c + e448d6e commit 17f79d0

22 files changed

+544
-24
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
miqHttpInject(
2+
angular.module('ManageIQ.toolbar', [
3+
'miqStaticAssets', 'ui.bootstrap'
4+
])
5+
.config(function ($locationProvider) {
6+
$locationProvider.html5Mode({
7+
enabled: true,
8+
requireBase: false
9+
})
10+
})
11+
);

app/assets/javascripts/application.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
//= require miq_api
2222
//= require rxjs/dist/rx.all
2323
//= require miq_angular_application
24+
//= require_tree ./angular_modules/
2425
//= require_tree ./controllers/
2526
//= require_tree ./directives/
2627
//= require_tree ./services/
@@ -78,3 +79,6 @@
7879
//= require miq_c3
7980
//= require miq_explorer
8081
//= require qs
82+
// Bower packages
83+
//= require manageiq-ui-components/dist/js/ui-components
84+
//= require rx-angular/dist/rx.angular
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
(function(){
2+
3+
function isButton(item) {
4+
return item.type === 'button';
5+
}
6+
7+
function isButtonTwoState(item) {
8+
return item.type === 'buttonTwoState' && item.id.indexOf('view') === -1;
9+
}
10+
11+
/**
12+
* Private method for subscribing to rxSubject.
13+
* For success functuon @see ToolbarController#onRowSelect()
14+
*/
15+
function subscribeToSubject() {
16+
ManageIQ.angular.rxSubject.subscribe(function(event) {
17+
if (event.rowSelect) {
18+
this.onRowSelect(event.rowSelect);
19+
} else if (event.redrawToolbar) {
20+
this.onUpdateToolbar(event.redrawToolbar);
21+
} else if (event.update) {
22+
this.onUpdateItem(event);
23+
}
24+
}.bind(this),
25+
function (err) {
26+
console.error('Angular RxJs Error: ', err);
27+
},
28+
function () {
29+
console.debug('Angular RxJs subject completed, no more events to catch.');
30+
});
31+
}
32+
33+
/**
34+
* Private method for setting rootPoint of MiQEndpointsService.
35+
* @param MiQEndpointsService service responsible for endpoits.
36+
*/
37+
function initEndpoints(MiQEndpointsService) {
38+
var urlPrefix = '/' + location.pathname.split('/')[1];
39+
if (urlPrefix) {
40+
MiQEndpointsService.rootPoint = urlPrefix;
41+
}
42+
}
43+
44+
/**
45+
* Constructor of angular's miqToolbarController.
46+
* @param MiQToolbarSettingsService toolbarSettings service from ui-components.
47+
* @param MiQEndpointsService endpoits service from ui-components.
48+
* @param $scope service for managing $scope (for apply and digest reasons).
49+
* @param $location service for managing browser's location.
50+
* this contructor will assign all params to `this`, it will init endpoits, set if toolbar is used on list page.
51+
*/
52+
var ToolbarController = function(MiQToolbarSettingsService, MiQEndpointsService, $scope, $location) {
53+
this.MiQToolbarSettingsService = MiQToolbarSettingsService;
54+
this.MiQEndpointsService = MiQEndpointsService;
55+
this.$scope = $scope;
56+
this.$location = $location;
57+
initEndpoints(this.MiQEndpointsService);
58+
this.isList = _.contains(location.pathname, 'show_list');
59+
}
60+
61+
/**
62+
* Public method which is executed after row in gtl is selected.
63+
*/
64+
ToolbarController.prototype.onRowSelect = function(data) {
65+
this.MiQToolbarSettingsService.checkboxClicked(data.checked);
66+
if(!this.$scope.$$phase) {
67+
this.$scope.$digest();
68+
}
69+
}
70+
71+
/**
72+
* Public method for setting up url of data views, based on last path param (e.g. /show_list).
73+
*/
74+
ToolbarController.prototype.defaultViewUrl = function() {
75+
this.dataViews.forEach(function(item) {
76+
if (item.url === "") {
77+
var lastSlash = location.pathname.lastIndexOf('/');
78+
item.url = (lastSlash !== -1) ? location.pathname.substring(lastSlash): "";
79+
}
80+
});
81+
}
82+
83+
/**
84+
* Method which will retrieves toolbar settings from server.
85+
* @see MiQToolbarSettingsService#getSettings for more info.
86+
* Settings is called with this.isList and $location search object with value of `type`.
87+
* No need to worry about multiple search params and no complicated function for parsing is needed.
88+
*/
89+
ToolbarController.prototype.fetchData = function(getData) {
90+
return this.MiQToolbarSettingsService
91+
.getSettings(getData)
92+
.then(function(toolbarItems) {
93+
this.toolbarItems = toolbarItems.items;
94+
this.dataViews = toolbarItems.dataViews;
95+
}.bind(this));
96+
}
97+
98+
/**
99+
*
100+
*/
101+
ToolbarController.prototype.setClickHandler = function() {
102+
var buttons = _
103+
.chain(this.toolbarItems)
104+
.flatten()
105+
.map(function(item) {
106+
return (item && item.hasOwnProperty('items')) ? item.items : item;
107+
})
108+
.flatten()
109+
.filter(function(item){
110+
return item.type &&
111+
(isButton(item) || isButtonTwoState(item))
112+
})
113+
.each(function(item) {
114+
item.eventFunction = function($event) {
115+
miqToolbarOnClick.bind($event.delegateTarget)($event);
116+
}
117+
})
118+
.value();
119+
}
120+
121+
/**
122+
* Public method for changing view over data.
123+
*/
124+
ToolbarController.prototype.onViewClick = function(item, $event) {
125+
if (item.url.indexOf('/') === 0) {
126+
var tail = (ManageIQ.record.recordId) ? ManageIQ.record.recordId : '';
127+
location.replace('/' + ManageIQ.controller + item.url + tail + item.url_parms);
128+
} else {
129+
miqToolbarOnClick.bind($event.delegateTarget)($event);
130+
}
131+
}
132+
133+
ToolbarController.prototype.initObject = function(toolbarString) {
134+
subscribeToSubject.bind(this)();
135+
this.updateToolbar(JSON.parse(toolbarString));
136+
}
137+
138+
ToolbarController.prototype.onUpdateToolbar = function(toolbarObject) {
139+
this.updateToolbar(toolbarObject);
140+
if(!this.$scope.$$phase) {
141+
this.$scope.$digest();
142+
}
143+
}
144+
145+
ToolbarController.prototype.onUpdateItem = function(updateData) {
146+
_.find(_.flatten(this.toolbarItems), {id: updateData.update})[updateData.type] = updateData.value;
147+
if(!this.$scope.$$phase) {
148+
this.$scope.$digest();
149+
}
150+
}
151+
152+
ToolbarController.prototype.updateToolbar = function(toolbarObject) {
153+
toolbarItems = this.MiQToolbarSettingsService.generateToolbarObject(toolbarObject);
154+
this.toolbarItems = toolbarItems.items;
155+
this.dataViews = toolbarItems.dataViews;
156+
this.defaultViewUrl();
157+
this.setClickHandler();
158+
}
159+
160+
ToolbarController.$inject = ['MiQToolbarSettingsService', 'MiQEndpointsService', '$scope', '$location'];
161+
miqHttpInject(angular.module('ManageIQ.toolbar'))
162+
.controller('miqToolbarController', ToolbarController);
163+
})();

app/assets/javascripts/miq_application.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,8 @@ function miqUpdateAllCheckboxes(button_div) {
407407
function miqUpdateButtons(obj, button_div) {
408408
var count = 0;
409409

410+
sendDataWithRx({rowSelect: obj});
411+
410412
if (typeof obj.id != "undefined") {
411413
$("input[id^='check_']").each(function () {
412414
if (this.checked && !this.disabled) {
@@ -1389,8 +1391,14 @@ function miqAccordionSwap(_collapse, expand) {
13891391

13901392
// This function is called in miqOnLoad
13911393
function miqInitToolbars() {
1392-
$("#toolbar button:not(.dropdown-toggle), #toolbar ul.dropdown-menu > li > a, #toolbar .toolbar-pf-view-selector > ul.list-inline > li > a").off('click');
1393-
$("#toolbar button:not(.dropdown-toggle), #toolbar ul.dropdown-menu > li > a, #toolbar .toolbar-pf-view-selector > ul.list-inline > li > a").click(miqToolbarOnClick);
1394+
$("#toolbar:not(.miq-toolbar-menu) button:not(.dropdown-toggle), "+
1395+
"#toolbar:not(.miq-toolbar-menu) ul.dropdown-menu > li > a, "+
1396+
"#toolbar:not(.miq-toolbar-menu) .toolbar-pf-view-selector > ul.list-inline > li > a"
1397+
).off('click');
1398+
$("#toolbar:not(.miq-toolbar-menu) button:not(.dropdown-toggle), " +
1399+
"#toolbar:not(.miq-toolbar-menu) ul.dropdown-menu > li > a, "+
1400+
"#toolbar:not(.miq-toolbar-menu) .toolbar-pf-view-selector > ul.list-inline > li > a"
1401+
).click(miqToolbarOnClick);
13941402
}
13951403

13961404
// Function to run transactions when toolbar button is clicked
@@ -1473,7 +1481,7 @@ function miqToolbarOnClick(_e) {
14731481
tb_url += "/" + ManageIQ.record.recordId;
14741482
}
14751483
tb_url += "?pressed=";
1476-
if (typeof button.data('pressed') == "undefined") {
1484+
if (typeof button.data('pressed') == "undefined" && button.data('click')) {
14771485
tb_url += button.data('click').split("__").pop();
14781486
} else {
14791487
tb_url += button.data('pressed');

app/assets/javascripts/miq_explorer.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,12 @@ ManageIQ.explorer.processReplaceRightCell = function(data) {
184184
.html(data.rightCellText);
185185
}
186186

187-
if (_.isObject(data.reloadToolbars)) {
187+
188+
if (_.isArray(data.reloadToolbars)) {
189+
ManageIQ.angular.rxSubject.onNext({
190+
redrawToolbar: data.reloadToolbars
191+
})
192+
} else if (_.isObject(data.reloadToolbars)) {
188193
_.forEach(data.reloadToolbars, function (content, element) {
189194
$('#' + element).html(content);
190195
});

app/assets/javascripts/miq_toolbar.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,35 @@ ManageIQ.toolbars.findByDataClick = function (toolbar, attr_click) {
66

77
ManageIQ.toolbars.enableItem = function (toolbar, attr_click) {
88
ManageIQ.toolbars.findByDataClick(toolbar, attr_click).removeClass('disabled');
9+
ManageIQ.angular.rxSubject.onNext({update: attr_click, type: 'enabled', value: true});
910
};
1011

1112
ManageIQ.toolbars.disableItem = function (toolbar, attr_click) {
1213
ManageIQ.toolbars.findByDataClick(toolbar, attr_click).addClass('disabled');
14+
ManageIQ.angular.rxSubject.onNext({update: attr_click, type: 'enabled', value: false});
1315
};
1416

1517
ManageIQ.toolbars.setItemTooltip = function (toolbar, attr_click, tooltip) {
1618
ManageIQ.toolbars.findByDataClick(toolbar, attr_click).attr('title', tooltip);
19+
ManageIQ.angular.rxSubject.onNext({update: attr_click, type: 'title', value: tooltip});
1720
};
1821

1922
ManageIQ.toolbars.showItem = function (toolbar, attr_click) {
2023
ManageIQ.toolbars.findByDataClick(toolbar, attr_click).show();
24+
ManageIQ.angular.rxSubject.onNext({update: attr_click, type: 'hidden', value: true});
2125
};
2226

2327
ManageIQ.toolbars.hideItem = function (toolbar, attr_click) {
2428
ManageIQ.toolbars.findByDataClick(toolbar, attr_click).hide();
29+
ManageIQ.angular.rxSubject.onNext({update: attr_click, type: 'hidden', value: true});
2530
};
2631

2732
ManageIQ.toolbars.markItem = function (toolbar, attr_click) {
2833
ManageIQ.toolbars.findByDataClick(toolbar, attr_click).addClass('active');
34+
ManageIQ.angular.rxSubject.onNext({update: attr_click, type: 'selected', value: true});
2935
};
3036

3137
ManageIQ.toolbars.unmarkItem = function (toolbar, attr_click) {
3238
ManageIQ.toolbars.findByDataClick(toolbar, attr_click).removeClass('active');
39+
ManageIQ.angular.rxSubject.onNext({update: attr_click, type: 'selected', value: false});
3340
};

app/assets/stylesheets/patternfly_overrides.scss

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,40 @@ body#dashboard {
518518
.scrollable {
519519
overflow: auto;
520520
}
521+
522+
/* begin toolbar styling (to be moved to the ui-components repo) */
523+
524+
.toolbar-pf .form-group { /*compensates for filter-pf not being implemented */
525+
padding-left: 0;
526+
}
527+
528+
.toolbar-pf-actions .btn-group .dropdown button img { /* styling for images (not part of toolbar-pf) */
529+
padding-right: 3px;
530+
}
531+
532+
.toolbar-pf .toolbar-pf-actions .form-group { /* adds padding between buttons when they wrap */
533+
margin-bottom: 10px !important
534+
}
535+
536+
.toolbar-pf .form-group .btn,
537+
.toolbar-pf .form-group .btn-group { /* overrides _toolbar.scss to account for intermediate Angular markup */
538+
margin-left: 5px;
539+
}
540+
541+
.form-group.miq-toolbar-group { /* fixes the display for the main dashboard toolbar only */
542+
display: inline-block;
543+
.miq-custom-html {
544+
form {
545+
display: inline-block;
546+
}
547+
.form-group {
548+
margin-bottom: 0 !important;
549+
border-right: 0;
550+
&:last-child {
551+
padding-right: 0px
552+
}
553+
}
554+
}
555+
}
556+
557+
/* end toolbar styling */

app/controllers/dashboard_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ def change_tab
9393
def show
9494
@layout = "dashboard"
9595
@dashboard = true
96+
@display = "dashboard"
97+
@lastaction = "show"
9698

9799
records = current_group.ordered_widget_sets
98100

app/helpers/application_helper/toolbar/custom.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
ApplicationHelper::Toolbar::Custom = Struct.new(:name, :args) do
2-
def render(_view_context)
2+
def render(view_context)
33
# FIXME: assigns? locals? view_binding? instance_data?
4-
@content = ApplicationController.renderer.render :partial => args[:partial]
4+
@content = view_context.render :partial => args[:partial]
55
end
66

77
attr_reader :content
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class ApplicationHelper::Toolbar::DashboardCenter < ApplicationHelper::Toolbar::Basic
2+
custom_content('custom', :partial => 'dashboard/dropdownbar')
3+
end

0 commit comments

Comments
 (0)