]> source.dussan.org Git - sonarqube.git/commitdiff
custom dashboards: add the annotation @WidgetLayout with values DEFAULT (gray border...
authorsimonbrandhof <simon.brandhof@gmail.com>
Fri, 5 Nov 2010 12:48:07 +0000 (12:48 +0000)
committersimonbrandhof <simon.brandhof@gmail.com>
Fri, 5 Nov 2010 12:48:07 +0000 (12:48 +0000)
23 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/AlertsWidget.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/DescriptionWidget.java
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/_extended_analysis.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/_static_analysis.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/code_coverage.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/comments_duplications.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/custom_measures.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/description.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/events.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/rules.html.erb
plugins/sonar-design-plugin/src/main/resources/org/sonar/plugins/design/ui/widgets/chidamber_kemerer.html.erb
plugins/sonar-design-plugin/src/main/resources/org/sonar/plugins/design/ui/widgets/file_design.html.erb
plugins/sonar-design-plugin/src/main/resources/org/sonar/plugins/design/ui/widgets/package_design.html.erb
sonar-plugin-api/src/main/java/org/sonar/api/web/AbstractDashboardWidget.java
sonar-plugin-api/src/main/java/org/sonar/api/web/WidgetLayout.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/web/WidgetLayoutType.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/ui/ViewProxy.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboard_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/views/dashboard/_configure_widget.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/dashboard/_widget.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/dashboards/_widget.html.erb
sonar-server/src/main/webapp/stylesheets/dashboard.css
sonar-server/src/test/java/org/sonar/server/ui/ViewProxyTest.java

index 604b491b4365369db2932e0e41ad0fb5846ede72..426f35f93f8c0f4d611e3ea32bddad38b7fd0f9a 100644 (file)
  */\r
 package org.sonar.plugins.core.widgets;\r
 \r
-import org.sonar.api.web.AbstractRubyTemplate;\r
-import org.sonar.api.web.Description;\r
-import org.sonar.api.web.RubyRailsWidget;\r
+import org.sonar.api.web.*;\r
 \r
+@WidgetLayout(WidgetLayoutType.NONE)\r
 @Description("Display current alerts on the project.")\r
 public class AlertsWidget extends AbstractRubyTemplate implements RubyRailsWidget {\r
   public String getId() {\r
index 52f47b03b62b6a98bed6fb226d441a6e17f9b677..f3304e4607341f8e7ce2071943e19c62b1226e32 100644 (file)
  */\r
 package org.sonar.plugins.core.widgets;\r
 \r
-import org.sonar.api.web.AbstractRubyTemplate;\r
-import org.sonar.api.web.Description;\r
-import org.sonar.api.web.RubyRailsWidget;\r
+import org.sonar.api.web.*;\r
 \r
+@WidgetLayout(WidgetLayoutType.NONE)\r
 @Description("Displays general project information taken from the pom.xml")\r
 public class DescriptionWidget extends AbstractRubyTemplate implements RubyRailsWidget {\r
   public String getId() {\r
index b2c4f1cedc1f19544c7ea348abba004f23147dec..86c1eec3b0f098f1e5c161c9e834dc6f9502beb5 100644 (file)
@@ -8,7 +8,6 @@
  if file_complexity || function_complexity || class_complexity || paragraph_complexity
 complexity=measure('complexity')
 %>
-<div class="widget">
 <div class="dashbox" >
  <h3>Complexity</h3>
  <% if function_complexity %>
@@ -106,6 +105,5 @@ if file_distribution
 <% end %>
 
 <div class="clear"></div>
-</div>
 <% end %>
 
index d654238d02cd36928278a0c3f3ea63c968c3c9e7..f8baf7ad4d3c001a027c8293d311122284a08425 100644 (file)
@@ -3,7 +3,6 @@ if measure('lines') || measure('ncloc')
   files=measure('files')
   statements=measure('statements')
 %>
-<div class="widget">
 <table width="100%">
        <tr>
                <td valign="top" width="48%" nowrap>
@@ -61,5 +60,4 @@ if measure('lines') || measure('ncloc')
                </td>
        </tr>
 </table>
-</div>
 <% end %>
\ No newline at end of file
index 82dcc03258e9e088d8ea35824fec29077bf89a04..422c131f96bc562310696e7fb1c7292ad6365fd7 100644 (file)
@@ -2,7 +2,6 @@
 code_coverage_measure=measure(Metric::COVERAGE)
 tests_measure=measure(Metric::TESTS)
 if code_coverage_measure || tests_measure %>
-<div class="widget">
 <div class="yui-g">
   <div class="yui-u first">
 <div class="dashbox">
@@ -43,5 +42,4 @@ if code_coverage_measure || tests_measure %>
   <% end %>
 </div>
 </div>
-</div>
 <% end %>
index aabb5c642e682699642d01ebc1f547464273cab6..28f28552123bf3e70ea627de0776b3bbc0391e1e 100644 (file)
@@ -1,5 +1,4 @@
 <% if measure(Metric::LINES) || measure(Metric::NCLOC) %>
-<div class="widget">
 <table width="100%">
        <tr>
                <td valign="top" width="48%" nowrap>
@@ -35,5 +34,4 @@
                </td>
        </tr>
 </table>
-</div>
 <% end %>
\ No newline at end of file
index 4fc22a71d71f7f305c1909f8780da61b05be241d..d53de7b202d223e38215c8ff272570fd46630ad6 100644 (file)
@@ -6,7 +6,6 @@
  }
  %>
  <% if is_admin?(@snapshot) || measures.size>0 %>
- <div class="widget">
    <script type="text/javascript">
      function selectReviewMetric(){
        $$('.review_description_update').each(function(element) {
@@ -66,5 +65,4 @@
         </div>
  <% end %>
    <div class="clear"></div>
- </div>
  <% end %>
index aee61ede1070b3b00c585d7ce61e10e17a016313..2a876313e9b2bac1271f8224970a07ed7363efdc 100644 (file)
@@ -3,8 +3,6 @@
   <%= h @project.description %><br/>
   <% end %>
 
-  <%= @project.name %>
-
   Key : <%= @project.key %><br/>
 <% if @project.language %>
   Language : <%= @project.language %><br/>
index 41a9415f66732b62c3bc6133202d0cc14460dd7f..1a2755b5af5ebeb1e2c04ad8b54b608b109594a4 100644 (file)
@@ -1,5 +1,5 @@
 <% if @project.project? %>
-<div class="widget" id="widget_events"><div id="events_portlet"></div></div>
+<div id="widget_events"><div id="events_portlet"></div></div>
 <script>
 <%= remote_function(:update => "events_portlet", :url => { :controller => :project, :action => :events, :id => @snapshot.id }, :method => 'get') %>
 </script>
index a1cc13ed827c5d590bc47bf813bd042bd8c60892..dbcad0d1d5c371e2054e12e35ffa6f47001005de 100644 (file)
@@ -1,5 +1,5 @@
 <% if measure(Metric::LINES) %>
-<div class="widget" id="widget_rules">
+<div id="widget_rules">
        <table width="100%">
                <tr>
                  <td valign="top">
index 936a6f7efec3f98914fc20df9f34eeb7f13cd02b..2f772d05ce79cf48b87112cc2375a7b294e55717 100644 (file)
@@ -6,7 +6,6 @@ if lcom || rfc
   rfc_distribution=measure('rfc_distribution')
   suspect_lcom4_density=measure('suspect_lcom4_density')
   %>
-<div class="widget">
 <table width="100%">
   <tbody>
     <tr>
@@ -48,5 +47,4 @@ if lcom || rfc
     </tr>
   </tbody>
 </table>
-</div>
 <% end %>
index 6f53a2478d50605be0b6b812b05ac0de7fe08bb4..70041753975c44cefbcfc412af6a3f694b66b5b5 100644 (file)
@@ -4,7 +4,6 @@
     file_cycles=measure('file_cycles')
     file_feedback_edges=measure('file_feedback_edges')
 %>
-<div class="widget">
 <table width="100%">
   <tbody>
     <tr>
@@ -28,7 +27,6 @@
     </tr>
   </tbody>
 </table>
-</div>
 <%
   end
 %>
\ No newline at end of file
index c4903328ace8a3279f674be2617ba65fc760a7ba..59136259ee14b3273f6ce9f0d9d00351519a54fd 100644 (file)
@@ -2,7 +2,6 @@
   package_tangle_index=measure('package_tangle_index')
   if package_tangle_index
 %>
-<div class="widget">
 <table width="100%">
   <tbody>
     <tr>
@@ -34,7 +33,6 @@
     </tr>
   </tbody>
 </table>
-</div>
 <%
   end
 %>
\ No newline at end of file
index be9d0415405b18944c379fb2110fc4d935b79337..dcc5ca2179f439dff1fd3fd73c08df0f01fe0763 100644 (file)
@@ -27,10 +27,10 @@ package org.sonar.api.web;
 public abstract class AbstractDashboardWidget extends AbstractRubyTemplate implements RubyRailsWidget {
 
   public String getId() {
-    return getClass().toString();
+    return getClass().getSimpleName();
   }
 
   public String getTitle() {
-    return getClass().toString();
+    return getClass().getSimpleName();
   }
 }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/web/WidgetLayout.java b/sonar-plugin-api/src/main/java/org/sonar/api/web/WidgetLayout.java
new file mode 100644 (file)
index 0000000..81a0b87
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.api.web;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @since 2.4
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface WidgetLayout {
+  WidgetLayoutType value();
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/web/WidgetLayoutType.java b/sonar-plugin-api/src/main/java/org/sonar/api/web/WidgetLayoutType.java
new file mode 100644 (file)
index 0000000..dc542cb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.api.web;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @since 2.4
+ */
+public enum WidgetLayoutType {
+  DEFAULT, NONE
+}
\ No newline at end of file
index 7cb7159bcf0b59f6afa5492579d2feb9f6edf447..59fae3ac6a505dc39bc7b050f18a989243ad80bb 100644 (file)
@@ -37,8 +37,9 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
   private String[] resourceLanguages = {};
   private String[] defaultForMetrics = {};
   private String description = "";
-  private WidgetProperty[] properties = {};
-  private String[] categories = {};
+  private WidgetProperty[] widgetProperties = {};
+  private String[] widgetCategories = {};
+  private WidgetLayoutType widgetLayout = WidgetLayoutType.DEFAULT;
   private boolean isDefaultTab = false;
   private boolean isWidget = false;
 
@@ -87,14 +88,19 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
       description = descriptionAnnotation.value();
     }
 
-    WidgetProperties widgetProperties = AnnotationUtils.getClassAnnotation(view, WidgetProperties.class);
-    if (widgetProperties != null) {
-      properties = widgetProperties.value();
+    WidgetProperties propAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetProperties.class);
+    if (propAnnotation != null) {
+      this.widgetProperties = propAnnotation.value();
     }
 
-    WidgetCategory widgetCategory = AnnotationUtils.getClassAnnotation(view, WidgetCategory.class);
-    if (widgetCategory != null) {
-      categories = widgetCategory.value();
+    WidgetCategory categAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetCategory.class);
+    if (categAnnotation != null) {
+      widgetCategories = categAnnotation.value();
+    }
+
+    WidgetLayout layoutAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetLayout.class);
+    if (layoutAnnotation != null) {
+      widgetLayout = layoutAnnotation.value();
     }
 
     isWidget = (view instanceof Widget);
@@ -116,12 +122,12 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
     return description;
   }
 
-  public WidgetProperty[] getProperties() {
-    return properties;
+  public WidgetProperty[] getWidgetProperties() {
+    return widgetProperties;
   }
 
-  public String[] getCategories() {
-    return categories;
+  public String[] getWidgetCategories() {
+    return widgetCategories;
   }
 
   public String[] getSections() {
@@ -160,13 +166,17 @@ public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
     return view instanceof GwtPage;
   }
 
+  public WidgetLayoutType getWidgetLayout() {
+    return widgetLayout;
+  }
+
   public boolean isEditable() {
-    return !ArrayUtils.isEmpty(properties);
+    return !ArrayUtils.isEmpty(widgetProperties);
   }
 
   public boolean hasRequiredProperties() {
     boolean requires = false;
-    for (WidgetProperty property : properties) {
+    for (WidgetProperty property : widgetProperties) {
       if (!property.optional() && StringUtils.isEmpty(property.defaultValue())) {
         requires = true;
       }
index 50d872a104c57c655b19fed3e27dcafae7551c95..289bb1b7138cc47a2296f693cd2e1a0b8ca80e8e 100644 (file)
@@ -111,7 +111,7 @@ class DashboardController < ApplicationController
     #TODO check owner of dashboard
     definition=java_facade.getWidget(widget.widget_key)
     errors_by_property_key={}
-    definition.getProperties().each do |property_def|
+    definition.getWidgetProperties().each do |property_def|
       value=params[property_def.key()] || property_def.defaultValue()
       value='false' if value.empty? && property_def.type.name()==WidgetProperty::TYPE_BOOLEAN
 
@@ -201,10 +201,10 @@ class DashboardController < ApplicationController
   def load_widget_definitions(filter_on_category=nil)
     @widget_definitions=java_facade.getWidgets()
     @widget_categories=[]
-    @widget_definitions.each {|definition| @widget_categories<<definition.getCategories()}
+    @widget_definitions.each {|definition| @widget_categories<<definition.getWidgetCategories()}
     @widget_categories=@widget_categories.flatten.uniq.sort
     unless filter_on_category.blank?
-      @widget_definitions=@widget_definitions.select{|definition| definition.getCategories().to_a.include?(filter_on_category)}
+      @widget_definitions=@widget_definitions.select{|definition| definition.getWidgetCategories().to_a.include?(filter_on_category)}
     end
   end
 
index d592eceb471325696ebecf7d59d2cec364a2cdca..86472f3de6b67c0a78be2ebea197cdf8e28f0d70 100644 (file)
@@ -21,7 +21,7 @@
   <% form_remote_tag :url => {:action => 'save_widget', :wid => widget.id, :id => params[:id]}, :method => :post do -%>
     <table class="form">
       <tbody>
-      <% definition.getProperties().each do |property_def|
+      <% definition.getWidgetProperties().each do |property_def|
           value=widget.property_value(property_def.key(), property_def.defaultValue())
       %>
           <tr>
   <![endif]-->
 <div class="transparent"></div>
   <% if widget_body.include? '<' %>
-  <%= widget_body %>
+    <%
+      default_layout=(definition.getWidgetLayout().name()=='DEFAULT')
+      if default_layout
+    %>
+      <div class="widget">
+    <% end %>
+    <%= widget_body -%>
+    <% if default_layout %><div class="clear"> </div></div><% end %>
   <% else %>
   <div class="widget"><p>No data</p></div>
   <% end %>
index e6ff5c559431eca3c2bdaf5d4d2d1254aca470ea..c97d62e69ae4c0761de815526935cc5578f0376c 100644 (file)
 
     if widget_body.include?('<')
   %>
-    <%= widget_body %>
+    <%
+      default_layout=(definition.getWidgetLayout().name()=='DEFAULT')
+      if default_layout
+    %>
+      <div class="widget">
+    <% end %>
+    <%= widget_body -%>
+    <% if default_layout %><div class="clear"> </div></div><% end %>
   <%
     end
   %>
index d7c834d0f5015d83fff644908cc7c7f706b73c17..17d5e6f135e6441ed286983f7947502410fe5383 100644 (file)
@@ -1,5 +1,5 @@
 <%\r
-   properties_available=widget_view.getProperties() && widget_view.getProperties().size() != 0\r
+   properties_available=widget_view.getWidgetProperties() && widget_view.getWidgetProperties().size() != 0\r
 \r
    if !properties_available || (widget && widget.state==Widget::STATE_ACTIVE)\r
        begin\r
@@ -51,7 +51,7 @@
                            :before => "$(this).down('.widgetid').value=$(this).up('.block').identify().split('_').pop();hide_block_info($(this).up('.block'))" do -%>\r
             <table class="form" align="center" style="border-collapse:separate;border-spacing:5px;">\r
               <tbody>\r
-              <% widget_view.getProperties().each do |property|\r
+              <% widget_view.getWidgetProperties().each do |property|\r
                   db_property_value=widget.widget_property_value(property.key()) if widget\r
                   entered_value=params[property.key()]\r
                   entered_value=property.defaultValue() if !entered_value || entered_value.empty?\r
index 321454fa79a24846c4f133976ccf3f9f085b7d67..a275105d8c653b46d94e697ad0bf1352c1998d77 100644 (file)
@@ -49,7 +49,7 @@
 
 /*CONFIGURATION*/
 #dashboard #widget_defs {
-  height: 130px;
+  height: 150px;
   overflow-y: auto;
   background-color: #FFF6BF;
   border: 2px solid #FFD324;
@@ -70,6 +70,7 @@
   margin: 3px;
   white-space: normal;
   vertical-align: top;
+  height: 80px;
 }
 #dashboard ul.widget_categs li {
   padding-right: 5px;
index c93558678e09b0c8ff8a8154c1fde579fd60e277..edc78acaafaa78e83de4b99766fea2b6ededeb52 100644 (file)
@@ -119,7 +119,7 @@ public class ViewProxyTest {
   public void widgetShouldBeEditable() {
     ViewProxy proxy = new ViewProxy<Widget>(new EditableWidget());
     assertThat(proxy.isEditable(), is(true));
-    assertThat(proxy.getProperties().length, is(2));
+    assertThat(proxy.getWidgetProperties().length, is(2));
   }
 
   @Test