diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-02-07 12:25:32 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-02-07 12:25:32 +0100 |
commit | eb6c3ebf24003a296f2a69ce5ba60fbd24e651b6 (patch) | |
tree | e65671b30a2e2cdd9ef4a9fa9681aacfa4e0bda7 | |
parent | 18c4b94aaf596645ecd53d9df1101986a7a1d599 (diff) | |
download | sonarqube-eb6c3ebf24003a296f2a69ce5ba60fbd24e651b6.tar.gz sonarqube-eb6c3ebf24003a296f2a69ce5ba60fbd24e651b6.zip |
Update issue ui in resource viewer update to be consistent with issues filter
12 files changed, 240 insertions, 229 deletions
diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index 4a467aa054d..cbe50409e85 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -582,6 +582,7 @@ issue.manual.no_rules.non_admin=At least one manual rule must exist before manua issue.reported_by=Reported by issue.authorLogin=Author: issue.component_deleted=Removed +issue.debt=Debt: issue.technical_debt=Technical Debt: issue.technical_debt_short=Debt issue.technical_debt.x_days={0} days diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManager.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManager.java index 86913704cf3..3bb7b5bae7d 100644 --- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManager.java +++ b/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManager.java @@ -22,6 +22,7 @@ package org.sonar.core.technicaldebt; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.technicaldebt.server.Characteristic; import org.sonar.api.technicaldebt.server.TechnicalDebtManager; import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic; @@ -31,6 +32,7 @@ import org.sonar.core.technicaldebt.db.CharacteristicDto; import javax.annotation.CheckForNull; import javax.annotation.Nullable; + import java.util.List; import static com.google.common.collect.Lists.newArrayList; @@ -41,9 +43,11 @@ import static com.google.common.collect.Lists.newArrayList; public class DefaultTechnicalDebtManager implements TechnicalDebtManager { private final CharacteristicDao dao; + private final RuleFinder ruleFinder; - public DefaultTechnicalDebtManager(CharacteristicDao dao) { + public DefaultTechnicalDebtManager(CharacteristicDao dao, RuleFinder ruleFinder) { this.dao = dao; + this.ruleFinder = ruleFinder; } public List<Characteristic> findRootCharacteristics() { @@ -65,6 +69,16 @@ public class DefaultTechnicalDebtManager implements TechnicalDebtManager { } @CheckForNull + public Characteristic findRequirementByRuleId(int ruleId) { + CharacteristicDto requirementDto = dao.selectByRuleId(ruleId); + if (requirementDto != null) { + Rule rule = ruleFinder.findById(ruleId); + return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey())); + } + return null; + } + + @CheckForNull public Characteristic findRequirementByRule(Rule rule) { CharacteristicDto requirementDto = dao.selectByRuleId(rule.getId()); if (requirementDto != null) { diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManagerTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManagerTest.java index a20cb142ee9..7ac3d435309 100644 --- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManagerTest.java +++ b/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManagerTest.java @@ -27,6 +27,7 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.technicaldebt.server.Characteristic; import org.sonar.api.utils.WorkUnit; import org.sonar.core.technicaldebt.db.CharacteristicDao; @@ -44,11 +45,14 @@ public class DefaultTechnicalDebtManagerTest { @Mock CharacteristicDao dao; + @Mock + RuleFinder ruleFinder; + DefaultTechnicalDebtManager finder; @Before public void setUp() throws Exception { - finder = new DefaultTechnicalDebtManager(dao); + finder = new DefaultTechnicalDebtManager(dao, ruleFinder); } @Test @@ -126,4 +130,37 @@ public class DefaultTechnicalDebtManagerTest { Characteristic result = finder.findCharacteristicById(2); assertThat(result).isNull(); } + + @Test + public void find_requirement_by_rule_id() throws Exception { + Rule rule = Rule.create("repo", "key"); + rule.setId(1); + + when(ruleFinder.findById(1)).thenReturn(rule); + + when(dao.selectByRuleId(rule.getId())).thenReturn( + new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear").setFactorValue(30.0).setFactorUnit("mn")); + + Characteristic result = finder.findRequirementByRuleId(1); + + assertThat(result.id()).isEqualTo(3); + assertThat(result.parentId()).isEqualTo(2); + assertThat(result.rootId()).isEqualTo(1); + assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key")); + assertThat(result.function()).isEqualTo("linear"); + assertThat(result.factor()).isEqualTo(WorkUnit.create(30.0, WorkUnit.MINUTES)); + assertThat(result.offset()).isEqualTo(WorkUnit.create()); + } + + @Test + public void not_find_requirement_by_rule_id_on_unknown_requirement() throws Exception { + Rule rule = Rule.create("repo", "key"); + rule.setId(1); + + when(ruleFinder.findById(1)).thenReturn(rule); + + when(dao.selectByRuleId(rule.getId())).thenReturn(null); + + assertThat(finder.findRequirementByRuleId(1)).isNull(); + } } diff --git a/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleShowWsHandler.java b/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleShowWsHandler.java index 6efedab37c1..ccb97dc0ce8 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleShowWsHandler.java +++ b/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleShowWsHandler.java @@ -74,6 +74,7 @@ public class RuleShowWsHandler implements RequestHandler { @CheckForNull private Rule findRule(RuleKey ruleKey) { + // TODO remove this when manual rules when be indexed in E/S if (ruleKey.repository().equals(Rule.MANUAL_REPOSITORY_KEY)) { org.sonar.api.rules.Rule rule = ruleFinder.findByKey(ruleKey); if (rule != null) { diff --git a/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java b/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java index 464214c03e3..fe89ec33b3b 100644 --- a/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java +++ b/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java @@ -22,12 +22,12 @@ package org.sonar.server.technicaldebt; import org.sonar.api.ServerComponent; import org.sonar.api.issue.internal.WorkDayDuration; -import org.sonar.api.rules.Rule; import org.sonar.api.technicaldebt.server.Characteristic; import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager; import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; + import java.util.List; public class DebtService implements ServerComponent { @@ -52,8 +52,8 @@ public class DebtService implements ServerComponent { return finder.findRootCharacteristics(); } - public Characteristic findRequirement(Rule rule) { - return finder.findRequirementByRule(rule); + public Characteristic findRequirementByRuleId(int ruleId) { + return finder.findRequirementByRuleId(ruleId); } @CheckForNull diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb index 58df6c0e39f..a9b04bcd49b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb @@ -187,6 +187,12 @@ class IssueController < ApplicationController require_parameters :id rule_key = params[:id].split(':') @rule = Rule.first(:conditions => ['plugin_name=? and plugin_rule_key=?', rule_key[0], rule_key[1]]) + @requirement = Internal.technical_debt.findRequirementByRuleId(@rule.id) + # Requirement can be null if it's disabled or if there's no requirement on this rule + if @requirement + @characteristic = Internal.technical_debt.findCharacteristic(@requirement.parentId) + @root_characteristic = Internal.technical_debt.findCharacteristic(@requirement.rootId) + end render :partial => 'issue/rule' end @@ -200,21 +206,6 @@ class IssueController < ApplicationController render :partial => 'issue/changelog' end - # Display the technical debt detail in the issue panel - def technicaldebt - verify_ajax_request - require_parameters :id - @issue_results = Api.issues.find(params[:id]) - @issue = @issue_results.first() - - rule = @issue_results.rule(@issue) - @requirement = Internal.technical_debt.findRequirement(rule) - # Requirement can be null if it's disabled - @characteristic = Internal.technical_debt.findCharacteristic(@requirement.parentId) if @requirement - @root_characteristic = Internal.technical_debt.findCharacteristic(@requirement.rootId) if @requirement - render :partial => 'issue/technicaldebt' - end - private diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb index 0d790ae6585..18aca66d630 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb @@ -1,166 +1,158 @@ -<div class="code-issue" data-issue-key="<%= issue.key -%>" data-issue-component="<%= issue.componentKey() -%>" data-issue-rule="<%= u issue.ruleKey().toString() -%>"> - <div class="code-issue-name"> - <div style="float: right"> +<div id="issue-<%= u issue.key -%>" class="code-issue code-issue-collapsed" data-issue-key="<%= issue.key -%>" data-issue-component="<%= issue.componentKey() -%>" data-issue-rule="<%= u issue.ruleKey().toString() -%>"> + <div class="code-issue-name code-issue-toggle"> + <div class="code-issue-name-rule"> + <i class="icon-severity-<%= issue.severity.downcase -%>"></i> + <span class="rulename"> + <%= h !issue.message.blank? ? Api::Utils.split_newlines(issue.message).join('<br/>') : @issue_results.rule(issue).getName() -%> + </span> + </div> + <div class="code-issue-permalink"> <a href="#" onclick="return openIssuePopup(this)" class="issue-permalink"><img src="<%= ApplicationController.root_context -%>/images/new-window-16.gif"></a> </div> + </div> - <i class="icon-severity-<%= issue.severity.downcase -%>"></i> - - <a href="#" onclick="return toggleIssueRule(this)" class="rulename issue-rule-link"><%= h @issue_results.rule(issue).getName() -%></a> - - <% if issue.resolution %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <span><%= message("issue.resolution.#{issue.resolution}") -%></span> - - <% else %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <span><%= message("issue.status.#{issue.status}") -%></span> - - <% end %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <%= message('issue.updated') -%> <a href="#" onclick="return toggleIssueChangelog(this)" class="gray issue-changelog-link" - id="toggle-issue-changelog"><%= distance_of_time_in_words_to_now(Api::Utils.java_to_ruby_datetime(issue.updateDate())) -%></a> - - <% if issue.reporter %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <span><%= message('issue.reported_by') -%> <%= @issue_results.user(issue.reporter).name -%></span> - + <ul class="code-issue-actions code-issue-list"> + <% if current_user %> + <li><a href='#' onclick="return issueForm('comment', this)" class="link-action spacer-right" autofocus><%= message('issue.comment.formlink') -%></a></li> <% end %> - <% if issue.authorLogin %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <span><%= message('issue.authorLogin') -%> <%= issue.authorLogin -%></span> - - <% end %> - <% if issue.technicalDebt %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <%= message('issue.technical_debt') -%> <a href="#" onclick="return toggleTechnicalDebt(this)" class="gray issue-technicaldebt-link" - id="toggle-issue-technicaldebt"><%= Internal.technical_debt.format(issue.technicalDebt) -%></a> - + <li> + <i class="icon-status-<%= issue.status.downcase -%>"></i><%= message("issue.status.#{issue.status}") -%> <%= '(' + message("issue.resolution.#{issue.resolution}") + ')' if issue.resolution -%> + </li> + <% if current_user %> + <% transitions = Internal.issues.listTransitions(issue).to_a + if !transitions.empty? && transitions.first + first_transition = transitions.first %> + <li> + <!-- Display only the first transition --> + <a href="#" onclick="return doIssueTransition(this, '<%= first_transition.key -%>')" class="link-action issue-transition spacer-left"> + <%= message("issue.transition.#{first_transition.key}") -%></a> + <!-- Display remaining transitions --> + <% if transitions.size > 1 %> + <div class="dropdown"> + <a href="#" class="link-action link-more" onclick="showDropdownMenuOnElement($j(this).next('.dropdown-menu')); return false;"/></a> + <ul style="display: none" class="dropdown-menu"> + <% transitions[1..-1].each do |transition| %> + <li> + <a href="#" onclick="return doIssueTransition(this, '<%= transition.key -%>')" class="link-action spacer-right"><%= message("issue.transition.#{transition.key}") -%></a> + </li> + <% end %> + </ul> + </div> + <% end %> + </li> + <% end %> <% end %> - </div> - - <div class="issue-rule rule-desc" style="display: none"></div> - <div class="issue-changelog" id="issue-changelog" style="display: none"></div> - <div class="issue-technicaldebt" id="issue-technicaldebt" style="display: none"></div> - - <% unless issue.message.blank? %> - <div class="code-issue-msg"> - <%= Api::Utils.split_newlines(h(issue.message)).join('<br/>') -%> - </div> - <% end %> - - <% - issue.comments.each do |comment| - comment_html_id = "comment-#{comment.key}-#{rand(100)}" - %> - <div class="code-issue-comment" id="<%= comment_html_id -%>" data-comment-key="<%= comment.key -%>"> - <h4> - <%= image_tag('reviews/comment.png') -%> <b><%= @issue_results.user(comment.userLogin()).name() -%></b> - (<%= distance_of_time_in_words_to_now(Api::Utils.java_to_ruby_datetime(comment.createdAt)) -%>) - <% if current_user && current_user.login==comment.userLogin %> - - <%= image_tag 'sep12.png' -%> - - <a class="link-action" href="#" onclick="return formEditIssueComment(this)"><%= message('edit') -%></a> - <a class="link-action spacer-right" href="#" onclick="return deleteIssueComment(this, '<%= escape_javascript(message('issue.comment.delete_confirm_message')) -%>')"><%= message('delete') -%></a> - <% end %> - </h4> - <%= Internal.text.markdownToHtml(comment.markdownText) -%> - </div> - <% end %> - - <% if current_user %> - - <div class="code-issue-actions"> - <a href='#' onclick="return issueForm('comment', this)" class="link-action spacer-right" autofocus><%= message('issue.comment.formlink') -%></a> - <% unless issue.resolution %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <span class="spacer-right"> + <% unless issue.resolution %> + <li> <% if issue.assignee %> - <a href='#' onclick="return issueForm('assign', this)" class="link-action"><%= message('assigned_to') -%></a> <%= h @issue_results.user(issue.assignee).name -%> - <% else %> + <% if current_user %> + <a href='#' onclick="return issueForm('assign', this)" class="link-action"><%= message('assigned_to') -%></a> <%= h @issue_results.user(issue.assignee).name -%> + <% else %> + <%= message('assigned_to') -%> <strong><%= h @issue_results.user(issue.assignee).name -%></strong> + <% end %> + <% elsif current_user %> <a href='#' onclick="return issueForm('assign', this)" class="link-action"><%= message('issue.assign.formlink') -%></a> <% if issue.assignee != current_user.login %> [<a href="#" onclick="return assignIssueToMe(this)" class="link-action"><%= message('issue.assign.to_me') -%></a>] <% end %> <% end %> - </span> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <span class="spacer-right"> - <% if issue.actionPlanKey %> - <a href="#" onclick="return issueForm('plan', this)" class="link-action"><%= message('issue.planned_for') -%></a> <%= h(@issue_results.actionPlan(issue).name()) -%> - <% else %> - <a href="#" onclick="return issueForm('plan', this)" class="link-action"><%= message('issue.do_plan') -%></a> - <% end %> - </span> - <% end %> - - <% - transitions = Internal.issues.listTransitions(issue).to_a - - # Display only the first transition - if !transitions.empty? && transitions.first - first_transition = transitions.first - %> - <img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> - - <a href="#" onclick="return doIssueTransition(this, '<%= first_transition.key -%>')" class="link-action spacer-right"><%= message("issue.transition.#{first_transition.key}") -%></a> + </li> + <li> + <% if issue.actionPlanKey %> + <% if current_user %> + <a href="#" onclick="return issueForm('plan', this)" class="link-action"><%= message('issue.planned_for') -%></a> <%= h(@issue_results.actionPlan(issue).name()) -%> + <% else %> + <%= message('issue.planned_for') -%> <strong><%= h(@issue_results.actionPlan(issue).name()) -%></strong> + <% end %> + <% elsif current_user %> + <a href="#" onclick="return issueForm('plan', this)" class="link-action"><%= message('issue.do_plan') -%></a> <% end %> + </li> + <% end %> + <% if current_user %> + <% plugin_actions = Internal.issues.listActions(issue) + if !issue.resolution || !plugin_actions.empty? %> + <li> + <div class="dropdown"> + <a href="#" class="link-action link-more" onclick="showDropdownMenuOnElement($j(this).next('.dropdown-menu')); return false;"><%= message('more_actions') -%></a> + <ul style="display: none" class="dropdown-menu"> + <% if Java::OrgSonarServerUser::UserSession.get().hasProjectPermission('issueadmin', issue.projectKey) %> + <% unless issue.resolution %> + <li> + <a href="#" onclick="return issueForm('severity', this)" class="link-action spacer-right"><%= message("issue.set_severity") -%></a> + </li> + <% end %> + <% end %> - <% - plugin_actions = Internal.issues.listActions(issue) - shouldDisplayDropDown = transitions.size > 1 || !issue.resolution || !plugin_actions.empty? - if shouldDisplayDropDown - %> - <div class="dropdown"> - <a href="#" class="link-action link-more" onclick="showDropdownMenuOnElement($j(this).next('.dropdown-menu')); return false;"><%= message('more_actions') -%></a> - <ul style="display: none" class="dropdown-menu"> - <% if Java::OrgSonarServerUser::UserSession.get().hasProjectPermission('issueadmin', issue.projectKey) %> - <% unless issue.resolution %> + <% # Display actions defined by plugins + plugin_actions.each do |action| %> <li> - <a href="#" onclick="return issueForm('severity', this)" class="link-action spacer-right"><%= message("issue.set_severity") -%></a> + <a href="#" onclick="return doPluginIssueAction(this, '<%= action.key -%>')" class="link-action spacer-right"><%= message("issue.action.#{action.key}.formlink") -%></a> </li> <% end %> - <% end %> + </ul> + </div> + </li> + <% end %> + <% end %> + <% if issue.technicalDebt %> + <li><%= message('issue.debt') -%> <%= Internal.technical_debt.format(issue.technicalDebt) -%></li> + <% end %> + <% if issue.authorLogin %> + <li><%= message('issue.authorLogin') -%> <%= issue.authorLogin -%></li> + <% end %> + <% if issue.reporter %> + <li><%= message('issue.reported_by') -%> <%= @issue_results.user(issue.reporter).name -%></li> + <% end %> + </ul> + <div class="code-issue-form hidden"></div> - <% # Display remaining transitions - if transitions.size > 1 - transitions[1..-1].each do |transition| %> - <li> - <a href="#" onclick="return doIssueTransition(this, '<%= transition.key -%>')" class="link-action spacer-right"><%= message("issue.transition.#{transition.key}") -%></a> - </li> - <% end - end %> + <div class="code-issue-details"> + <ul class="tabs"> + <li> + <a href="#tab-issue-rule"><%= message('rule') -%></a> + </li> + <li> + <a href="#tab-issue-changelog"><%= message('changelog') -%></a> + </li> + </ul> - <% # Display actions defined by plugins - plugin_actions.each do |action| %> - <li> - <a href="#" onclick="return doPluginIssueAction(this, '<%= action.key -%>')" class="link-action spacer-right"><%= message("issue.action.#{action.key}.formlink") -%></a> - </li> - <% end %> - </ul> - </div> - <% end %> + <div id="tab-issue-rule"> + <%= image_tag 'loading.gif', :class => 'rule-loading hidden' -%> + <div class="issue-rule rule-desc"></div> </div> - <div class="code-issue-form hidden"></div> - <% elsif issue.assignee || issue.actionPlanKey %> - <div class="code-issue-actions"> - <% if issue.assignee %> - <span class="gray"><%= message('assigned_to') -%> <%= h @issue_results.user(issue.assignee).name -%></span> - - <% end %> - <% if issue.actionPlanKey %> - <% if issue.assignee %><img src="<%= ApplicationController.root_context -%>/images/sep12.png"/> <% end %> - <span class="gray"><%= message('issue.planned_for') -%> <%= h(@issue_results.actionPlan(issue).name()) -%></span> - <% end %> + + <div id="tab-issue-changelog"> + <%= image_tag 'loading.gif', :class => 'changelog-loading hidden' -%> + <table class="issue-changelog spaced"> + </table> </div> - <% end %> + </div> + + <div class="code-issue-comments"> + <% issue.comments.each do |comment| + comment_html_id = "comment-#{comment.key}-#{rand(100)}" %> + <div class="code-issue-comment" id="<%= comment_html_id -%>" data-comment-key="<%= comment.key -%>"> + <h4> + <%= image_tag('reviews/comment.png') -%> <b><%= @issue_results.user(comment.userLogin()).name() -%></b> + (<%= distance_of_time_in_words_to_now(Api::Utils.java_to_ruby_datetime(comment.createdAt)) -%>) + <% if current_user && current_user.login==comment.userLogin %> + + <%= image_tag 'sep12.png' -%> + + <a class="link-action" href="#" onclick="return formEditIssueComment(this)"><%= message('edit') -%></a> + <a class="link-action spacer-right" href="#" onclick="return deleteIssueComment(this, '<%= escape_javascript(message('issue.comment.delete_confirm_message')) -%>')"><%= message('delete') -%></a> + <% end %> + </h4> + <%= Internal.text.markdownToHtml(comment.markdownText) -%> + </div> + <% end %> + </div> </div> + +<script> + $j('#issue-<%= u issue.key -%> .code-issue-details').tabs(); + $j('#issue-<%= u issue.key -%> .code-issue-toggle').click(function() { + toggleIssueCollapsed(this); + }); +</script> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_rule.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_rule.html.erb index f93e91898f2..19a91902617 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_rule.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_rule.html.erb @@ -1,3 +1,5 @@ +<h1 class="marginbottom10"><%= h @rule.name %></h1> + <div class="marginbottom10"> <% if @rule.description.strip.start_with?('<p>') %> <%= Internal.text.interpretMacros(@rule.description) %> @@ -12,8 +14,12 @@ </div> <% end %> -<div class="note"> - <%= h @rule.plugin_name -%> +<p class="note"> + <%= h @rule.plugin_name -%>:<%= h @rule.plugin_rule_key -%> <%= image_tag 'sep12.png' -%> - <a href="#" onclick="return openIssueRulePopup(this)"><%= h @rule.plugin_rule_key -%></a> -</div> + <% if @requirement %> + <%= @root_characteristic.name -%> > <%= @characteristic.name -%> + <% else %> + <%= message 'issue.technical_debt_deleted' %> + <% end %> +</p> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_technicaldebt.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_technicaldebt.html.erb deleted file mode 100644 index 09078b49363..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_technicaldebt.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -<div> - <% if @requirement %> - <%= @root_characteristic.name %> > <%= @characteristic.name %> - <% else %> - <%= message 'issue.technical_debt_deleted' %> - <% end %> -</div> - diff --git a/sonar-server/src/main/webapp/javascripts/issue.js b/sonar-server/src/main/webapp/javascripts/issue.js index e38027e80dc..3a91c7401ba 100644 --- a/sonar-server/src/main/webapp/javascripts/issue.js +++ b/sonar-server/src/main/webapp/javascripts/issue.js @@ -203,67 +203,45 @@ function submitCreateIssueForm(elt) { return false; } -function toggleIssueRule(elt) { +function toggleIssueCollapsed(elt) { var issueElt = $j(elt).closest('[data-issue-rule]'); - var ruleElt = issueElt.find('.issue-rule'); - if (ruleElt.is(':visible')) { - ruleElt.slideUp('fast'); - } else { - issueElt.find('.issue-changelog').slideUp('fast'); - issueElt.find('.issue-technicaldebt').slideUp('fast'); + issueElt.toggleClass('code-issue-collapsed'); + + if (!issueElt.hasClass('code-issue-collapsed')) { + + // Load rule desc + // Display loading images and hide existing content + var ruleLoading = issueElt.find('.rule-loading'); + ruleLoading.removeClass('hidden'); + var ruleElt = issueElt.find('.issue-rule'); + ruleElt.addClass('hidden'); var ruleKey = issueElt.attr('data-issue-rule'); $j.get(baseUrl + "/issue/rule/" + ruleKey, function (html) { ruleElt.html(html); - ruleElt.slideDown('fast'); - // re-enable the links opening modal popups ruleElt.find('.open-modal').modal(); + }).always(function () { + ruleLoading.addClass('hidden'); + ruleElt.removeClass('hidden'); }); - } - return false; -} -function toggleIssueChangelog(elt) { - var issueElt = $j(elt).closest('[data-issue-key]'); - var changelogElt = issueElt.find('.issue-changelog'); - if (changelogElt.is(':visible')) { - changelogElt.slideUp('fast'); - } else { - issueElt.find('.issue-rule').slideUp('fast'); - issueElt.find('.issue-technicaldebt').slideUp('fast'); + // Load changelog + // Display loading images and hide existing content + var cangelogLoading = issueElt.find('.changelog-loading'); + cangelogLoading.removeClass('hidden'); + var changelogElt = issueElt.find('.issue-changelog'); + changelogElt.addClass('hidden'); var issueKey = issueElt.attr('data-issue-key'); $j.get(baseUrl + "/issue/changelog/" + issueKey, function (html) { changelogElt.html(html); - changelogElt.slideDown('fast'); - }); - } - return false; -} - -function toggleTechnicalDebt(elt) { - var issueElt = $j(elt).closest('[data-issue-key]'); - var debtElt = issueElt.find('.issue-technicaldebt'); - if (debtElt.is(':visible')) { - debtElt.slideUp('fast'); - } else { - issueElt.find('.issue-changelog').slideUp('fast'); - issueElt.find('.issue-rule').slideUp('fast'); - var issueKey = issueElt.attr('data-issue-key'); - $j.get(baseUrl + "/issue/technicaldebt/" + issueKey, function (html) { - debtElt.html(html); - debtElt.slideDown('fast'); + }).always(function () { + cangelogLoading.addClass('hidden'); + changelogElt.removeClass('hidden'); }); } return false; } -function openIssueRulePopup(elt) { - var issueElt = $j(elt).closest('[data-issue-rule]'); - var ruleKey = issueElt.attr('data-issue-rule'); - openPopup(baseUrl + "/rules/show/" + ruleKey + "?layout=false", 'rule'); - return false; -} - function openIssuePopup(elt) { var issueElt = $j(elt).closest('[data-issue-key]'); var issueKey = issueElt.attr('data-issue-key'); diff --git a/sonar-server/src/main/webapp/stylesheets/style.css b/sonar-server/src/main/webapp/stylesheets/style.css index 2edc06c0cb0..84b5ba0a23e 100644 --- a/sonar-server/src/main/webapp/stylesheets/style.css +++ b/sonar-server/src/main/webapp/stylesheets/style.css @@ -814,6 +814,7 @@ th.operations, td.operations { line-height: 16px; color: #777; border: 1px solid #DDD; + border-bottom: medium none; } .code-issue-msg { @@ -854,7 +855,7 @@ th.operations, td.operations { top: 5px; right: 26px; } -.code-issue-comment, .code-issue-msg, .code-issue-actions, .code-issue-form, .issue-rule, .issue-changelog, .issue-technicaldebt { +.code-issue-comment, .code-issue-msg, .code-issue-actions, .code-issue-form { background-color: #EFEFEF; border: 1px solid #DDD; border-top: none; @@ -944,6 +945,7 @@ th.operations, td.operations { .code-issue-list { font-size: 0; white-space: nowrap; + background-color: #E4ECF3; } .code-issue-list > li { diff --git a/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java b/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java index b0a1cd61cb2..586444b6f5e 100644 --- a/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java @@ -21,7 +21,6 @@ package org.sonar.server.technicaldebt; import org.junit.Test; import org.sonar.api.issue.internal.WorkDayDuration; -import org.sonar.api.rules.Rule; import org.sonar.api.technicaldebt.server.Characteristic; import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic; import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager; @@ -61,11 +60,9 @@ public class DebtServiceTest { } @Test - public void find_requirement() { - Rule rule = Rule.create("repo", "key"); - Characteristic requirement = new DefaultCharacteristic(); - when(finder.findRequirementByRule(rule)).thenReturn(requirement); - assertThat(service.findRequirement(rule)).isEqualTo(requirement); + public void find_requirement_by_rule_id() { + service.findRequirementByRuleId(1); + verify(finder).findRequirementByRuleId(1); } @Test |