From: James Moger Date: Mon, 28 Apr 2014 15:08:50 +0000 (-0400) Subject: Overdue labeling, notify changed tickets control X-Git-Tag: v1.6.0~99^2~1 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=667163976e4e51fc3ebf191525e44d97c8a724dc;p=gitblit.git Overdue labeling, notify changed tickets control --- diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index cce805ed..3261ca96 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -651,11 +651,12 @@ public abstract class ITicketService { * @param oldName * @param newName * @param createdBy - * @param send ticket notifications + * @param notifyOpenTickets * @return true if successful * @since 1.6.0 */ - public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy, boolean notify) { + public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, + String newName, String createdBy, boolean notifyOpenTickets) { if (StringUtils.isEmpty(newName)) { throw new IllegalArgumentException("new milestone can not be empty!"); } @@ -680,11 +681,11 @@ public abstract class ITicketService { Change change = new Change(createdBy); change.setField(Field.milestone, newName); TicketModel ticket = updateTicket(repository, qr.number, change); - if (notify && ticket.isOpen()) { + if (notifyOpenTickets && ticket.isOpen()) { notifier.queueMailing(ticket); } } - if (notify) { + if (notifyOpenTickets) { notifier.sendAll(); } @@ -709,6 +710,21 @@ public abstract class ITicketService { * @since 1.4.0 */ public synchronized boolean deleteMilestone(RepositoryModel repository, String milestone, String createdBy) { + return deleteMilestone(repository, milestone, createdBy, true); + } + + /** + * Deletes a milestone. + * + * @param repository + * @param milestone + * @param createdBy + * @param notifyOpenTickets + * @return true if successful + * @since 1.6.0 + */ + public synchronized boolean deleteMilestone(RepositoryModel repository, String milestone, + String createdBy, boolean notifyOpenTickets) { if (StringUtils.isEmpty(milestone)) { throw new IllegalArgumentException("milestone can not be empty!"); } @@ -722,14 +738,18 @@ public abstract class ITicketService { milestonesCache.remove(repository.name); + TicketNotifier notifier = createNotifier(); for (QueryResult qr : tm.tickets) { - if (qr.isOpen()) { - // reset the milestone only for open tickets - Change change = new Change(createdBy); - change.setField(Field.milestone, ""); - TicketModel ticket = updateTicket(repository, qr.number, change); + Change change = new Change(createdBy); + change.setField(Field.milestone, ""); + TicketModel ticket = updateTicket(repository, qr.number, change); + if (notifyOpenTickets && ticket.isOpen()) { + notifier.queueMailing(ticket); } } + if (notifyOpenTickets) { + notifier.sendAll(); + } return true; } catch (IOException e) { log.error("failed to delete milestone " + milestone + " in " + repository, e); diff --git a/src/main/java/com/gitblit/tickets/TicketMilestone.java b/src/main/java/com/gitblit/tickets/TicketMilestone.java index 680615a9..dacedda6 100644 --- a/src/main/java/com/gitblit/tickets/TicketMilestone.java +++ b/src/main/java/com/gitblit/tickets/TicketMilestone.java @@ -37,7 +37,15 @@ public class TicketMilestone extends TicketLabel { super(name); status = Status.Open; } - + + public boolean isOpen() { + return status == Status.Open; + } + + public boolean isOverdue() { + return due == null ? false : System.currentTimeMillis() > due.getTime(); + } + public void setDue(Date due) { this.due = due; } diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index ce4c0b22..e66e53a7 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -673,4 +673,6 @@ gb.mergeToDescription = default integration branch for merging ticket patchsets gb.anonymousCanNotPropose = Anonymous users can not propose patchsets. gb.youDoNotHaveClonePermission = You are not permitted to clone this repository. gb.newMilestone = new milestone -gb.editMilestone = edit milestone \ No newline at end of file +gb.editMilestone = edit milestone +gb.notifyChangedOpenTickets = send notification for changed open tickets +gb.overdue = overdue \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html index 31f76f1c..0897ebee 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html @@ -19,8 +19,9 @@ - + +
 
*
diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java index 967d8f35..b844442a 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -24,7 +24,9 @@ import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; @@ -102,6 +104,8 @@ public class EditMilestonePage extends RepositoryPage { form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + form.add(new Label("dueFormat", "yyyy-MM-dd")); + form.add(new CheckBox("notify", notificationModel)); List statusChoices = Arrays.asList(Status.Open, Status.Closed); form.add(new DropDownChoice("status", statusModel, statusChoices)); @@ -160,8 +164,9 @@ public class EditMilestonePage extends RepositoryPage { public void onSubmit() { UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; + boolean notify = notificationModel.getObject(); - if (app().tickets().deleteMilestone(getRepositoryModel(), oldName, createdBy)) { + if (app().tickets().deleteMilestone(getRepositoryModel(), oldName, createdBy, notify)) { setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } else { // TODO error processing diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html index 1b7e11ae..2ba5d5cc 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html @@ -19,7 +19,7 @@ - +
 
diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java index d6e34cb0..a9f76d3a 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -22,6 +22,7 @@ import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; @@ -78,6 +79,7 @@ public class NewMilestonePage extends RepositoryPage { form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + form.add(new Label("dueFormat", "yyyy-MM-dd")); form.add(new AjaxButton("create") { @@ -87,6 +89,13 @@ public class NewMilestonePage extends RepositoryPage { protected void onSubmit(AjaxRequestTarget target, Form form) { String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { + // invalid name + return; + } + + TicketMilestone milestone = app().tickets().getMilestone(getRepositoryModel(), name); + if (milestone != null) { + // milestone already exists return; } @@ -95,7 +104,7 @@ public class NewMilestonePage extends RepositoryPage { UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; - TicketMilestone milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); + milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); if (milestone != null) { milestone.due = due; app().tickets().updateMilestone(getRepositoryModel(), milestone, createdBy); diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index 984b3754..b7e392a2 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -20,6 +20,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -657,9 +658,20 @@ public class TicketsPage extends TicketBasePage { } else { add(new Label("newMilestone").setVisible(false)); } - + // milestones list - List allMilestones = app().tickets().getMilestones(repositoryModel); + List allMilestones = new ArrayList(app().tickets().getMilestones(repositoryModel)); + Collections.sort(allMilestones, new Comparator() { + @Override + public int compare(TicketMilestone o1, TicketMilestone o2) { + if (o2.isOpen() && !o1.isOpen()) { + return 1; + } else if (o1.isOpen() && !o2.isOpen()) { + return -1; + } + return o2.due.compareTo(o1.due); + } + }); ListDataProvider allMilestonesDp = new ListDataProvider(allMilestones); DataView milestonesList = new DataView("milestoneList", allMilestonesDp) { private static final long serialVersionUID = 1L; @@ -671,15 +683,21 @@ public class TicketsPage extends TicketBasePage { item.add(new LinkPanel("milestoneName", null, tm.name, TicketsPage.class, params).setRenderBodyOnly(true)); String css; + String status = tm.status.name(); switch (tm.status) { case Open: - css = "aui-lozenge aui-lozenge-subtle"; + if (tm.isOverdue()) { + css = "aui-lozenge aui-lozenge-subtle aui-lozenge-error"; + status = "overdue"; + } else { + css = "aui-lozenge aui-lozenge-subtle"; + } break; default: css = "aui-lozenge"; break; } - Label stateLabel = new Label("milestoneState", tm.status.name()); + Label stateLabel = new Label("milestoneState", status); WicketUtils.setCssClass(stateLabel, css); item.add(stateLabel);