]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2662 Add action plan widget
authorFabrice Bellingard <bellingard@gmail.com>
Tue, 20 Dec 2011 10:48:15 +0000 (11:48 +0100)
committerFabrice Bellingard <bellingard@gmail.com>
Tue, 20 Dec 2011 16:13:03 +0000 (17:13 +0100)
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/actionPlans/ActionPlansWidget.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/reviews/PlannedReviewsWidget.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/reviews/UnplannedReviewsWidget.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/actionPlans/action_plans.html.erb [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/reviews/planned_reviews.html.erb [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/reviews/unplanned_reviews.html.erb [new file with mode: 0644]
plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties
sonar-server/src/main/webapp/WEB-INF/app/views/action_plans/index.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
sonar-server/src/main/webapp/stylesheets/style.css

index 58b343aeb4680ccfb5aa269eb8b8df6bc729a548..22e2ccd4b8f45bf98d0c5bed235a0470512ca01f 100644 (file)
@@ -42,10 +42,13 @@ import org.sonar.plugins.core.testdetailsviewer.TestsViewerDefinition;
 import org.sonar.plugins.core.timemachine.*;
 import org.sonar.plugins.core.web.Lcom4Viewer;
 import org.sonar.plugins.core.widgets.*;
+import org.sonar.plugins.core.widgets.actionPlans.ActionPlansWidget;
 import org.sonar.plugins.core.widgets.reviews.FalsePositiveReviewsWidget;
 import org.sonar.plugins.core.widgets.reviews.MyReviewsWidget;
+import org.sonar.plugins.core.widgets.reviews.PlannedReviewsWidget;
 import org.sonar.plugins.core.widgets.reviews.ProjectReviewsWidget;
 import org.sonar.plugins.core.widgets.reviews.ReviewsPerDeveloperWidget;
+import org.sonar.plugins.core.widgets.reviews.UnplannedReviewsWidget;
 
 import java.util.List;
 
@@ -248,6 +251,9 @@ public class CorePlugin extends SonarPlugin {
     extensions.add(ProjectReviewsWidget.class);
     extensions.add(FalsePositiveReviewsWidget.class);
     extensions.add(ReviewsPerDeveloperWidget.class);
+    extensions.add(PlannedReviewsWidget.class);
+    extensions.add(UnplannedReviewsWidget.class);
+    extensions.add(ActionPlansWidget.class);
 
     // dashboards
     extensions.add(DefaultDashboard.class);
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/actionPlans/ActionPlansWidget.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/actionPlans/ActionPlansWidget.java
new file mode 100644 (file)
index 0000000..4950c87
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.plugins.core.widgets.actionPlans;
+
+import org.sonar.api.web.AbstractRubyTemplate;
+import org.sonar.api.web.RubyRailsWidget;
+import org.sonar.api.web.WidgetCategory;
+
+@WidgetCategory({ "Action plans", "Reviews" })
+public class ActionPlansWidget extends AbstractRubyTemplate implements RubyRailsWidget {
+  public String getId() {
+    return "action_plans";
+  }
+
+  public String getTitle() {
+    return "Action plans";
+  }
+
+  @Override
+  protected String getTemplatePath() {
+    return "/org/sonar/plugins/core/widgets/actionPlans/action_plans.html.erb";
+  }
+}
\ No newline at end of file
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/reviews/PlannedReviewsWidget.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/reviews/PlannedReviewsWidget.java
new file mode 100644 (file)
index 0000000..9299e69
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.plugins.core.widgets.reviews;
+
+import org.sonar.api.web.AbstractRubyTemplate;
+import org.sonar.api.web.RubyRailsWidget;
+import org.sonar.api.web.WidgetCategory;
+import org.sonar.api.web.WidgetProperties;
+import org.sonar.api.web.WidgetProperty;
+import org.sonar.api.web.WidgetPropertyType;
+
+@WidgetCategory({ "Action plans", "Reviews" })
+@WidgetProperties(
+    {
+        @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5", 
+                        description="Maximum number of reviews displayed at the same time.")
+    }
+)
+public class PlannedReviewsWidget extends AbstractRubyTemplate implements RubyRailsWidget {
+  public String getId() {
+    return "planned_reviews";
+  }
+
+  public String getTitle() {
+    return "Planned reviews";
+  }
+
+  @Override
+  protected String getTemplatePath() {
+    return "/org/sonar/plugins/core/widgets/reviews/planned_reviews.html.erb";
+  }
+}
\ No newline at end of file
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/reviews/UnplannedReviewsWidget.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/reviews/UnplannedReviewsWidget.java
new file mode 100644 (file)
index 0000000..dbe1fc9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.plugins.core.widgets.reviews;
+
+import org.sonar.api.web.AbstractRubyTemplate;
+import org.sonar.api.web.RubyRailsWidget;
+import org.sonar.api.web.WidgetCategory;
+import org.sonar.api.web.WidgetProperties;
+import org.sonar.api.web.WidgetProperty;
+import org.sonar.api.web.WidgetPropertyType;
+
+@WidgetCategory({ "Action plans", "Reviews" })
+@WidgetProperties(
+    {
+        @WidgetProperty(key = "numberOfLines", type = WidgetPropertyType.INTEGER, defaultValue = "5", 
+                        description="Maximum number of reviews displayed at the same time.")
+    }
+)
+public class UnplannedReviewsWidget extends AbstractRubyTemplate implements RubyRailsWidget {
+  public String getId() {
+    return "unplanned_reviews";
+  }
+
+  public String getTitle() {
+    return "Unplanned reviews";
+  }
+
+  @Override
+  protected String getTemplatePath() {
+    return "/org/sonar/plugins/core/widgets/reviews/unplanned_reviews.html.erb";
+  }
+}
\ No newline at end of file
diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/actionPlans/action_plans.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/actionPlans/action_plans.html.erb
new file mode 100644 (file)
index 0000000..e378873
--- /dev/null
@@ -0,0 +1,53 @@
+<%
+   if has_role?(:user, @project)
+     action_plans = ActionPlan.find(:all, :conditions => ['status= ? AND project_id=?', ActionPlan::STATUS_OPEN, @project.id], 
+                                          :include => 'reviews', :order => 'dead_line ASC')
+     
+     div_id = "action-plan-widget-#{widget.id.to_s}"
+%>
+
+<div class="line-block">
+  <div style="float:right">
+    <a href="<%= url_for :controller => 'action_plans', :action => 'index', :id => @project.id -%>">
+      <%= message('widgets.more') -%>
+    </a>
+  </div>
+  <h3><%= message('widget.action_plans.title') -%></h3>
+</div>
+
+<% if action_plans.size ==0 %>
+  <span class="empty_widget"><%= message('widget.action_plans.no_action_plan') -%></span>
+<% else %>
+
+<div id="<%= div_id -%>">
+  <table class="width100 data actionPlans">
+    <thead>
+    <tr>
+      <th colspan="3"></th>
+    </tr>
+    </thead>
+    <tbody>
+      <%
+         action_plans.each do |plan|
+      %>
+      <tr class="<%= cycle 'even', 'odd', :name => (div_id) -%>">
+        <td class="thin nowrap"><%= h(plan.name) -%></td>
+        <td class="thin nowrap <%= 'over-due' if plan.over_due? -%>" align="right" x="<%= plan.dead_line ? plan.dead_line.tv_sec : '' -%>"><%= plan.dead_line ? plan.dead_line.strftime("%d %b %Y") : ' '  -%></td>
+        <% if plan.progress[:total]==0 %>
+        <td class="noprogress thin nowrap"><%= message('action_plans.no_reviews_linked_to_action_plan') -%></td>
+        <% else %>
+        <td class="progress thin">
+            <%= render :partial => 'action_plans/progress', :locals => {:action_plan => plan} -%>
+        </td>
+        <% end %>
+      </tr>
+      <% 
+         end 
+      %>
+    </tbody>
+  </table>
+</div>
+
+<% end %>
+
+<% end %>
diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/reviews/planned_reviews.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/reviews/planned_reviews.html.erb
new file mode 100644 (file)
index 0000000..a81fe82
--- /dev/null
@@ -0,0 +1 @@
+<b> Under construction ;-) </b>
diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/reviews/unplanned_reviews.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/reviews/unplanned_reviews.html.erb
new file mode 100644 (file)
index 0000000..1fcfa83
--- /dev/null
@@ -0,0 +1 @@
+<b> Under construction ;-) </b>
\ No newline at end of file
index a4c273918e92d8c1b08652c3dc9a867a58d26d33..ac7dbbf677509b08de0db5c5a871c3d6f16ae932 100644 (file)
@@ -654,6 +654,18 @@ widget.reviews_per_developer.name=Open reviews per developer
 widget.reviews_per_developer.description=Shows the number of open/reopened reviews per developer.
 widget.reviews_per_developer.not_assigned=Not assigned
 
