import java.lang.annotation.RetentionPolicy;\r
import java.lang.annotation.Target;\r
\r
-/**\r
- * Created by IntelliJ IDEA.\r
- * User: dreik\r
- * Date: 09.08.2010\r
- * Time: 10:33:35\r
- */\r
@Retention(RetentionPolicy.RUNTIME)\r
@Target(ElementType.TYPE)\r
public @interface WidgetProperty {\r
\r
String key();\r
\r
- String defaultValue() default "";\r
+ String type() default "STRING";\r
\r
- String name();\r
+ String defaultValue() default "";\r
\r
String description() default "";\r
\r
- String type() default "STRING";\r
-\r
- String parameter() default "";\r
-\r
boolean optional() default true;\r
}\r
SECTION=Navigation::SECTION_RESOURCE
- verify :method => :post, :only => [:set_layout, :add_widget, :set_dashboard], :redirect_to => {:action => :index}
+ verify :method => :post, :only => [:set_layout, :add_widget, :set_dashboard, :save_widget], :redirect_to => {:action => :index}
before_filter :login_required, :except => [:index]
def index
widget=@dashboard.widgets.to_a.find { |i| i.id==id.to_i() }
if widget
widget.column_index=index+1
- widget.order_index=order+1
+ widget.row_index=order+1
widget.save!
all_ids<<widget.id
end
new_widget=dashboard.widgets.create(:widget_key => definition.getId(),
:name => definition.getTitle(),
:column_index => dashboard.number_of_columns,
- :order_index => dashboard.column_size(dashboard.number_of_columns) + 1,
- :state => Widget::STATE_ACTIVE)
+ :row_index => dashboard.column_size(dashboard.number_of_columns) + 1,
+ :configured => !definition.isEditable())
widget_id=new_widget.id
end
end
redirect_to :action => 'configure', :id => dashboard.id, :resource => params[:resource], :highlight => widget_id
end
+
+ def save_widget
+ widget=Widget.find(params[:id].to_i)
+ #TODO check owner of dashboard
+ definition=java_facade.getWidget(widget.widget_key)
+ errors_by_property_key={}
+ definition.getProperties().each do |property_def|
+ value=params[property_def.key()] || property_def.defaultValue()
+ value='false' if value.empty? && property_def.type()==WidgetProperty::TYPE_BOOLEAN
+
+ errors=WidgetProperty.validate_definition(property_def, value)
+ if errors.empty?
+ widget.set_property(property_def.key(), value)
+ else
+ widget.unset_property(property_def.key())
+ errors_by_property_key[property_def.key()]=errors
+ end
+ end
+
+ if errors_by_property_key.empty?
+ widget.configured=true
+ widget.save
+ widget.properties.each {|p| p.save}
+ render :update do |page|
+ page.redirect_to(url_for(:action => :configure, :id => widget.dashboard_id, :resource => params[:resource]))
+ end
+ else
+ widget.configured=false
+ widget.save
+ render :update do |page|
+ page.alert('errors ' + errors_by_property_key.inspect)
+ end
+ end
+ end
+
private
def load_dashboard
def load_widget_definitions()
@widget_definitions = java_facade.getWidgets()
end
+
end
\ No newline at end of file
def active_widgets_ids_formatted(column)
active_widget_ids=[]
- @dashboard.widgets.find(:all, :conditions => {:column_index => column}, :order => :order_index).each do |widget|
+ @dashboard.widgets.find(:all, :conditions => {:column_index => column}, :order => 'row_index ASC').each do |widget|
widget_view=nil
found_index=-1
@widgets.each_with_index {|item, index|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
#\r
module WidgetPropertiesHelper\r
- VALUE_TYPE_INT = 'INT'\r
- VALUE_TYPE_BOOLEAN = 'BOOL'\r
- VALUE_TYPE_FLOAT = 'FLOAT'\r
- VALUE_TYPE_STRING = 'STRING'\r
- VALUE_TYPE_REGEXP = 'REGEXP'\r
+ \r
\r
def valid_property_value?(type, value, parameter="")\r
- if type==VALUE_TYPE_INT\r
+ if type==WidgetProperty::TYPE_INTEGER\r
value.to_i.to_s == value\r
\r
- elsif type==VALUE_TYPE_FLOAT\r
+ elsif type==WidgetProperty::TYPE_FLOAT\r
true if Float(value) rescue false\r
\r
- elsif type==VALUE_TYPE_BOOLEAN\r
+ elsif type==WidgetProperty::TYPE_BOOLEAN\r
value=="1" || value=="0"\r
\r
- elsif type==VALUE_TYPE_STRING\r
+ elsif type==WidgetProperty::TYPE_STRING\r
true\r
\r
- elsif type==VALUE_TYPE_REGEXP\r
- value.to_s.match(parameter) == nil ? false : true\r
-\r
else\r
false\r
end\r
end\r
\r
- def property_value_field(type, fieldname, value, param_value="")\r
- val= param_value ? param_value : value\r
- \r
- if type==VALUE_TYPE_INT\r
- text_field_tag fieldname, val , :size => 10\r
+ def property_value_field(definition, value)\r
+ val=value || definition.defaultValue()\r
+ if definition.type()==WidgetProperty::TYPE_INTEGER\r
+ text_field_tag definition.key(), val, :size => 10\r
\r
- elsif type==VALUE_TYPE_FLOAT\r
- text_field_tag fieldname, val, :size => 10\r
+ elsif definition.type()==WidgetProperty::TYPE_FLOAT\r
+ text_field_tag definition.key(), val, :size => 10\r
\r
- elsif type==VALUE_TYPE_BOOLEAN\r
- opts="<option value=''>Select value</option>"\r
- opts+="<option value='1'"+(val=="1" ? " selected" : "" )+">Yes</option>"\r
- opts+="<option value='0'"+(val=="0" ? " selected" : "" )+">No</option>"\r
- select_tag fieldname, opts\r
+ elsif definition.type()==WidgetProperty::TYPE_BOOLEAN\r
+ check_box_tag definition.key(), "true", val=='true'\r
\r
- elsif type==VALUE_TYPE_STRING\r
- text_field_tag fieldname, val, :size => 10\r
+ elsif definition.type()==WidgetProperty::TYPE_STRING\r
+ text_field_tag definition.key(), val, :size => 10\r
\r
- elsif type==VALUE_TYPE_REGEXP\r
- text_field_tag fieldname, val, :size => 10\r
else\r
- hidden_field_tag fieldname\r
+ hidden_field_tag definition.key()\r
end\r
end\r
\r
class Dashboard < ActiveRecord::Base\r
belongs_to :user\r
\r
- has_many :widgets, :include => 'widget_properties', :dependent => :delete_all\r
+ has_many :widgets, :include => 'properties', :dependent => :delete_all\r
has_many :active_dashboards, :dependent => :delete_all\r
\r
validates_length_of :name, :within => 1..256\r
end\r
\r
def column_size(column_index)\r
- last_widget=widgets.select{|w| w.column_index==column_index}.max{|x,y| x.order_index <=> y.order_index}\r
- last_widget ? last_widget.order_index : 0\r
+ last_widget=widgets.select{|w| w.column_index==column_index}.max{|x,y| x.row_index <=> y.row_index}\r
+ last_widget ? last_widget.row_index : 0\r
end\r
\r
def deep_copy()\r
self.widgets.each do |child|\r
new_widget = Widget.create(child.attributes)\r
\r
- child.widget_properties.each do |prop|\r
+ child.properties.each do |prop|\r
widget_prop = WidgetProperty.create(prop.attributes)\r
- new_widget.widget_properties << widget_prop\r
+ new_widget.properties << widget_prop\r
end\r
\r
new_widget.save\r
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
#\r
class Widget < ActiveRecord::Base\r
- STATE_ACTIVE='A'\r
- STATE_INACTIVE='I'\r
- \r
- has_many :widget_properties, :dependent => :delete_all\r
+ has_many :properties, :dependent => :delete_all, :class_name => 'WidgetProperty'\r
belongs_to :dashboards\r
\r
validates_presence_of :name\r
validates_presence_of :widget_key\r
validates_length_of :widget_key, :within => 1..256\r
\r
- validates_length_of :description, :maximum => 1000, :allow_blank => true, :allow_nil => true\r
-\r
- def state\r
- read_attribute(:state) || 'V'\r
- end\r
-\r
#---------------------------------------------------------------------\r
# WIDGET PROPERTIES\r
#---------------------------------------------------------------------\r
- def properties\r
- widget_properties\r
- end\r
- \r
- def widget_property(key)\r
- widget_properties().each do |p|\r
+ def property(key)\r
+ properties().each do |p|\r
return p if (p.key==key)\r
end\r
nil\r
end\r
\r
- def widget_property_value(key)\r
- prop=widget_property(key)\r
- prop ? prop.value : nil\r
+ def property_value(key, default_value=nil)\r
+ prop=property(key)\r
+ (prop ? prop.value : nil) || default_value\r
end\r
\r
- def set_widget_property(options)\r
- key=options[:kee]\r
- prop=widget_property(key)\r
+ def set_property(key, value)\r
+ prop=property(key)\r
if prop\r
- prop.attributes=options\r
- prop.widget_id=id\r
- prop.save!\r
+ prop.text_value=value\r
else\r
- prop=WidgetProperty.new(options)\r
- prop.widget_id=id\r
- widget_properties<<prop\r
+ self.properties.build(:kee => key, :text_value => value)\r
end\r
+ properties_as_hash[key]=value\r
end\r
\r
- def delete_widget_property(key)\r
- prop=widget_property(key)\r
+ def unset_property(key)\r
+ prop=property(key)\r
+ self.properties.delete(prop) if prop\r
+ end\r
+\r
+ def delete_property(key)\r
+ prop=property(key)\r
if prop\r
- widget_properties.delete(prop)\r
+ properties.delete(prop)\r
end\r
end\r
\r
def properties_as_hash\r
- hash={}\r
- widget_properties.each do |prop|\r
- hash[prop.key]=prop.value\r
- end\r
- hash\r
+ @properties_hash ||=\r
+ begin\r
+ hash={}\r
+ properties.each do |prop|\r
+ hash[prop.key]=prop.value\r
+ end\r
+ hash\r
+ end\r
+ @properties_hash\r
end\r
end
\ No newline at end of file
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
#\r
class WidgetProperty < ActiveRecord::Base\r
+ TYPE_INTEGER = 'INTEGER'\r
+ TYPE_BOOLEAN = 'BOOLEAN'\r
+ TYPE_FLOAT = 'FLOAT'\r
+ TYPE_STRING = 'STRING'\r
\r
- belongs_to :widgets\r
+ belongs_to :widget\r
\r
- validates_presence_of :kee\r
validates_length_of :kee, :within => 1..100\r
- validates_length_of :description, :maximum => 4000, :allow_blank => true, :allow_nil => true\r
validates_length_of :text_value, :maximum => 4000, :allow_blank => true, :allow_nil => true\r
\r
def key\r
- kee\r
- end\r
+ kee\r
+ end\r
\r
def value\r
- text_value\r
+ text_value\r
end\r
\r
def to_hash_json\r
end\r
xml\r
end\r
- \r
+\r
+ def self.validate_definition(definition, value)\r
+ errors=[]\r
+ if value.empty?\r
+ errors<<"Missing value" unless definition.optional()\r
+ else\r
+ errors<<"Please type an integer (example: 123)" if definition.type()==TYPE_INTEGER && value.to_i.to_s!=value\r
+ if definition.type()==TYPE_FLOAT\r
+ begin\r
+ Float(value)\r
+ rescue\r
+ errors<<"Please type a number (example: 123.45)"\r
+ end\r
+ end\r
+ errors<<"Please check value" if definition.type()==TYPE_BOOLEAN && !(value=="true" || value=="false")\r
+ end\r
+ errors\r
+ end\r
end
\ No newline at end of file
<a class="block-view-toggle" onclick="portal.editWidget(<%= widget.id -%>);return false;">Edit</a>
<% end %>
</div>
-<% if defined?(validation_result) %>
- <div class="error" style="<%= "display: none;" unless validation_result["errormsg"] %>clear:both;margin: 0;border-bottom:0;">
- <span class="errormsg"><%= validation_result["errormsg"] if validation_result["errormsg"] %></span> [<a href="#" onclick="hide_block_info($(this).up('.block'));return false;">hide</a>]
- </div>
- <div class="notice" style="<%= "display: none;" unless validation_result["infomsg"] %>clear:both;margin: 0;border-bottom:0;">
- <span class="infomsg"><%= validation_result["infomsg"] if validation_result["infomsg"] %></span> [<a href="#" onclick="hide_block_info($(this).up('.block'));return false;">hide</a>]
- </div>
-<% end %>
-<div class="widget_props" id="widget_props_<%= widget.id -%>" style="display: none">
- <% form_remote_tag :url => {:action => 'save_widget', :id => @dashboard.id}, :method => :post do -%>
- <table class="form" align="center" style="border-collapse:separate;border-spacing:5px;">
+<div class="widget_props" id="widget_props_<%= widget.id -%>" style="<%= 'display:none' if widget.configured -%>">
+ <% form_remote_tag :url => {:action => 'save_widget', :id => widget.id, :resource => params[:resource]}, :method => :post do -%>
+ <table class="form">
<tbody>
- <% definition.getProperties().each do |property|
- db_property_value=widget.widget_property_value(property.key())
- entered_value=params[property.key()]
- entered_value=property.defaultValue() if !entered_value || entered_value.empty?
+ <% definition.getProperties().each do |property_def|
+ value=widget.property_value(property_def.key(), property_def.defaultValue())
editrow_class=""
if defined?(validation_result)
- editrow_class= validation_result[property.key()]=="valid" ? "valid-editrow" : "invalid-editrow"
+ editrow_class= validation_result[property_def.key()]=="valid" ? "valid-editrow" : "invalid-editrow"
end
%>
<tr>
- <td class="first"><%= property.name() -%>:<br>
- <span style="font-size: 85%;font-weight: normal;">[<%= property.type()+" "+property.key() -%>]</span></td>
- <td id="row_<%= property.key() -%>" class="editrow <%= editrow_class %>" style="vertical-align: middle;"><%= property_value_field(property.type(), property.key(), db_property_value, entered_value) %><%= " *" unless property.optional() %>
- <br>
- <span style="font-size: 85%;font-weight: normal;">[<%= property.description() -%>]</span></td>
+ <td valign="top" nowrap><b><%= property_def.key() -%></b><%= "*" unless property_def.optional()==true -%>: </td>
+ <td id="row_<%= property_def.key() -%>">
+ <%= property_value_field(property_def, value) -%>
+ <span class="note"><%= property_def.description() -%></span>
+ </td>
</tr>
<% end %>
+ <tr>
+ <td colspan="2">
+ <%= submit_tag 'Save' %>
+ <% if widget.configured %>
+ <a href="#" onClick="portal.cancelEditWidget(<%= widget.id -%>);return false;">Cancel</a>
+ <% end %>
+ </td>
+ </tr>
</tbody>
</table>
<%= hidden_field_tag "widgetid", "", :class => "widgetid" %>
- <div align="center"><%= submit_tag 'Save' %> <a href="#" onClick="portal.cancelEditWidget(<%= widget.id -%>);return false;">Cancel</a></div>
-
<% end -%>
</div>
-<div id="widget_<%= widget.id -%>" class="configure_widget <%= definition.getId() -%>" style="height:100%;">
+<div id="widget_<%= widget.id -%>" class="configure_widget <%= definition.getId() -%>" style="height:100%;<%= 'display:none;' if !widget.configured -%>">
<!--[if lte IE 6]>
<style type="text/css">
#dashboard .block .content .transparent {
<div class="<%= definition.getId() %>" style="height:100%;">
-<%
- begin
- widget_body=render :inline => definition.getTarget().getTemplate(), :locals => {:widget_properties => widget.properties_as_hash}
- rescue => error
- logger.error("Can not render widget #{definition.getId()}: " + error)
- logger.error(error.backtrace.join("\n"))
- widget_body=""
- end
+<% if widget.configured %>
+ <%
+ begin
+ widget_body=render :inline => definition.getTarget().getTemplate(), :locals => {:widget_properties => widget.properties_as_hash}
+ rescue => error
+ logger.error("Can not render widget #{definition.getId()}: " + error)
+ logger.error(error.backtrace.join("\n"))
+ widget_body=""
+ end
- if widget_body.include?('<')
-%>
- <%= widget_body %>
-<%
- end
-%>
+ if widget_body.include?('<')
+ %>
+ <%= widget_body %>
+ <%
+ end
+ %>
+<% else %>
+ <div class="widget">
+ <p>Please configure the widget <b><%= definition.getTitle() -%></b>.</p>
+ </div>
+<% end %>
<div style="clear: both;"></div>
</div>
\ No newline at end of file
dashboardstate: 'dashboardstate',
toggle: 'block-toggle',
blocklist: 'widget_defs',
- highlight_duration: 3,
+ highlight_duration: 2,
highlight_startcolor: '#cae3f2',
highlight_endcolor: '#ffffff',
saveurl: '<%= url_for :action => 'set_dashboard', :id => @dashboard.id, :resource => @resource.id -%>'
<div class="column-handle" style="display: none"> </div>
<%
- @dashboard.widgets.select{|widget| widget.column_index==index}.sort_by{|widget| widget.order_index}.each do |widget|
+ @dashboard.widgets.select{|widget| widget.column_index==index}.sort_by{|widget| widget.row_index}.each do |widget|
widget_definition=@widget_definitions.find{|wd| wd.getId()==widget.widget_key }
if widget_definition
%>
<div class="dashboard-column-wrapper" style="width: <%= (columns.size()>0) ? columns[index-1].to_i : 100 %>%; clear: right;">
<div class="dashboard-column" id="dashboard-column-<%= index -%>" style="margin: 0px <%= index<columns.size() ? "5px" : "0px" %> 0px <%= index>1 ? "5px" : "0px" %>;">
<%
- @dashboard.widgets.select{|widget| widget.column_index==index}.sort_by{|widget| widget.order_index}.each do |widget|
+ @dashboard.widgets.select{|widget| widget.column_index==index}.sort_by{|widget| widget.row_index}.each do |widget|
widget_definition=@widget_definitions.find{|wd| wd.getId()==widget.widget_key }
if widget_definition
%>
t.column :name, :string, :null => true, :limit => 256
t.column :description, :string, :null => true, :limit => 1000
t.column :column_index, :integer, :null => true
- t.column :order_index, :integer, :null => true
- t.column :state, :string, :null => true, :limit => 1
+ t.column :row_index, :integer, :null => true
+ t.column :configured, :boolean, :null => true
t.timestamps
end
add_index :widgets, [:dashboard_id], :name => 'widgets_dashboards'
create_table :widget_properties do |t|
t.column :widget_id, :integer, :null => false
- t.column :description, :string, :null => true, :limit => 4000
t.column :kee, :string, :null => true, :limit => 100
t.column :text_value, :string, :null => true, :limit => 4000
end
def self.create_dashboard
dashboard=::Dashboard.new(:name => 'Dashboard', :shared => true, :description => 'Default dashboard', :column_layout => "50-50")
- dashboard.widgets.build(:widget_key => 'static_analysis', :name => 'Static analysis', :column_index => 1, :order_index => 1, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'comments_duplications', :name => 'Comments duplications', :column_index => 1, :order_index => 2, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'extended_analysis', :name => 'Extended analysis', :column_index => 1, :order_index => 3, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'code_coverage', :name => 'Code coverage', :column_index => 1, :order_index => 4, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'events', :name => 'Events', :column_index => 1, :order_index => 5, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'description', :name => 'Description', :column_index => 1, :order_index => 6, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'rules', :name => 'Rules', :column_index => 2, :order_index => 1, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'alerts', :name => 'Alerts', :column_index => 2, :order_index => 2, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'custom_measures', :name => 'Custom measures', :column_index => 2, :order_index => 3, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'file-design', :name => 'File design', :column_index => 2, :order_index => 4, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'package-design', :name => 'Package design', :column_index => 2, :order_index => 5, :state => Widget::STATE_ACTIVE)
- dashboard.widgets.build(:widget_key => 'ckjm', :name => 'CKJM', :column_index => 2, :order_index => 6, :state => Widget::STATE_ACTIVE)
+ dashboard.widgets.build(:widget_key => 'static_analysis', :name => 'Static analysis', :column_index => 1, :row_index => 1, :configured => true)
+ dashboard.widgets.build(:widget_key => 'comments_duplications', :name => 'Comments duplications', :column_index => 1, :row_index => 2, :configured => true)
+ dashboard.widgets.build(:widget_key => 'extended_analysis', :name => 'Extended analysis', :column_index => 1, :row_index => 3, :configured => true)
+ dashboard.widgets.build(:widget_key => 'code_coverage', :name => 'Code coverage', :column_index => 1, :row_index => 4, :configured => true)
+ dashboard.widgets.build(:widget_key => 'events', :name => 'Events', :column_index => 1, :row_index => 5, :configured => true)
+ dashboard.widgets.build(:widget_key => 'description', :name => 'Description', :column_index => 1, :row_index => 6, :configured => true)
+ dashboard.widgets.build(:widget_key => 'rules', :name => 'Rules', :column_index => 2, :row_index => 1, :configured => true)
+ dashboard.widgets.build(:widget_key => 'alerts', :name => 'Alerts', :column_index => 2, :row_index => 2, :configured => true)
+ dashboard.widgets.build(:widget_key => 'custom_measures', :name => 'Custom measures', :column_index => 2, :row_index => 3, :configured => true)
+ dashboard.widgets.build(:widget_key => 'file-design', :name => 'File design', :column_index => 2, :row_index => 4, :configured => true)
+ dashboard.widgets.build(:widget_key => 'package-design', :name => 'Package design', :column_index => 2, :row_index => 5, :configured => true)
+ dashboard.widgets.build(:widget_key => 'ckjm', :name => 'CKJM', :column_index => 2, :row_index => 6, :configured => true)
dashboard.save
dashboard