*/
package org.sonar.plugins.core.widgets;
+import org.sonar.api.web.WidgetGlobal;
+
import org.sonar.api.web.AbstractRubyTemplate;
import org.sonar.api.web.RubyRailsWidget;
import org.sonar.api.web.UserRole;
import org.sonar.api.web.WidgetCategory;
-@WidgetCategory(value = "Information", detached = true)
+@WidgetCategory("Information")
+@WidgetGlobal
@UserRole(UserRole.USER)
public class GlobalWidget extends AbstractRubyTemplate implements RubyRailsWidget {
files=Files
filter_verb=Filter
follow=Follow
+global=Global
hide=Hide
identifier_abbreviated=Id
info=Info
private String description;
private String columnLayout;
private boolean shared;
- private boolean detached;
+ private boolean global;
private Date createdAt;
private Date updatedAt;
private List<WidgetDto> widgetDtos = Lists.newArrayList();
return this;
}
- public boolean getDetached() {
- return detached;
+ public boolean getGlobal() {
+ return global;
}
- public DashboardDto setDetached(boolean detached) {
- this.detached = detached;
+ public DashboardDto setGlobal(boolean global) {
+ this.global = global;
return this;
}
<mapper namespace="org.sonar.core.dashboard.DashboardMapper">
<select id="selectGlobalDashboard" parameterType="string" resultType="Dashboard">
- select id, user_id as "userId", name, description, column_layout as "columnLayout", shared, detached, created_at as "createdAt", updated_at as "updatedAt"
+ select id, user_id as "userId", name, description, column_layout as "columnLayout", shared, is_global, created_at as "createdAt", updated_at as "updatedAt"
from dashboards WHERE name=#{id} and user_id is null
</select>
<selectKey order="BEFORE" resultType="Long" keyProperty="id">
select dashboards_seq.NEXTVAL from DUAL
</selectKey>
- INSERT INTO dashboards (id, user_id, name, description, column_layout, shared, detached, created_at, updated_at)
+ INSERT INTO dashboards (id, user_id, name, description, column_layout, shared, is_global, created_at, updated_at)
VALUES (#{id}, #{userId, jdbcType=FLOAT}, #{name, jdbcType=VARCHAR}, #{description, jdbcType=VARCHAR},
- #{columnLayout, jdbcType=INTEGER}, #{shared}, #{detached}, #{createdAt, jdbcType=TIMESTAMP}, #{updatedAt, jdbcType=TIMESTAMP})
+ #{columnLayout, jdbcType=INTEGER}, #{shared}, #{global}, #{createdAt, jdbcType=TIMESTAMP}, #{updatedAt, jdbcType=TIMESTAMP})
</insert>
</mapper>
<mapper namespace="org.sonar.core.dashboard.DashboardMapper">
<select id="selectGlobalDashboard" parameterType="string" resultType="Dashboard">
- select id, user_id as "userId", name, description, column_layout as "columnLayout", shared, detached, created_at as "createdAt", updated_at as "updatedAt"
+ select id, user_id as "userId", name, description, column_layout as "columnLayout", shared, is_global, created_at as "createdAt", updated_at as "updatedAt"
from dashboards WHERE name=#{id} and user_id is null
</select>
<insert id="insert" parameterType="Dashboard" useGeneratedKeys="true" keyProperty="id">
- INSERT INTO dashboards (user_id, name, description, column_layout, shared, detached, created_at, updated_at)
+ INSERT INTO dashboards (user_id, name, description, column_layout, shared, is_global, created_at, updated_at)
VALUES (#{userId, jdbcType=FLOAT}, #{name, jdbcType=VARCHAR}, #{description, jdbcType=VARCHAR},
- #{columnLayout, jdbcType=INTEGER}, #{shared}, #{detached}, #{createdAt, jdbcType=TIMESTAMP}, #{updatedAt, jdbcType=TIMESTAMP})
+ #{columnLayout, jdbcType=INTEGER}, #{shared}, #{global}, #{createdAt, jdbcType=TIMESTAMP}, #{updatedAt, jdbcType=TIMESTAMP})
</insert>
</mapper>
"DESCRIPTION" VARCHAR(1000),
"COLUMN_LAYOUT" VARCHAR(20),
"SHARED" BOOLEAN,
- "DETACHED" BOOLEAN,
+ "IS_GLOBAL" BOOLEAN,
"CREATED_AT" TIMESTAMP,
"UPDATED_AT" TIMESTAMP
);
dashboardDto.setDescription("This is a dashboard");
dashboardDto.setColumnLayout("100%");
dashboardDto.setShared(true);
+ dashboardDto.setGlobal(true);
dashboardDto.setCreatedAt(aDate);
dashboardDto.setUpdatedAt(aDate);
dashboardDto.setDescription(null);
dashboardDto.setColumnLayout(null);
dashboardDto.setShared(true);
+ dashboardDto.setGlobal(false);
dashboardDto.setCreatedAt(null);
dashboardDto.setUpdatedAt(null);
description="This is a dashboard"
column_layout="100%"
shared="[true]"
- detached="[false]"
+ is_global="[true]"
/>
<widgets
description="[null]"
column_layout="[null]"
shared="[true]"
- detached="[false]"
+ is_global="[false]"
created_at="[null]"
updated_at="[null]"
/>
description="User SQALE dashboard"
column_layout="100%"
shared="[true]"
- detached="[false]"
/>
<dashboards
description="Global SQALE dashboard"
column_layout="100%"
shared="[true]"
- detached="[false]"
/>
</dataset>
@Target(ElementType.TYPE)
public @interface WidgetCategory {
String[] value();
-
- /**
- * Is the widget detached from any project?
- * Before version 3.1 no widget was detached.
- *
- * @since 3.1
- */
- boolean detached() default false;
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 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.api.web;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A widget is global when it can only ne displayed on Global Dashboards.
+ * It doesn't display information from a projet but rather more general information.
+ * <p>Before version 3.1 no widget was global.</p>
+ *
+ * @since 3.1
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface WidgetGlobal {
+}
private WidgetLayoutType widgetLayout = WidgetLayoutType.DEFAULT;
private boolean isDefaultTab = false;
private boolean isWidget = false;
- private boolean isDetached = false;
+ private boolean isGlobal = false;
private String[] mandatoryMeasures = {};
private String[] needOneOfMeasures = {};
initWidgetProperties(view);
initWidgetCategory(view);
initWidgetLayout(view);
- initWidgetDetached(view);
+ initWidgetGlobal(view);
initRequiredMeasures(view);
isWidget = (view instanceof Widget);
}
}
- private void initWidgetDetached(final V view) {
- WidgetCategory categAnnotation = AnnotationUtils.getClassAnnotation(view, WidgetCategory.class);
- if (categAnnotation != null) {
- isDetached = categAnnotation.detached();
- }
+ private void initWidgetGlobal(final V view) {
+ isGlobal = null != AnnotationUtils.getClassAnnotation(view, WidgetGlobal.class);
}
private void initWidgetProperties(final V view) {
return isWidget;
}
- public boolean isDetached() {
- return isDetached;
+ public boolean isGlobal() {
+ return isGlobal;
}
public boolean isGwt() {
end
def load_widget_definitions(dashboard, filter_on_category=nil)
- @widget_definitions=java_facade.getWidgets()
- if dashboard.detached
- @widget_definitions=@widget_definitions.select(&:isDetached)
- end
+ @widget_definitions=java_facade.getWidgets().select { |w| w.isGlobal() == dashboard.global}
@widget_categories=@widget_definitions.map(&:getWidgetCategories).flatten.uniq.sort
unless filter_on_category.blank?
def load_dashboard_from_params(dashboard)
dashboard.name=params[:name]
dashboard.description=params[:description]
+ dashboard.global=(params[:global].present?)
dashboard.shared=(params[:shared].present? && is_admin?)
dashboard.user_id=current_user.id
dashboard.column_layout=Dashboard::DEFAULT_LAYOUT if !dashboard.column_layout
end
-end
\ No newline at end of file
+end
before_destroy :check_not_default_before_destroy
def name(l10n=false)
- n=read_attribute(:name)
- if l10n
- Api::Utils.message("dashboard.#{n}.name", :default => n)
- else
- n
- end
+ n=read_attribute(:name)
+ if l10n
+ Api::Utils.message("dashboard.#{n}.name", :default => n)
+ else
+ n
+ end
end
def shared?
- read_attribute(:shared) || false
+ read_attribute(:shared) || false
+ end
+
+ def global?
+ read_attribute(:is_global) || false
end
def layout
- column_layout
+ column_layout
end
def user_name
- user_id ? user.name : nil
+ user_id ? user.name : nil
end
def editable_by?(user)
- (user && self.user_id==user.id) || (user_id.nil? && user.has_role?(:admin))
+ (user && self.user_id==user.id) || (user_id.nil? && user.has_role?(:admin))
end
def owner?(user)
- self.user_id==user.id
+ self.user_id==user.id
end
def number_of_columns
- column_layout.split('-').size
+ column_layout.split('-').size
end
def column_size(column_index)
- last_widget=widgets.select { |w| w.column_index==column_index }.max { |x, y| x.row_index <=> y.row_index }
- last_widget ? last_widget.row_index : 0
+ last_widget=widgets.select { |w| w.column_index==column_index }.max { |x, y| x.row_index <=> y.row_index }
+ last_widget ? last_widget.row_index : 0
end
def deep_copy()
- dashboard=Dashboard.new(attributes)
- dashboard.shared=false
- self.widgets.each do |child|
- new_widget = Widget.create(child.attributes)
-
- child.properties.each do |prop|
- widget_prop = WidgetProperty.create(prop.attributes)
- new_widget.properties << widget_prop
- end
-
- new_widget.save
- dashboard.widgets << new_widget
- end
- dashboard.save
- dashboard
+ dashboard=Dashboard.new(attributes)
+ dashboard.shared=false
+ self.widgets.each do |child|
+ new_widget = Widget.create(child.attributes)
+
+ child.properties.each do |prop|
+ widget_prop = WidgetProperty.create(prop.attributes)
+ new_widget.properties << widget_prop
+ end
+
+ new_widget.save
+ dashboard.widgets << new_widget
+ end
+ dashboard.save
+ dashboard
end
def provided_programmatically?
- shared && user_id.nil?
+ shared && user_id.nil?
end
protected
def check_not_default_before_destroy
- if shared?
- default_actives = active_dashboards.select { |ad| ad.default? }
- return default_actives.size==0
- end
- true
+ if shared?
+ default_actives = active_dashboards.select { |ad| ad.default? }
+ return default_actives.size==0
+ end
+ true
end
def validate_on_update
- # Check that not used as default dashboard when unsharing
- if shared_was && !shared
- # unsharing
- default_actives = active_dashboards.select { |ad| ad.default? }
-
- unless default_actives.empty?
- errors.add_to_base(Api::Utils.message('dashboard.error_unshare_default'))
- end
- end
+ # Check that not used as default dashboard when unsharing
+ if shared_was && !shared
+ # unsharing
+ default_actives = active_dashboards.select { |ad| ad.default? }
+
+ unless default_actives.empty?
+ errors.add_to_base(Api::Utils.message('dashboard.error_unshare_default'))
+ end
+ end
end
-end
\ No newline at end of file
+end
<%= message('description') -%>:<br/><input type="text" name="description" size="30" maxlength="1000">
</td>
</tr>
+ <tr>
+ <td class="left" valign="top">
+ <%= message('global') -%>:<br/><input type="checkbox" name="global" value="true">
+ </td>
+ </tr>
<% if is_admin? %>
<tr>
<td class="left" valign="top">
</table>
<script>
$('create-dashboard-form').name.focus();
-</script>
\ No newline at end of file
+</script>
<thead>
<tr>
<th><%= message('name') -%></th>
+ <th><%= message('global') -%></th>
<% if is_admin %>
<th><%= message('shared') -%></th>
<% end %>
<p class="small"><%= h active.dashboard.description -%></p>
<% end %>
</td>
+ <td>
+ <%= boolean_icon(active.dashboard.global?) -%>
+ </td>
<% if is_admin %>
<td>
- <%= boolean_icon(active.dashboard.shared, {:display_false => false}) -%>
+ <%= boolean_icon(active.dashboard.shared?) -%>
</td>
<% end %>
<td>
<li class="<%= 'selected' if controller.controller_path=='dependencies' -%>">
<a href="<%= ApplicationController.root_context -%>/dependencies/index"><%= message('dependencies.page') -%></a></li>
- <% ActiveDashboard.user_dashboards(current_user).select { |active_dashboard| active_dashboard.dashboard.detached }.each do |active_dashboard| %>
+ <% ActiveDashboard.user_dashboards(current_user).select { |active_dashboard| active_dashboard.dashboard.global? }.each do |active_dashboard| %>
<li class="<%= 'selected' if @dashboard && controller.controller_path=='dashboard' && active_dashboard.dashboard_id==@dashboard.id -%>">
<a href="<%= ApplicationController.root_context -%>/dashboard/index/?did=<%= active_dashboard.dashboard_id -%>"><%= active_dashboard.dashboard.name(true) -%></a>
</li>
<% end %>
<% elsif selected_section==Navigation::SECTION_RESOURCE %>
- <% ActiveDashboard.user_dashboards(current_user).select { |active_dashboard| !active_dashboard.dashboard.detached }.each do |active_dashboard| %>
+ <% ActiveDashboard.user_dashboards(current_user).select { |active_dashboard| !active_dashboard.dashboard.global? }.each do |active_dashboard| %>
<li class="<%= 'selected' if @dashboard && controller.controller_path=='dashboard' && active_dashboard.dashboard_id==@dashboard.id -%>">
<a href="<%= ApplicationController.root_context -%>/dashboard/index/<%= @project.id -%>?did=<%= active_dashboard.dashboard_id -%><%= "&"+period_param if period_param -%>"><%= active_dashboard.dashboard.name(true) -%></a>
</li>
class AddGlobalToDashboards < ActiveRecord::Migration
def self.up
- add_column 'dashboards', 'detached', :boolean, :null => false, :default => false
+ add_column 'dashboards', 'global', :boolean, :null => false, :default => false
end
end
*/
package org.sonar.server.ui;
+import org.sonar.api.web.WidgetGlobal;
+
import org.junit.Test;
import org.sonar.api.web.DefaultTab;
import org.sonar.api.web.NavigationSection;
import org.sonar.api.web.UserRole;
import org.sonar.api.web.View;
import org.sonar.api.web.Widget;
-import org.sonar.api.web.WidgetCategory;
import org.sonar.api.web.WidgetProperties;
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
}
@Test
- public void widget_should_not_be_detached() {
+ public void widget_should_not_be_global_by_default() {
ViewProxy proxy = new ViewProxy<Widget>(new EditableWidget());
- assertThat(proxy.isDetached()).isFalse();
+ assertThat(proxy.isGlobal()).isFalse();
}
@Test
- public void widget_should_be_detached() {
- ViewProxy proxy = new ViewProxy<Widget>(new DetachedWidget());
+ public void widget_should_be_global() {
+ ViewProxy proxy = new ViewProxy<Widget>(new GlobalWidget());
- assertThat(proxy.isDetached()).isTrue();
+ assertThat(proxy.isGlobal()).isTrue();
}
@Test
}
}
-@WidgetCategory(value = "", detached = true)
-class DetachedWidget implements Widget {
+@WidgetGlobal
+class GlobalWidget implements Widget {
public String getId() {
- return "detached";
+ return "global";
}
public String getTitle() {
- return "Detached";
+ return "Global";
}
}