+widget.action_plans.name=Action plans
+widget.action_plans.description=Shows all the open action plans of the project
+widget.action_plans.title=Open action plans
+widget.action_plans.no_action_plan=No action plan
+
+widget.planned_reviews.name=Planned reviews
+widget.planned_reviews.description=Shows all the planned reviews of the project, gathered by action plan
+
+widget.unplanned_reviews.name=Unplanned reviews
+widget.unplanned_reviews.description=Shows all the reviews of the project that are not planned yet in an action plan
+
+
 
 #------------------------------------------------------------------------------
 #
index 60fda96d531dee9bb57940243cba9c7eb1313240..38ecf0abd7ee05b3773379f97ac48fcbca977c95 100644 (file)
@@ -8,7 +8,7 @@
   <h1><%= message('action_plans.page_title') -%></h1>
 </div>
 
-<table class="width100 data sortable" id="actionPlans">
+<table class="width100 data sortable actionPlans" id="actionPlans">
   <thead>
   <tr>
     <th class="thin nowrap"><%= message('action_plans.col.status') -%></th>
index d88104aad2fed0d45c1ac859a54c2a2e0b1db43f..fec76547b340f1918eebce5633d7b74df25b4bb9 100644 (file)
               <li class="h2"><%= message('sidebar.project_settings') -%></li>
               <li class="<%= 'selected' if request.request_uri.include?('/manual_measures') -%>">
                 <a href="<%= ApplicationController.root_context -%>/manual_measures/index/<%= @project.id -%>"><%= message('manual_measures.page') -%></a></li>
