diff options
author | Julien Lancelot <julien.lancelot@gmail.com> | 2013-05-21 12:12:17 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@gmail.com> | 2013-05-21 12:12:17 +0200 |
commit | c93e1fea3a623d6d214c3fcb7b33cdd93c774937 (patch) | |
tree | 65da779b62904e18bc1fbfd441da1c347d1139dd | |
parent | b6b56822d8206c05510da48678dea8021b5be109 (diff) | |
download | sonarqube-c93e1fea3a623d6d214c3fcb7b33cdd93c774937.tar.gz sonarqube-c93e1fea3a623d6d214c3fcb7b33cdd93c774937.zip |
SONAR-4301 Add sort on issue search page
22 files changed, 589 insertions, 73 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDao.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDao.java index 6a67dcf6774..2fa1dba1ed1 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDao.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueDao.java @@ -30,6 +30,7 @@ import org.sonar.api.issue.IssueQuery; import org.sonar.core.persistence.MyBatis; import javax.annotation.CheckForNull; + import java.util.Collection; import java.util.Collections; import java.util.List; @@ -97,21 +98,22 @@ public class IssueDao implements BatchComponent, ServerComponent { return mapper.selectIssueAndComponentIds(query); } - Collection<IssueDto> selectByIds(Collection<Long> ids) { + @VisibleForTesting + Collection<IssueDto> selectByIds(Collection<Long> ids, IssueQuery.Sort sort, boolean asc) { SqlSession session = mybatis.openSession(); try { - return selectByIds(ids, session); + return selectByIds(ids, sort, asc, session); } finally { MyBatis.closeQuietly(session); } } - public Collection<IssueDto> selectByIds(Collection<Long> ids, SqlSession session) { + public Collection<IssueDto> selectByIds(Collection<Long> ids, IssueQuery.Sort sort, boolean asc, SqlSession session) { if (ids.isEmpty()) { return Collections.emptyList(); } - List<List<Long>> idsPartition = Lists.partition(newArrayList(ids), 1000); - Map<String, List<List<Long>>> params = ImmutableMap.of("ids", idsPartition); + Object idsPartition = Lists.partition(newArrayList(ids), 1000); + Map<String, Object> params = ImmutableMap.of("ids", idsPartition, "sort", sort, "asc", asc); return session.selectList("org.sonar.core.issue.db.IssueMapper.selectByIds", params); } } diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml index 40fc177e27d..9717a2417cf 100644 --- a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml @@ -32,6 +32,40 @@ p.kee as componentKey </sql> + <sql id="sortFilter"> + <if test="sort != null"> + order by + <choose> + <when test="'SEVERITY'.equals(sort.name())"> + i.severity + </when> + <when test="'STATUS'.equals(sort.name())"> + i.status + </when> + <when test="'ASSIGNEE'.equals(sort.name())"> + i.assignee + </when> + <when test="'CREATION_DATE'.equals(sort.name())"> + i.issue_creation_date + </when> + <when test="'UPDATE_DATE'.equals(sort.name())"> + i.issue_update_date + </when> + <when test="'CLOSE_DATE'.equals(sort.name())"> + i.issue_close_date + </when> + </choose> + <choose> + <when test="true.equals(asc)"> + asc + </when> + <otherwise> + desc + </otherwise> + </choose> + </if> + </sql> + <insert id="insert" parameterType="Issue" useGeneratedKeys="false" keyProperty="id"> INSERT INTO issues (kee, resource_id, rule_id, action_plan_key, severity, manual_severity, message, line, effort_to_fix, status, @@ -115,6 +149,7 @@ and i.rule_id=r.id and p.id=i.resource_id </where> + <include refid="sortFilter"/> </select> <select id="selectIssueAndComponentIds" parameterType="map" resultType="Issue"> @@ -244,31 +279,7 @@ <if test="sort == null"> order by i.id </if> - <if test="sort != null"> - order by - <choose> - <when test="'CREATION_DATE'.equals(sort.name())"> - i.issue_creation_date - </when> - <when test="'UPDATE_DATE'.equals(sort.name())"> - i.issue_update_date - </when> - <when test="'CLOSE_DATE'.equals(sort.name())"> - i.issue_close_date - </when> - <when test="'ASSIGNEE'.equals(sort.name())"> - i.assignee - </when> - </choose> - <choose> - <when test="true.equals(asc)"> - asc - </when> - <otherwise> - desc - </otherwise> - </choose> - </if> + <include refid="sortFilter"/> </sql> </mapper> diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java index 2bc8932b731..cfb30567f21 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java @@ -27,7 +27,6 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.DateUtils; import org.sonar.core.persistence.AbstractDaoTestCase; -import java.util.Collection; import java.util.List; import static com.google.common.collect.Lists.newArrayList; @@ -222,8 +221,32 @@ public class IssueDaoTest extends AbstractDaoTestCase { } @Test + public void should_select_sort_by_severity() { + setupData("shared", "should_select_returned_sorted_result_by_severity"); + + IssueQuery query = IssueQuery.builder().sort(IssueQuery.Sort.SEVERITY).asc(true).build(); + List<IssueDto> results = newArrayList(dao.select(query)); + assertThat(results).hasSize(3); + assertThat(results.get(0).getSeverity()).isEqualTo("BLOCKER"); + assertThat(results.get(1).getSeverity()).isEqualTo("MAJOR"); + assertThat(results.get(2).getSeverity()).isEqualTo("MINOR"); + } + + @Test + public void should_select_sort_by_status() { + setupData("shared", "should_select_returned_sorted_result_by_status"); + + IssueQuery query = IssueQuery.builder().sort(IssueQuery.Sort.STATUS).asc(true).build(); + List<IssueDto> results = newArrayList(dao.select(query)); + assertThat(results).hasSize(3); + assertThat(results.get(0).getStatus()).isEqualTo("CLOSED"); + assertThat(results.get(1).getStatus()).isEqualTo("OPEN"); + assertThat(results.get(2).getStatus()).isEqualTo("REOPEN"); + } + + @Test public void should_select_sort_by_assignee() { - setupData("shared", "should_select_returned_sorted_result"); + setupData("shared", "should_select_returned_sorted_result_by_assignee"); IssueQuery query = IssueQuery.builder().sort(IssueQuery.Sort.ASSIGNEE).asc(true).build(); List<IssueDto> results = newArrayList(dao.select(query)); @@ -234,6 +257,42 @@ public class IssueDaoTest extends AbstractDaoTestCase { } @Test + public void should_select_sort_by_creation_date() { + setupData("shared", "should_select_returned_sorted_result_by_creation_date"); + + IssueQuery query = IssueQuery.builder().sort(IssueQuery.Sort.CREATION_DATE).asc(false).build(); + List<IssueDto> results = newArrayList(dao.select(query)); + assertThat(results).hasSize(3); + assertThat(results.get(0).getId()).isEqualTo(102); + assertThat(results.get(1).getId()).isEqualTo(100); + assertThat(results.get(2).getId()).isEqualTo(101); + } + + @Test + public void should_select_sort_by_update_date() { + setupData("shared", "should_select_returned_sorted_result_by_update_date"); + + IssueQuery query = IssueQuery.builder().sort(IssueQuery.Sort.UPDATE_DATE).asc(false).build(); + List<IssueDto> results = newArrayList(dao.select(query)); + assertThat(results).hasSize(3); + assertThat(results.get(0).getId()).isEqualTo(102); + assertThat(results.get(1).getId()).isEqualTo(100); + assertThat(results.get(2).getId()).isEqualTo(101); + } + + @Test + public void should_select_sort_by_close_date() { + setupData("shared", "should_select_returned_sorted_result_by_close_date"); + + IssueQuery query = IssueQuery.builder().sort(IssueQuery.Sort.CLOSE_DATE).asc(false).build(); + List<IssueDto> results = newArrayList(dao.select(query)); + assertThat(results).hasSize(3); + assertThat(results.get(0).getId()).isEqualTo(102); + assertThat(results.get(1).getId()).isEqualTo(100); + assertThat(results.get(2).getId()).isEqualTo(101); + } + + @Test public void should_select_issue_and_component_ids() { setupData("shared", "should_select_issue_and_component_ids"); @@ -259,7 +318,10 @@ public class IssueDaoTest extends AbstractDaoTestCase { public void should_select_by_ids() { setupData("shared", "should_select_by_ids"); - Collection<IssueDto> results = dao.selectByIds(newArrayList(100l, 101l, 102l)); + List<IssueDto> results = newArrayList(dao.selectByIds(newArrayList(100l, 101l, 102l), IssueQuery.Sort.CREATION_DATE, false)); assertThat(results).hasSize(3); + assertThat(results.get(0).getId()).isEqualTo(102); + assertThat(results.get(1).getId()).isEqualTo(100); + assertThat(results.get(2).getId()).isEqualTo(101); } } diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_ids.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_ids.xml index d2804c856d3..3d6ad15c5a0 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_ids.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_ids.xml @@ -18,11 +18,11 @@ assignee="perceval" author_login="[null]" attributes="JIRA=FOO-1234" - issue_creation_date="2013-04-16" - issue_update_date="2013-04-16" - issue_close_date="2013-04-16" - created_at="2013-04-16" - updated_at="2013-04-16" + issue_creation_date="2013-04-17" + issue_update_date="2013-04-17" + issue_close_date="2013-04-17" + created_at="2013-04-17" + updated_at="2013-04-17" /> <issues @@ -68,10 +68,10 @@ assignee="perceval" author_login="[null]" attributes="JIRA=FOO-1234" - issue_creation_date="2013-04-16" - issue_update_date="2013-04-16" - issue_close_date="2013-04-16" - created_at="2013-04-16" - updated_at="2013-04-16" + issue_creation_date="2013-04-18" + issue_update_date="2013-04-18" + issue_close_date="2013-04-18" + created_at="2013-04-18" + updated_at="2013-04-18" /> </dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_assignee.xml index 41a97ef98b8..41a97ef98b8 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_assignee.xml diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_close_date.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_close_date.xml new file mode 100644 index 00000000000..b27051ff207 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_close_date.xml @@ -0,0 +1,77 @@ +<dataset> + + <!-- rule 500 --> + <issues + id="100" + kee="ABCDE-1" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="arthur" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-17" + issue_close_date="2013-04-17" + created_at="2013-04-16" + updated_at="2013-04-17" + /> + + <issues + id="101" + kee="ABCDE-2" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="perceval" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> + + + <!-- rule 501 --> + <issues + id="102" + kee="ABCDE-3" + resource_id="401" + rule_id="501" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="henry" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-18" + issue_close_date="2013-04-18" + created_at="2013-04-16" + updated_at="2013-04-18" + /> +</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_creation_date.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_creation_date.xml new file mode 100644 index 00000000000..d84b71fa09b --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_creation_date.xml @@ -0,0 +1,74 @@ +<dataset> + + <issues + id="100" + kee="ABCDE-1" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="arthur" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-15" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-15" + updated_at="2013-04-16" + /> + + <issues + id="101" + kee="ABCDE-2" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="perceval" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-14" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-14" + updated_at="2013-04-16" + /> + + <issues + id="102" + kee="ABCDE-3" + resource_id="401" + rule_id="501" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="henry" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> +</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_severity.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_severity.xml new file mode 100644 index 00000000000..9dae4080973 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_severity.xml @@ -0,0 +1,74 @@ +<dataset> + + <issues + id="100" + kee="ABCDE-1" + resource_id="401" + rule_id="500" + severity="MINOR" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="arthur" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> + + <issues + id="101" + kee="ABCDE-2" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="perceval" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> + + <issues + id="102" + kee="ABCDE-3" + resource_id="401" + rule_id="501" + severity="MAJOR" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="henry" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> +</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_status.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_status.xml new file mode 100644 index 00000000000..b510a5c447a --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_status.xml @@ -0,0 +1,77 @@ +<dataset> + + <!-- rule 500 --> + <issues + id="100" + kee="ABCDE-1" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="arthur" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> + + <issues + id="101" + kee="ABCDE-2" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="CLOSED" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="perceval" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> + + + <!-- rule 501 --> + <issues + id="102" + kee="ABCDE-3" + resource_id="401" + rule_id="501" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="REOPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="henry" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> +</dataset> diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_update_date.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_update_date.xml new file mode 100644 index 00000000000..769bae1454d --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_returned_sorted_result_by_update_date.xml @@ -0,0 +1,74 @@ +<dataset> + + <issues + id="100" + kee="ABCDE-1" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="arthur" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-17" + issue_close_date="2013-04-17" + created_at="2013-04-16" + updated_at="2013-04-17" + /> + + <issues + id="101" + kee="ABCDE-2" + resource_id="401" + rule_id="500" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="perceval" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-16" + issue_close_date="2013-04-16" + created_at="2013-04-16" + updated_at="2013-04-16" + /> + + <issues + id="102" + kee="ABCDE-3" + resource_id="401" + rule_id="501" + severity="BLOCKER" + manual_severity="[false]" + message="[null]" + line="200" + effort_to_fix="4.2" + status="OPEN" + resolution="FIXED" + checksum="XXX" + reporter="arthur" + assignee="henry" + author_login="[null]" + attributes="JIRA=FOO-1234" + issue_creation_date="2013-04-16" + issue_update_date="2013-04-18" + issue_close_date="2013-04-18" + created_at="2013-04-16" + updated_at="2013-04-18" + /> +</dataset> diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueQuery.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueQuery.java index 869be8aca7e..4a74dedf0fb 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueQuery.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueQuery.java @@ -25,6 +25,7 @@ import org.sonar.api.rule.RuleKey; import javax.annotation.CheckForNull; import javax.annotation.Nullable; + import java.util.Collection; import java.util.Date; @@ -39,7 +40,7 @@ public class IssueQuery { public static final int MAX_ISSUE_KEYS = 500; public static enum Sort { - CREATION_DATE, UPDATE_DATE, CLOSE_DATE, ASSIGNEE, SEVERITY + CREATION_DATE, UPDATE_DATE, CLOSE_DATE, ASSIGNEE, SEVERITY, STATUS } private final Collection<String> issueKeys; @@ -58,7 +59,7 @@ public class IssueQuery { private final Date createdAfter; private final Date createdBefore; private final Sort sort; - private final boolean asc; + private final Boolean asc; private final String requiredRole; // max results per page @@ -154,7 +155,7 @@ public class IssueQuery { return sort; } - public boolean asc() { + public Boolean asc() { return asc; } @@ -197,7 +198,7 @@ public class IssueQuery { private Date createdAfter; private Date createdBefore; private Sort sort; - private boolean asc = false; + private Boolean asc = false; private Integer pageSize; private Integer pageIndex; private String requiredRole; @@ -297,7 +298,7 @@ public class IssueQuery { return this; } - public Builder asc(boolean asc) { + public Builder asc(Boolean asc) { this.asc = asc; return this; } diff --git a/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java b/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java index 515b240daab..f0fb6517564 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java @@ -46,6 +46,7 @@ import org.sonar.core.user.AuthorizationDao; import org.sonar.server.platform.UserSession; import javax.annotation.CheckForNull; + import java.util.Collection; import java.util.List; import java.util.Map; @@ -117,7 +118,7 @@ public class DefaultIssueFinder implements IssueFinder { Set<Long> pagedIssueIds = pagedIssueIds(authorizedIssues, paging); // 4. Load issues and their related data (rules, components, comments, action plans, ...) - Collection<IssueDto> pagedIssues = issueDao.selectByIds(pagedIssueIds, sqlSession); + Collection<IssueDto> pagedIssues = issueDao.selectByIds(pagedIssueIds, query.sort(), query.asc(), sqlSession); Map<String, DefaultIssue> issuesByKey = newHashMap(); List<Issue> issues = newArrayList(); Set<Integer> ruleIds = Sets.newHashSet(); diff --git a/sonar-server/src/main/java/org/sonar/server/issue/PublicRubyIssueService.java b/sonar-server/src/main/java/org/sonar/server/issue/PublicRubyIssueService.java index eac63549e25..f9ffe8071f9 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/PublicRubyIssueService.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/PublicRubyIssueService.java @@ -32,6 +32,7 @@ import org.sonar.api.web.UserRole; import org.sonar.server.util.RubyUtils; import javax.annotation.Nullable; + import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -84,7 +85,8 @@ public class PublicRubyIssueService implements RubyIssueService { builder.pageIndex(RubyUtils.toInteger(props.get("pageIndex"))); String sort = (String) props.get("sort"); if (sort != null) { - builder.sort(IssueQuery.Sort.valueOf(sort)); + builder.sort(IssueQuery.Sort.valueOf(sort.toUpperCase())); + builder.asc(RubyUtils.toBoolean(props.get("asc"))); } return builder.build(); } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb index c10e77552b6..ff855c03b5c 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb @@ -32,7 +32,6 @@ class IssuesController < ApplicationController @filter.criteria=criteria_params @filter.execute - # TODO replace by project from issues result API @project = Project.by_key(@filter.criteria('componentRoots')).root_project if @filter.criteria('componentRoots') end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb index 2b8617e2bff..013da3c1bb8 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb @@ -912,5 +912,4 @@ module ApplicationHelper html end - end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/issues_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/issues_helper.rb new file mode 100644 index 00000000000..fe629dc62da --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/issues_helper.rb @@ -0,0 +1,32 @@ +# +# Sonar, entreprise quality control tool. +# Copyright (C) 2008-2013 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube 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. +# +# SonarQube 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 this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +module IssuesHelper + + def column_html(filter, column_label, column_tooltip, sort) + filter_sort = filter.criteria[:sort] + filter_asc = filter.criteria[:asc] == 'true' ? true : false + html = link_to_function(h(column_label), "refreshList('#{escape_javascript sort}',#{!filter_asc}, #{filter.criteria[:page]||1})", :title => h(column_tooltip)) + if sort == filter_sort + html << (filter_asc ? image_tag("asc12.png") : image_tag("desc12.png")) + end + html + end + +end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb index 32d30ee96bf..5bce516bb72 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb @@ -20,9 +20,6 @@ require 'set' class IssueFilter - CRITERIA_SEPARATOR = '|' - CRITERIA_KEY_VALUE_SEPARATOR = ',' - attr_reader :paging, :issues, :issues_result def criteria(key=nil) @@ -75,7 +72,9 @@ class IssueFilter @issues_result = nil @paging = nil @issues = nil - criteria['pageSize'] = 25 + criteria['pageSize'] = 100 + criteria['sort'] ||= 'CREATION_DATE' + criteria['asc'] ||= 'false' self end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb index 3bd595a6eac..f4e75cd8afe 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb @@ -1,3 +1,22 @@ +<% content_for :script do %> + <script> + var filterCriteria = <%= @filter.criteria.to_json -%>; + + function refreshList(sort, asc, page) { + $j('#issue-filter-foot_pages').hide(); + $j('#issue-filter-foot_loading').show(); + + filterCriteria['sort']=sort; + filterCriteria['asc']=asc; + filterCriteria['pageIndex']=page; + var url=baseUrl + '/issues/search?' + $j.param(filterCriteria); + + window.location = url; + return false; + } + </script> +<% end %> + <% if @filter.issues && !@filter.issues.empty? colspan = 8 @@ -7,10 +26,10 @@ <thead> <tr> <th width="1%" nowrap> - <%= message('severity_abbreviated') -%> + <%= column_html(@filter, message('severity_abbreviated'), message('severity'), 'SEVERITY') %> </th> <th width="1%" nowrap> - <%= message('status_abbreviated') -%> + <%= column_html(@filter, message('status_abbreviated'), message('status'), 'STATUS') %> </th> <th> <%= message('description') -%> @@ -19,16 +38,16 @@ <%= message('component') -%> </th> <th> - <%= message('issue_filter.header.assignee') -%> + <%= column_html(@filter, message('issue_filter.header.assignee'), message('issue_filter.header.assignee'), 'ASSIGNEE') %> </th> <th> <%= message('issue_filter.header.action_plan') -%> </th> <th> - <%= message('issue_filter.header.creation_date') -%> + <%= column_html(@filter, message('issue_filter.header.creation_date'), message('issue_filter.header.creation_date'), 'CREATION_DATE') %> </th> <th> - <%= message('issue_filter.header.update_date') -%> + <%= column_html(@filter, message('issue_filter.header.update_date'), message('issue_filter.header.update_date'), 'UPDATE_DATE') %> </th> </tr> </thead> @@ -44,7 +63,7 @@ <img src="<%= ApplicationController.root_context -%>/images/status/<%= issue.status -%>.png" title="<%= message(issue.status.downcase).capitalize -%>"/> </td> <td> - <%= link_to h(issue.message), :controller => 'issue', :action => 'view', :id => issue.key -%> + <%= link_to h(truncate(issue.message, :length => 100)), :controller => 'issue', :action => 'view', :id => issue.key -%> </td> <td> <%= h @filter.issues_result.component(issue).name -%> @@ -72,7 +91,7 @@ <% end %> </tbody> - <%= paginate_java(@filter.paging, :colspan => colspan, :include_loading_icon => true) { |label, page_id| + <%= paginate_java(@filter.paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id| link_to(label, @filter.criteria.merge({:pageIndex => page_id})) } -%> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb index 21c332a60c2..102b50aab1f 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb @@ -1,10 +1,13 @@ <ul class="sidebar gray-sidebar"> <form method="GET" action="<%= ApplicationController.root_context -%>/issues/search" > + + <input type="hidden" name="sort" value="<%= @filter.criteria('sort')-%>"/> + <input type="hidden" name="asc" value="<%= @filter.criteria('asc') -%>"/> + <li class="sidebar-title"> <%= message('issue_filter.new_search') -%> </li> <li id="criteria-project" class="marginbottom5"> - <!-- TODO replace by project from issues result API--> <% selected_project = @project if @filter.criteria('componentRoots') %> <%= message 'issue_filter.criteria.project' -%>: <%= resource_select_tag 'componentRoots', :resource_type_property => 'supportsGlobalDashboards', :width => '100%', diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb index 1234b293a22..ffc32f12e80 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/search.html.erb @@ -3,9 +3,14 @@ <%= render :partial => 'issues/sidebar' -%> </div> + <div class="page-split-right"> <div id="content"> <div class="marginbottom10"> + <% if @filter.issues_result && @filter.issues_result.securityExclusions() %> + <p class="notes"><%= message('results_not_display_due_to_security') -%></p> + <% end %> + <%= render :partial => 'list' -%> </div> </div> diff --git a/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java b/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java index 0c9fdea9f40..fd4bca4597a 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueFinderTest.java @@ -53,6 +53,7 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anySet; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.*; public class DefaultIssueFinderTest { @@ -82,7 +83,7 @@ public class DefaultIssueFinderTest { .setStatus("OPEN").setResolution("OPEN"); List<IssueDto> dtoList = newArrayList(issue1, issue2); when(issueDao.selectIssueAndComponentIds(eq(query), any(SqlSession.class))).thenReturn(dtoList); - when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList); + when(issueDao.selectByIds(anyCollection(), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class))).thenReturn(dtoList); IssueQueryResult results = finder.find(query); assertThat(results.issues()).hasSize(2); @@ -107,11 +108,11 @@ public class DefaultIssueFinderTest { List<IssueDto> dtoList = newArrayList(issue1, issue2); when(issueDao.selectIssueAndComponentIds(eq(query), any(SqlSession.class))).thenReturn(dtoList); when(authorizationDao.keepAuthorizedComponentIds(anySet(), anyInt(), anyString(), any(SqlSession.class))).thenReturn(newHashSet(123)); - when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(newArrayList(issue1)); + when(issueDao.selectByIds(anyCollection(), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class))).thenReturn(newArrayList(issue1)); IssueQueryResult results = finder.find(query); - verify(issueDao).selectByIds(eq(newHashSet(1L)), any(SqlSession.class)); + verify(issueDao).selectByIds(eq(newHashSet(1L)), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class)); assertThat(results.securityExclusions()).isTrue(); } @@ -131,7 +132,7 @@ public class DefaultIssueFinderTest { .setStatus("OPEN").setResolution("OPEN"); List<IssueDto> dtoList = newArrayList(issue1, issue2); when(issueDao.selectIssueAndComponentIds(eq(query), any(SqlSession.class))).thenReturn(dtoList); - when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList); + when(issueDao.selectByIds(anyCollection(), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class))).thenReturn(dtoList); IssueQueryResult results = finder.find(query); assertThat(results.paging().offset()).isEqualTo(0); @@ -139,7 +140,7 @@ public class DefaultIssueFinderTest { assertThat(results.paging().pages()).isEqualTo(2); // Only one result is expected because the limit is 1 - verify(issueDao).selectByIds(eq(newHashSet(1L)), any(SqlSession.class)); + verify(issueDao).selectByIds(eq(newHashSet(1L)), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class)); } @Test @@ -174,7 +175,7 @@ public class DefaultIssueFinderTest { .setStatus("OPEN").setResolution("OPEN"); List<IssueDto> dtoList = newArrayList(issue1, issue2); when(issueDao.selectIssueAndComponentIds(eq(query), any(SqlSession.class))).thenReturn(dtoList); - when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList); + when(issueDao.selectByIds(anyCollection(), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class))).thenReturn(dtoList); IssueQueryResult results = finder.find(query); assertThat(results.issues()).hasSize(2); @@ -202,7 +203,7 @@ public class DefaultIssueFinderTest { .setStatus("OPEN").setResolution("OPEN"); List<IssueDto> dtoList = newArrayList(issue1, issue2); when(issueDao.selectIssueAndComponentIds(eq(query), any(SqlSession.class))).thenReturn(dtoList); - when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList); + when(issueDao.selectByIds(anyCollection(), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class))).thenReturn(dtoList); IssueQueryResult results = finder.find(query); assertThat(results.issues()).hasSize(2); @@ -230,7 +231,7 @@ public class DefaultIssueFinderTest { .setStatus("OPEN").setResolution("OPEN"); List<IssueDto> dtoList = newArrayList(issue1, issue2); when(issueDao.selectIssueAndComponentIds(eq(query), any(SqlSession.class))).thenReturn(dtoList); - when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(dtoList); + when(issueDao.selectByIds(anyCollection(), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class))).thenReturn(dtoList); when(actionPlanService.findByKeys(anyCollection())).thenReturn(newArrayList(actionPlan1, actionPlan2)); IssueQueryResult results = finder.find(query); @@ -245,7 +246,7 @@ public class DefaultIssueFinderTest { grantAccessRights(); IssueQuery query = IssueQuery.builder().build(); when(issueDao.selectIssueAndComponentIds(eq(query), any(SqlSession.class))).thenReturn(Collections.<IssueDto>emptyList()); - when(issueDao.selectByIds(anyCollection(), any(SqlSession.class))).thenReturn(Collections.<IssueDto>emptyList()); + when(issueDao.selectByIds(anyCollection(), any(IssueQuery.Sort.class), anyBoolean(), any(SqlSession.class))).thenReturn(Collections.<IssueDto>emptyList()); IssueQueryResult results = finder.find(query); diff --git a/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyIssueServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyIssueServiceTest.java index 1267beb69ae..17c2a5262b2 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyIssueServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyIssueServiceTest.java @@ -74,6 +74,8 @@ public class PublicRubyIssueServiceTest { map.put("rules", "squid:AvoidCycle,findbugs:NullReference"); map.put("pageSize", 10l); map.put("pageIndex", 50); + map.put("sort", "creation_date"); + map.put("asc", true); IssueQuery query = new PublicRubyIssueService(finder).toQuery(map); assertThat(query.issueKeys()).containsOnly("ABCDE1234"); @@ -92,6 +94,8 @@ public class PublicRubyIssueServiceTest { assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200")); assertThat(query.pageSize()).isEqualTo(10); assertThat(query.pageIndex()).isEqualTo(50); + assertThat(query.sort()).isEqualTo(IssueQuery.Sort.CREATION_DATE); + assertThat(query.asc()).isTrue(); } @Test |