Project

General

Profile

« Previous | Next » 

Revision c1a8ccf1

Added by Daniel Lobato Garcia over 8 years ago

Fixes #10929 - Add removed widgets to dashboard

This commit allows users to re-add widgets. At this point it's only
possible to recover removed widgets by clicking on "Reset to default".

To do this I populate the 'Add widgets' list by getting a diff
between the current widgets and the available ones. The code calls any
available widget 'default_widget', so keep that in mind.

After removing a widget, we reload the page, which is fairly fast thanks
to turbolinks. This is so that we populate the 'Add widgets' list.

Clicking on the widget to add will trigger a POST call that will add the
widget to User.current.widgets and reload the page. The reason why I
need to reload the page is to get the data in the new widget, otherwise
we would load an empty widget. It's not optimal but turbolinks makes it
fast.

(cherry picked from commit 24fc15c59e0acb589ef46a8f60e8ce76e72fd8d2)

View differences:

app/assets/javascripts/dashboard.js
$(document).on('ContentLoad', function(){start_gridster()});
$(document).on("click",".widget_control .minimize" ,function(){ hide_widget(this);});
$(document).on("click",".widget_control .remove" ,function(){ remove_widget(this);});
function start_gridster(){
var gridster = $(".gridster>ul").gridster({
widget_margins: [10, 10],
widget_base_dimensions: [82, 340],
......
gridster.remove_widget(widget);
$(".gridster>ul").append(widget);
fill_restore_list();
}
function remove_widget(item){
......
var gridster = $(".gridster>ul").gridster().data('gridster');
if (confirm(__("Are you sure you want to delete this widget from your dashboard?"))){
$.ajax({
type: 'delete',
type: 'DELETE',
url: $(item).data('url'),
success: function(){
$.jnotify(__("Widget removed from dashboard."), 'success', false);
gridster.remove_widget(widget);
gridster.remove_widget(widget);
window.location.reload();
},
error: function(){
$.jnotify(__("Error removing widget from dashboard."), 'error', true);
......
}
}
function add_widget(name){
$.ajax({
type: 'POST',
url: 'widgets',
data: {'name': name},
success: function(){
$.jnotify(__("Widget added to dashboard."), 'success', false);
window.location.reload();
},
error: function(){
$.jnotify(__("Error adding widget to dashboard."), 'error', true);
},
dataType: 'json'
});
}
function save_position(path){
var positions = serialize_grid();
$.ajax({type: 'POST',
url: path,
data: {'widgets': positions},
success: function(){
$.jnotify(__("Widget positions successfully saved."), 'success', false);
},
error: function(){
$.jnotify(__("Failed to save widget positions."), 'error', true);
},
dataType: 'json'});
$.ajax({
type: 'POST',
url: path,
data: {'widgets': positions},
success: function(){
$.jnotify(__("Widget positions successfully saved."), 'success', false);
},
error: function(){
$.jnotify(__("Failed to save widget positions."), 'error', true);
},
dataType: 'json'
});
}
function serialize_grid(){
......
return result;
}
function fill_restore_list(){
$("ul>li.widget-restore").remove();
var restore_list = [];
var hidden_widgets = $(".gridster>ul>li[data-hide='true']");
if (hidden_widgets.exists()){
hidden_widgets.each(function(i, widget) {
restore_list.push( "<li class='widget-restore'><a href='#' onclick='show_widget(\""+$(widget).attr('data-id')+"\")'>" + $(widget).attr('data-name') + "</a></li>" );
restore_list.push("<li class='widget-restore'><a href='#' onclick='show_widget(\"" +
$(widget).attr('data-id') + "\")'>" +
$(widget).attr('data-name') + "</a></li>");
});
} else {
restore_list.push("<li class='widget-restore'><a>" + __('Nothing to restore') + "</a></li>");
}
$('#restore_list').parent('ul').append(restore_list.join(" "));
$('#restore_list').after(restore_list.join(" "));
}
function show_widget(id){
app/controllers/dashboard_controller.rb
end
def create
Dashboard::Manager.add_widget_to_user(User.current, params[:widget])
redirect_to root_path
widget = Dashboard::Manager.find_default_widget_by_name(params[:name])
(not_found and return) unless widget.present?
Dashboard::Manager.add_widget_to_user(User.current, widget.first)
render :json => { :name => params[:name] }, :status => :ok
end
def destroy
app/helpers/dashboard_helper.rb
def dashboard_actions
[_("Generated at %s") % Time.zone.now.to_s(:short),
select_action_button(_("Manage dashboard"), {},
link_to_function(_("Save dashboard"), "save_position('#{save_positions_widgets_path}')"),
link_to(_("Reset to default"), reset_default_widgets_path, :method => :put),
content_tag(:li,'',:class=>'divider'),
content_tag(:li,_("Restore widgets"), :class=>'nav-header', :id=>'restore_list' )
select_action_button(
_("Manage dashboard"), {},
link_to_function(_("Save dashboard"), "save_position('#{save_positions_widgets_path}')"),
link_to(_("Reset to default"), reset_default_widgets_path, :method => :put),
content_tag(:li, '', :class=>'divider'),
content_tag(:li, _("Restore widgets"), :class=>'nav-header', :id=>'restore_list'),
content_tag(:li, '', :class=>'divider'),
content_tag(:li, _("Add widgets"), :class=>'nav-header'),
content_tag(:li, '', :class=>'widget-add') do
widgets_to_add
end
)]
end
def removed_widgets
Dashboard::Manager.default_widgets - User.current.widgets.map(&:to_hash)
end
def widgets_to_add
return link_to(_('Nothing to add'), '#') unless removed_widgets.present?
removed_widgets.each do |removed_widget|
concat(link_to_function(_(removed_widget[:name]),
"add_widget('#{removed_widget[:name]}')"))
end
end
def render_widget(widget)
render(:partial => widget.template, :locals => widget.data)
end
app/models/widget.rb
serialize :data
before_validation :default_values
before_validation :default_values
def default_values
self.sizex ||= 4
......
self.hide ||= false
self.data ||= {}
end
# Returns widget representation as the hash object Dashboard::Manager uses in memory
def to_hash
{ :template => template, :sizex => sizex, :sizey => sizey, :name => name }
end
end
app/services/dashboard/manager.rb
add_widget_to_user(user, widget)
}
end
def self.find_default_widget_by_name(name)
@default_widgets.select { |widget| widget[:name] == name }
end
end
end
test/functional/dashboard_controller_test.rb
require 'test_helper'
class DashboardControllerTest < ActionController::TestCase
test "should get index" do
test 'should get index' do
get :index, {}, set_session_user
assert_response :success
end
test 'create returns 404 if widget to add is not found' do
post :create, { :name => 'non-existent-widget' }, set_session_user
assert_response :not_found
end
test 'create adds widget to user if widget is valid' do
assert_difference('users(:admin).widgets.count', 1) do
post :create, { :name => 'Status table' }, set_session_user
end
assert_response :success
end
end
test/integration/dashboard_test.rb
test "dashboard link hosts with alerts disabled" do
assert_dashboard_link 'Hosts with alerts disabled'
end
test 'widgets not in dashboard show up in list' do
deleted_widget = users(:admin).widgets.last
users(:admin).widgets.destroy(deleted_widget)
Capybara.reset_sessions!
login_admin
visit dashboard_path
assert_equal deleted_widget.name, page.find('li.widget-add a').text
end
end

Also available in: Unified diff