JiHan Kim 2014-03-18
IssueSearch: group milestones by state using optgroup
@1c134a3337a5f3b3ca9c7ed1c9eb52619ba1da84
app/assets/stylesheets/less/_override.less
--- app/assets/stylesheets/less/_override.less
+++ app/assets/stylesheets/less/_override.less
@@ -91,9 +91,9 @@
 
 .select2-results {
     max-height: 400px;
-    padding:0;
+    padding:4px; margin:4px 0 0 0;
 
-    li { margin-bottom:1px; padding-left:4px; }
+    li { margin-bottom:1px; }
 
     .avatar-wrap { margin-top:0; }
 
@@ -115,6 +115,11 @@
         padding:3px 7px 4px 8px;
         background:#fafafa; color:#aaa;
     }
+
+    .select2-result-with-children {
+        border-top:1px solid #eee;
+        padding-top:4px; margin-top:4px;
+    }
 }
 
 
app/views/common/select2.scala.html
--- app/views/common/select2.scala.html
+++ app/views/common/select2.scala.html
@@ -41,8 +41,7 @@
 </div>
 </script>
 <script id="tplSelect2FormatMilestone" type="text/x-jquery-tmpl">
-<div title="${name}">
-    <span class="label milestone-state ${state}">${stateLabel}</span>
+<div title="[${stateLabel}] ${name}">
     ${name}
 </div>
 </script>
app/views/issue/create.scala.html
--- app/views/issue/create.scala.html
+++ app/views/issue/create.scala.html
@@ -92,7 +92,7 @@
                         <dl id="milestoneOption" class="issue-option">
                             <dt>@Messages("milestone")</dt>
                             <dd>
