Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Refresh button to individual Dashboard Widget #6334

Merged
merged 18 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions app/controllers/dashboard_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ def start_url

def widget_chart_data
widget = find_record_with_rbac(MiqWidget, params[:id])
datum = widget.contents_for_user(current_user).contents
widget_content = widget.contents_for_user(current_user)
blank = widget_content.blank?
datum = blank ? nil : widget_content.contents
content = nil
if datum.blank?
state = 'no_data'
Expand All @@ -159,6 +161,7 @@ def widget_chart_data
end
render :json => {:content => content,
:minimized => widget_minimized?(params[:id]),
:blank => blank,
:state => state}
end

Expand All @@ -170,7 +173,8 @@ def widget_menu_data
{:description => shortcut.description, :href => shortcut.miq_shortcut.url}
end
render :json => {:shortcuts => shortcuts,
:minimized => widget_minimized?(params[:id])}
:minimized => widget_minimized?(params[:id]),
:blank => false}
end

def widget_minimized?(id)
Expand All @@ -180,8 +184,12 @@ def widget_minimized?(id)

def widget_report_data
widget = find_record_with_rbac(MiqWidget, params[:id])
widget_content = widget.contents_for_user(current_user)
blank = widget_content.blank?
content = blank ? nil : widget_content.contents
render :json => {
:content => widget.contents_for_user(current_user).contents,
:blank => blank,
:content => content,
:minimized => widget_minimized?(params[:id])
}
end
Expand Down Expand Up @@ -360,6 +368,17 @@ def widget_zoom
end
end

def widget_refresh
assert_privileges("widget_generate_content")
w = MiqWidget.find(params[:widget])
task_id = w.queue_generate_content
if task_id
render :json => {:task_id => task_id.to_s}, :status => 200
else
render :json => {:error => {:message => _("There was an error during refresh.")}}, :status => 400
end
end

