Overdue labeling, notify changed tickets control
| | |
| | | * @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!"); |
| | | } |
| | |
| | | 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(); |
| | | } |
| | | |
| | |
| | | * @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!"); |
| | | } |
| | |
| | | |
| | | 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); |
| | | 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); |
| | |
| | | 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; |
| | | } |
| | |
| | | gb.youDoNotHaveClonePermission = You are not permitted to clone this repository. |
| | | gb.newMilestone = new milestone |
| | | gb.editMilestone = edit milestone |
| | | gb.notifyChangedOpenTickets = send notification for changed open tickets |
| | | gb.overdue = overdue |
| | |
| | | <!-- Edit Milestone Table -->
|
| | | <table class="ticket">
|
| | | <tr><th><wicket:message key="gb.milestone"></wicket:message></th><td class="edit"><input class="input-large" type="text" wicket:id="name" id="name"></input></td></tr>
|
| | | <tr><th><wicket:message key="gb.due"></wicket:message></th><td class="edit"><input class="input-large" type="text" wicket:id="due"></input></td></tr>
|
| | | <tr><th><wicket:message key="gb.due"></wicket:message></th><td class="edit"><input class="input-large" type="text" wicket:id="due"></input> <span class="help-inline" wicket:id="dueFormat"></span></td></tr>
|
| | | <tr><th><wicket:message key="gb.status"></wicket:message><span style="color:red;">*</span></th><td class="edit"><select class="input-large" wicket:id="status"></select></td></tr>
|
| | | <tr><th></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="notify" /> <span class="help-inline"><wicket:message key="gb.notifyChangedOpenTickets"></wicket:message></span></label></td></tr>
|
| | | </table>
|
| | | </div>
|
| | | </div>
|
| | |
| | | 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;
|
| | |
| | |
|
| | | form.add(new TextField<String>("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<Status> statusChoices = Arrays.asList(Status.Open, Status.Closed);
|
| | | form.add(new DropDownChoice<TicketModel.Status>("status", statusModel, statusChoices));
|
| | |
| | | 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
|
| | |
| | | <!-- New Milestone Table -->
|
| | | <table class="ticket">
|
| | | <tr><th><wicket:message key="gb.milestone"></wicket:message></th><td class="edit"><input class="input-large" type="text" wicket:id="name" id="name"></input></td></tr>
|
| | | <tr><th><wicket:message key="gb.due"></wicket:message></th><td class="edit"><input class="input-large" type="text" wicket:id="due"></input></td></tr>
|
| | | <tr><th><wicket:message key="gb.due"></wicket:message></th><td class="edit"><input class="input-large" type="text" wicket:id="due"></input> <span class="help-inline" wicket:id="dueFormat"></span></td></tr>
|
| | | </table>
|
| | | </div>
|
| | | </div>
|
| | |
| | | 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;
|
| | |
| | |
|
| | | form.add(new TextField<String>("name", nameModel));
|
| | | form.add(new DateTextField("due", dueModel, "yyyy-MM-dd"));
|
| | | form.add(new Label("dueFormat", "yyyy-MM-dd"));
|
| | |
|
| | | form.add(new AjaxButton("create") {
|
| | |
|
| | |
| | | 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;
|
| | | }
|
| | |
|
| | |
| | | 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);
|
| | |
| | | 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;
|
| | |
| | | }
|
| | |
|
| | | // milestones list
|
| | | List<TicketMilestone> allMilestones = app().tickets().getMilestones(repositoryModel);
|
| | | List<TicketMilestone> allMilestones = new ArrayList<TicketMilestone>(app().tickets().getMilestones(repositoryModel));
|
| | | Collections.sort(allMilestones, new Comparator<TicketMilestone>() {
|
| | | @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<TicketMilestone> allMilestonesDp = new ListDataProvider<TicketMilestone>(allMilestones);
|
| | | DataView<TicketMilestone> milestonesList = new DataView<TicketMilestone>("milestoneList", allMilestonesDp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
| | | 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:
|
| | | 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);
|
| | |
|