-                            @defining(Milestone.findByProjectId(project.id)) { milestones =>
+                            @defining(Milestone.findOpenMilestones(project.id)) { milestones =>
                                 @if(milestones.isEmpty()) {
                                     <a href="@routes.MilestoneApp.newMilestoneForm(project.owner, project.name)" target="_blank" class="ybtn ybtn-success ybtn-small">@Messages("milestone.menu.new")</a>
                                 } else {
app/views/issue/edit.scala.html
--- app/views/issue/edit.scala.html
+++ app/views/issue/edit.scala.html
@@ -116,21 +116,37 @@
                     <dl id="milestoneOption" class="issue-option">
                         <dt>@Messages("milestone")</dt>
                         <dd>
-                        @defining(Milestone.findByProjectId(project.id)) { milestones =>
-                            @if(milestones.isEmpty()) {
+                        @defining(issue.milestone != null) { hasMilestone =>
+                            @if(Milestone.findByProjectId(project.id).isEmpty()) {
                                 <a href="@routes.MilestoneApp.newMilestoneForm(project.owner, project.name)" target="_blank" class="ybtn ybtn-success ybtn-small">@Messages("milestone.menu.new")</a>
                             } else {
                                 <select id="milestoneId" name="milestoneId"
                                             data-toggle="select2" data-format="milestone"
                                             data-placeholder="@Messages("issue.milestone.selectDefault")">
                                         <option></option>
-                                        <option value="-1" @if(issue.milestone == null){selected}>@Messages("issue.noMilestone")</option>
-                                        @for(milestone <- milestones){
-                                        <option value="@milestone.id" data-state="@milestone.state"
-                                            @if(issue.milestone != null && issue.milestone.id == milestone.id){selected}>
-                                            @milestone.title
+                                        <option value="@Milestone.NULL_MILESTONE_ID" @if(!hasMilestone){ selected }>
+                                            @Messages("issue.noMilestone")
                                         </option>
+                                        <optgroup label="@Messages("milestone.state.open")">
+                                        @for(milestone <- Milestone.findOpenMilestones(project.id)){
+                                            <option value="@milestone.id" data-state="@milestone.state"
+                                            @if(hasMilestone && issue.milestone.id == milestone.id){
+                                                selected
+                                            }>
+                                                @milestone.title
+                                            </option>
                                         }
+                                        </optgroup>
+                                        <optgroup label="@Messages("milestone.state.closed")">
+                                        @for(milestone <- Milestone.findClosedMilestones(project.id)){
+                                            <option value="@milestone.id" data-state="@milestone.state"
+                                            @if(hasMilestone && issue.milestone.id == milestone.id){
+                                                selected
+                                            }>
+                                                @milestone.title
+                                            </option>
+                                        }
+                                        </optgroup>
                                 </select>
                             }
                         }
app/views/issue/partial_search.scala.html
--- app/views/issue/partial_search.scala.html
+++ app/views/issue/partial_search.scala.html
@@ -126,30 +126,32 @@
                         <dd>
                             <select id="milestoneId" name="milestoneId" data-toggle="select2" data-format="milestone">
                                 <option value="">@Messages("milestone.state.all")</option>
-                                @if(param.milestoneId != null
-                                    && param.milestoneId == Milestone.NULL_MILESTONE_ID){
-                                    <option value="@Milestone.NULL_MILESTONE_ID">
-                                        @Messages("issue.noMilestone")
-                                    </option>
-                                }
-                                @for(milestone <- Milestone.findMilestones(project.id, State.OPEN, "dueDate", Direction.DESC)){
-                                    <option value="@milestone.id"
-                                            data-state="@milestone.state"
+                                <option value="@Milestone.NULL_MILESTONE_ID"
+                                    @if(param.milestoneId != null && param.milestoneId == Milestone.NULL_MILESTONE_ID){
+                                    selected
+                                }>
+                                    @Messages("issue.noMilestone")
+                                </option>
+                                <optgroup label="@Messages("milestone.state.open")">
+                                @for(milestone <- Milestone.findOpenMilestones(project.id)){
+                                    <option value="@milestone.id" data-state="@milestone.state"
                                     @if(param.milestoneId != null && param.milestoneId == milestone.id){
                                         selected
                                     }>
                                         @milestone.title
                                     </option>
                                 }
-                                @for(milestone <- Milestone.findMilestones(project.id, State.CLOSED, "dueDate", Direction.DESC)){
-                                    <option value="@milestone.id"
-                                            data-state="@milestone.state"
+                                </optgroup>
+                                <optgroup label="@Messages("milestone.state.closed")">
+                                @for(milestone <- Milestone.findClosedMilestones(project.id)){
+                                    <option value="@milestone.id" data-state="@milestone.state"
                                     @if(param.milestoneId != null && param.milestoneId == milestone.id){
                                         selected
                                     }>
                                         @milestone.title
                                     </option>
                                 }
+                                </optgroup>
                             </select>
                         </dd>
                     </dl>
app/views/issue/view.scala.html
--- app/views/issue/view.scala.html
+++ app/views/issue/view.scala.html
@@ -146,27 +146,44 @@
                         <dl>
                             <dt>@Messages("milestone")</dt>
                             <dd style="padding:5px 10px;">
-                            @defining(issue.milestone != null) { hasMilestone =>
-                                @if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
-                                <select id="milestone" name="milestone.id" data-toggle="select2" data-format="milestone">
-                                    <option value="-1" @if(!hasMilestone){ selected }>@Messages("issue.noMilestone")</option>
-                                    @for(milestone <- Milestone.findByProjectId(project.id)){
-                                    <option value="@milestone.id"
-                                        @if(hasMilestone && issue.milestone.id == milestone.id){
-                                            selected
+                            @if(Milestone.findByProjectId(project.id).isEmpty()){
+                                <a href="@routes.MilestoneApp.newMilestoneForm(project.owner, project.name)" target="_blank" class="ybtn ybtn-success ybtn-small">@Messages("milestone.menu.new")</a>
+                            } else {
+                                @defining(issue.milestone != null) { hasMilestone =>
+                                    @if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
+                                    <select id="milestone" name="milestone.id" data-toggle="select2" data-format="milestone">
+                                        <option value="@Milestone.NULL_MILESTONE_ID" @if(!hasMilestone){ selected }>
+                                            @Messages("issue.noMilestone")
+                                        </option>
+                                        <optgroup label="@Messages("milestone.state.open")">
+                                        @for(milestone <- Milestone.findOpenMilestones(project.id)){
+                                            <option value="@milestone.id" data-state="@milestone.state"
+                                            @if(hasMilestone && issue.milestone.id == milestone.id){
+                                                selected
+                                            }>
+                                                @milestone.title
+                                            </option>
                                         }
-                                        data-state="@milestone.state">
-                                        @milestone.title
-                                    </option>
-                                    }
-                                </select>
-                                } else {
-                                    @if(hasMilestone){
-                                        <a href="@routes.MilestoneApp.milestone(project.owner, project.name, issue.milestone.id)">
-                                            @issue.milestone.title
-                                        </a>
+                                        </optgroup>
+                                        <optgroup label="@Messages("milestone.state.closed")">
+                                        @for(milestone <- Milestone.findClosedMilestones(project.id)){
+                                            <option value="@milestone.id" data-state="@milestone.state"
+                                            @if(hasMilestone && issue.milestone.id == milestone.id){
+                                                selected
+                                            }>
+                                                @milestone.title
+                                            </option>
+                                        }
+                                        </optgroup>
+                                    </select>
                                     } else {
-                                        @Messages("issue.noMilestone")
+                                        @if(hasMilestone){
+                                            <a href="@routes.MilestoneApp.milestone(project.owner, project.name, issue.milestone.id)">
+                                                @issue.milestone.title
+                                            </a>
+                                        } else {
+                                            @Messages("issue.noMilestone")
+                                        }
                                     }
                                 }
                             }
@@ -177,7 +194,7 @@
                         @**<!-- voters -->**@
                         <dl>
                             <dt>@Messages("issue.vote")</dt>
-                            <dd>
+                            <dd style="padding:5px 10px;">
                                 @if(isProjectResourceCreatable(User.findByLoginId(session.get("loginId")), project, ResourceType.ISSUE_COMMENT)) {
                                     @if(issue.isVotedBy(UserApp.currentUser())) {
                                         <a href="@routes.VoteApp.unvote(project.owner, project.name, issue.getNumber)" data-request-method="post" class="ybtn ybtn-success"  data-toggle="tooltip" data-placement="right" data-original-title="@Messages("issue.unvote.description")">+@issue.voters.size</a>
@@ -222,7 +239,6 @@
 
             @if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.WATCH)) {
             <button id="watch-button" type="button" class="ybtn" data-toggle="button" data-watching="@if(issue.getWatchers.contains(UserApp.currentUser())){true}else{false}">
-
                 @if(issue.getWatchers.contains(UserApp.currentUser())) {
                     @Messages("project.unwatch")
                 } else {
public/javascripts/common/yobi.ui.Select2.js
--- public/javascripts/common/yobi.ui.Select2.js
+++ public/javascripts/common/yobi.ui.Select2.js
@@ -70,7 +70,7 @@
                 sMilestoneState = sMilestoneState.toLowerCase();
                 var sMilestoneStateLabel = Messages("milestone.state." + sMilestoneState);
                 var sTplMilestoneItem = $("#tplSElect2FormatMilestone").text()
-                                    || '<div title="${name}"><span class="label milestone-state ${state}">${stateLabel}</span> ${name}</div>';
+                                    || '<div title="[${stateLabel}] ${name}">${name}</div>';
 
                 var sText = $yobi.tmpl(sTplMilestoneItem, {
                     "name" : oItem.text.trim(),
Add a comment
List