# A widget has been dropped
def widget_dd_done
if params[:col1] || params[:col2] || params[:col3]
Expand Down
12 changes: 10 additions & 2 deletions app/javascript/angular/dashboard/dropdown-menu.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
ManageIQ.angular.app.component('dropdownMenu', {
bindings: {
widgetId: '@',
buttonsData: '@',
buttonsData: '<',
},
controllerAs: 'vm',
controller() {
const vm = this;

vm.$onInit = function() {
vm.dropdown_id = `btn_${vm.widgetId}`;
vm.buttons = JSON.parse(vm.buttonsData);
vm.buttons = vm.buttonsData;
};

vm.click = function(button) {
if (button.onclick) {
return button.onclick();
}
return true;
};
},
template: `
Expand All @@ -29,6 +36,7 @@ ManageIQ.angular.app.component('dropdownMenu', {
data-method="{{button.dataMethod}}"
data-miq_sparkle_on="{{button.sparkleOn ? 'true' : 'false'}}"
href="{{button.href}}"
ng-click="vm.click(button)"
id="{{button.id}}"
ng-attr-data-remote="{{button.dataRemote}}"
ng-attr-target="{{button.target}}"
Expand Down
71 changes: 48 additions & 23 deletions app/javascript/angular/dashboard/widget-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ ManageIQ.angular.app.component('widgetWrapper', {
widgetId: '@',
widgetType: '@',
widgetButtons: '@',
widgetBlank: '@',
widgetTitle: '@',
widgetLastRun: '@',
widgetNextRun: '@',
},
controllerAs: 'vm',
controller: ['$http', 'miqService', '$sce', function($http, miqService, $sce) {
controller: ['$http', 'miqService', '$sce', 'API', function($http, miqService, $sce, API) {
const vm = this;

const widgetTypeUrl = {
Expand All @@ -26,23 +25,49 @@ ManageIQ.angular.app.component('widgetWrapper', {
vm.$onInit = function() {
vm.divId = `w_${vm.widgetId}`;
vm.innerDivId = `dd_w${vm.widgetId}_box`;
vm.refreshWidgetHTML(false);
vm.parsedButtons = JSON.parse(vm.widgetButtons);
const refreshButton = vm.parsedButtons.find(ob => ob.id.includes("refresh"));
himdel marked this conversation as resolved.
Show resolved Hide resolved
if (refreshButton) {
refreshButton.onclick = vm.refresh;
};
};

if (vm.widgetBlank === 'false') {
$http.get(vm.widgetUrl())
.then((response) => {
vm.widgetModel = response.data;
// if there's html make it passable
if (vm.widgetModel.content) {
vm.widgetModel.content = $sce.trustAsHtml(vm.widgetModel.content);
}
deferred.resolve();
})
.catch((e) => {
vm.error = true;
miqService.handleFailure(e);
deferred.reject();
});
}
vm.refreshWidgetHTML = function(refreshed) {
return $http.get(vm.widgetUrl())
.then((response) => {
vm.widgetModel = response.data;
// if there's html make it passable
if (vm.widgetModel.content) {
vm.widgetModel.content = $sce.trustAsHtml(vm.widgetModel.content);
}
if (refreshed) {
miqSparkleOff();
add_flash(sprintf(__('Dashboard "%s" was refreshed'), vm.widgetTitle), 'success');
}
vm.error = false;
deferred.resolve();
})
.catch((e) => {
vm.error = true;
vm.widgetModel = null;
miqService.handleFailure(e);
deferred.reject();
});
};

vm.refresh = function() {
$http.post(`/dashboard/widget_refresh/?widget=${vm.widgetId}`)
.then((response) => {
vm.widgetModel = null;
return API.wait_for_task(response.data.task_id).then(vm.refreshWidgetHTML(true));
ZitaNemeckova marked this conversation as resolved.
Show resolved Hide resolved
})
.catch((e) => {
vm.error = true;
vm.widgetModel = null;
miqService.handleFailure(e);
deferred.reject();
});
};

vm.widgetUrl = function() {
Expand All @@ -59,20 +84,20 @@ ManageIQ.angular.app.component('widgetWrapper', {
<div class="card-pf-body">
<div class="card-pf-heading-kebab">
<dropdown-menu widget-id="{{vm.widgetId}}"
buttons-data="{{vm.widgetButtons}}"></dropdown-menu>
buttons-data="vm.parsedButtons"></dropdown-menu>
<h2 class="card-pf-title sortable-handle ui-sortable-handle"
style="cursor:move">
{{vm.widgetTitle}}
</h2>
</div>
</div>
<widget-error ng-if="vm.error === true"></widget-error>
<widget-spinner ng-if="!vm.widgetModel && vm.widgetBlank == 'false' && !vm.error"></widget-spinner>
<div ng-if="vm.widgetBlank === 'true' || vm.widgetModel"
<widget-spinner ng-if="!vm.widgetModel && !vm.error"></widget-spinner>
<div ng-if="vm.widgetModel"
ng-attr-id="{{vm.innerDivId}}"
ng-class="{ hidden: vm.widgetModel.minimized, mc:true }">
<widget-empty ng-if="vm.widgetBlank === 'true'"></widget-empty>
<div ng-if="vm.widgetBlank === 'false'"
<widget-empty ng-if="vm.widgetModel.blank === true"></widget-empty>
<div ng-if="vm.widgetModel.blank === false"
ng-switch on="vm.widgetType">
<widget-menu ng-switch-when="menu"
widget-id="{{vm.widgetId}}"
Expand Down
35 changes: 28 additions & 7 deletions app/javascript/spec/dashboard/widget-empty.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { module, inject } from './mocks';
require('../helpers/API.js');

require('../helpers/getJSONFixtures.js');

Expand All @@ -7,28 +8,48 @@ describe('widget-empty', () => {
let element;
let $compile;

beforeEach(module('ManageIQ'));
beforeEach(inject((_$compile_, $rootScope) => {
beforeEach(() => {
module('ManageIQ');
angular.mock.module('miq.api');
});

beforeEach(inject((_$compile_, $rootScope, $http) => {
$scope = $rootScope;
$scope.miqButtonClicked = () => null;
$scope.validForm = true;
$compile = _$compile_;
const response = {
data: {
content: null,
minimized: false,
blank: true,
},
status: 200,
statusText: 'OK',
};
spyOn($http, 'get').and.callFake(() => Promise.resolve(response));
spyOn(window.vanillaJsAPI, 'post').and.returnValue(Promise.resolve({
results: [
{ success: true, message: 'some' },
],
}));
}));

it('is rendered in widget-wrapper if widget-blank is set to true', (done) => {
it('is rendered in widget-wrapper if blank is set to true', (done) => {
element = angular.element(`
<form name="angularForm">
<widget-wrapper widget-id="42" widget-blank="true" widget-buttons="null"></widget-wrapper>
<widget-wrapper widget-id="42" widget-buttons="[]" widget-type="report"></widget-wrapper>
</form>
`);
element = $compile(element)($scope);

$scope.$digest();

setTimeout(() => {
const $ctrl = element.find('widget-wrapper').find('div').scope().vm;
$ctrl.promise.catch(() => null).then(() => {
$scope.$digest();

const widget = element.find('widget-empty');
expect(widget).toHaveLength(1);

done();
});
});
Expand Down
14 changes: 12 additions & 2 deletions app/javascript/spec/dashboard/widget-wrapper.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { module, inject } from './mocks';
require('../helpers/API.js');

require('../helpers/getJSONFixtures.js');

Expand All @@ -8,7 +9,10 @@ describe('widget-wrapper', () => {
let $compile;
const widgetTypes = ['chart', 'menu', 'report'];

beforeEach(module('ManageIQ'));
beforeEach(() => {
module('ManageIQ');
angular.mock.module('miq.api');
});

beforeEach(inject((_$compile_, $rootScope, $http) => {
$scope = $rootScope;
Expand All @@ -20,18 +24,24 @@ describe('widget-wrapper', () => {
content: '<div></div>',
minimized: false,
shortcuts: [],
blank: false,
},
status: 200,
statusText: 'OK',
};
spyOn($http, 'get').and.callFake(() => Promise.resolve(response));
spyOn(window.vanillaJsAPI, 'post').and.returnValue(Promise.resolve({
results: [
{ success: true, message: 'some' },
],
}));
}));

widgetTypes.forEach((widget) => {
it(`renders widget-${widget} when widget-type is ${widget}`, (done) => {
element = angular.element(`
<form name="angularForm">
<widget-wrapper widget-id="42" widget-blank="false" widget-buttons="null" widget-type="${widget}"></widget-wrapper>
<widget-wrapper widget-id="42" widget-blank="false" widget-buttons="[]" widget-type="${widget}"></widget-wrapper>
</form>
`);
element = $compile(element)($scope);
Expand Down
11 changes: 10 additions & 1 deletion app/presenters/widget_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,20 @@ def widget_buttons
:title => _("Zoom in on this chart"),
:name => _("Zoom in"),
:href => '/dashboard/widget_zoom?widget=' + @widget.id.to_s,
:fonticon => 'fa fa-plus fa-fw',
:fonticon => 'fa fa-plus fa-fw',
:dataRemote => true,
:sparkleOn => true,
:dataMethod => 'post')
end
if @widget.content_type != 'menu'
buttons.push(:id => "w_#{@widget.id}_refresh",
:title => _("Refresh this Widget"),
:name => _("Refresh"),
:fonticon => 'fa fa-refresh fa-fw',
:href => 'javascript:;',
:refresh => true)
end

buttons.to_json
end

Expand Down
2 changes: 0 additions & 2 deletions app/views/dashboard/_widget.html.haml
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
%div{:id => "ww_#{presenter.widget.id}"}
- last_run, next_run = last_next_run(presenter.widget)
- widget_blank = presenter.widget.content_type == 'menu' ? false : presenter.widget.contents_for_user(current_user).blank?
%widget-wrapper{"widget-id" => presenter.widget.id,
"widget-type" => presenter.widget.content_type,
"widget-buttons" => presenter.widget_buttons,
"widget-blank" => widget_blank,
"widget-last-run" => last_run,
"widget-next-run" => next_run,
"widget-title" => presenter.widget.title}
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,7 @@
widget_add
widget_close
widget_dd_done
widget_refresh
widget_toggle_minmax
widget_zoom
)
Expand Down