+              <% if (@project.project?) %>
               <li class="<%= 'selected' if request.request_uri.include?('/action_plans') -%>">
                 <a href="<%= ApplicationController.root_context -%>/action_plans/index/<%= @project.id -%>"><%= message('action_plans.page') -%></a></li>
+              <% end %>
               <% if (@project.project? || @project.module?) %>
                 <li class="<%= 'selected' if request.request_uri.include?('/project/settings') -%>">
                   <a href="<%= ApplicationController.root_context -%>/project/settings/<%= @project.id -%>"><%= message('project_settings.page') -%></a></li>
index bd9622f7ab3c2fb172cd96761823e7d4fa19ea0a..06e96e8e81c56d6622540c605f0a1089a78d90dc 100644 (file)
@@ -1228,23 +1228,23 @@ div.comment-excerpt {
 }
 
 /* ACTION PLANS */
-#actionPlans td {
+table.actionPlans td {
   vertical-align: top;
 }
 
-#actionPlans td.progress {
+table.actionPlans td.progress {
   width: 300px;
   padding: 0px 40px;
 }
 
-#actionPlans td.noprogress {
+table.actionPlans td.noprogress {
   color: #777777; 
   font-size: 93%;
   padding-left: 40px;
   padding-right: 40px;
 }
 
-#actionPlans td.over-due {
+table.actionPlans td.over-due {
   color: #CC0000;
   font-weight: bold;
 }