From ce048e750f7ae986dddfc8ab9b57750114d2b7b9 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 25 Apr 2014 23:52:30 -0400 Subject: Create and update milestone pages with rename support --- .../java/com/gitblit/tickets/ITicketService.java | 31 +++- src/main/java/com/gitblit/tickets/TicketLabel.java | 7 +- .../java/com/gitblit/tickets/TicketMilestone.java | 4 + .../java/com/gitblit/wicket/GitBlitWebApp.java | 4 + .../com/gitblit/wicket/GitBlitWebApp.properties | 4 +- .../gitblit/wicket/pages/EditMilestonePage.html | 38 +++++ .../gitblit/wicket/pages/EditMilestonePage.java | 166 +++++++++++++++++++++ .../com/gitblit/wicket/pages/NewMilestonePage.html | 37 +++++ .../com/gitblit/wicket/pages/NewMilestonePage.java | 123 +++++++++++++++ .../java/com/gitblit/wicket/pages/TicketsPage.html | 5 +- .../java/com/gitblit/wicket/pages/TicketsPage.java | 21 ++- 11 files changed, 430 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java create mode 100644 src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index c2f3283e..e1a377a6 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -49,6 +49,7 @@ import com.gitblit.models.TicketModel.Field; import com.gitblit.models.TicketModel.Patchset; import com.gitblit.models.TicketModel.Status; import com.gitblit.tickets.TicketIndexer.Lucene; +import com.gitblit.utils.DeepCopier; import com.gitblit.utils.DiffUtils; import com.gitblit.utils.DiffUtils.DiffStat; import com.gitblit.utils.StringUtils; @@ -556,9 +557,10 @@ public abstract class ITicketService { public TicketMilestone getMilestone(RepositoryModel repository, String milestone) { for (TicketMilestone ms : getMilestones(repository)) { if (ms.name.equalsIgnoreCase(milestone)) { + TicketMilestone tm = DeepCopier.copy(ms); String q = QueryBuilder.q(Lucene.rid.matches(repository.getRID())).and(Lucene.milestone.matches(milestone)).build(); - ms.tickets = indexer.queryFor(q, 1, 0, Lucene.number.name(), true); - return ms; + tm.tickets = indexer.queryFor(q, 1, 0, Lucene.number.name(), true); + return tm; } } return null; @@ -639,6 +641,21 @@ public abstract class ITicketService { * @since 1.4.0 */ public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy) { + return renameMilestone(repository, oldName, newName, createdBy, true); + } + + /** + * Renames a milestone. + * + * @param repository + * @param oldName + * @param newName + * @param createdBy + * @param send ticket notifications + * @return true if successful + * @since 1.6.0 + */ + public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy, boolean notify) { if (StringUtils.isEmpty(newName)) { throw new IllegalArgumentException("new milestone can not be empty!"); } @@ -651,7 +668,7 @@ public abstract class ITicketService { config.setString(MILESTONE, newName, STATUS, milestone.status.name()); config.setString(MILESTONE, newName, COLOR, milestone.color); if (milestone.due != null) { - config.setString(MILESTONE, milestone.name, DUE, + config.setString(MILESTONE, newName, DUE, new SimpleDateFormat(DUE_DATE_PATTERN).format(milestone.due)); } config.save(); @@ -663,9 +680,13 @@ public abstract class ITicketService { Change change = new Change(createdBy); change.setField(Field.milestone, newName); TicketModel ticket = updateTicket(repository, qr.number, change); - notifier.queueMailing(ticket); + if (notify && ticket.isOpen()) { + notifier.queueMailing(ticket); + } + } + if (notify) { + notifier.sendAll(); } - notifier.sendAll(); return true; } catch (IOException e) { diff --git a/src/main/java/com/gitblit/tickets/TicketLabel.java b/src/main/java/com/gitblit/tickets/TicketLabel.java index 686ce88b..a7f0ebec 100644 --- a/src/main/java/com/gitblit/tickets/TicketLabel.java +++ b/src/main/java/com/gitblit/tickets/TicketLabel.java @@ -30,14 +30,17 @@ public class TicketLabel implements Serializable { private static final long serialVersionUID = 1L; - public final String name; + public String name; public String color; public List tickets; - public TicketLabel(String name) { + setName(name); + } + + public void setName(String name) { this.name = name; this.color = StringUtils.getColor(name); } diff --git a/src/main/java/com/gitblit/tickets/TicketMilestone.java b/src/main/java/com/gitblit/tickets/TicketMilestone.java index c6b4fcca..680615a9 100644 --- a/src/main/java/com/gitblit/tickets/TicketMilestone.java +++ b/src/main/java/com/gitblit/tickets/TicketMilestone.java @@ -37,6 +37,10 @@ public class TicketMilestone extends TicketLabel { super(name); status = Status.Open; } + + public void setDue(Date due) { + this.due = due; + } public int getProgress() { int total = getTotalTickets(); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index c4fdeda5..d4c1bc40 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -51,6 +51,7 @@ import com.gitblit.wicket.pages.CommitPage; import com.gitblit.wicket.pages.ComparePage; import com.gitblit.wicket.pages.DocPage; import com.gitblit.wicket.pages.DocsPage; +import com.gitblit.wicket.pages.EditMilestonePage; import com.gitblit.wicket.pages.EditTicketPage; import com.gitblit.wicket.pages.ExportTicketPage; import com.gitblit.wicket.pages.FederationRegistrationPage; @@ -63,6 +64,7 @@ import com.gitblit.wicket.pages.LogoutPage; import com.gitblit.wicket.pages.LuceneSearchPage; import com.gitblit.wicket.pages.MetricsPage; import com.gitblit.wicket.pages.MyDashboardPage; +import com.gitblit.wicket.pages.NewMilestonePage; import com.gitblit.wicket.pages.NewTicketPage; import com.gitblit.wicket.pages.OverviewPage; import com.gitblit.wicket.pages.PatchPage; @@ -187,6 +189,8 @@ public class GitBlitWebApp extends WebApplication { mount("/tickets/new", NewTicketPage.class, "r"); mount("/tickets/edit", EditTicketPage.class, "r", "h"); mount("/tickets/export", ExportTicketPage.class, "r", "h"); + mount("/milestones/new", NewMilestonePage.class, "r"); + mount("/milestones/edit", EditMilestonePage.class, "r", "h"); // setup the markup document urls mount("/docs", DocsPage.class, "r"); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index aeb2d9ef..ce4c0b22 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -671,4 +671,6 @@ gb.serverDoesNotAcceptPatchsets = This server does not accept patchsets. gb.ticketIsClosed = This ticket is closed. 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. \ No newline at end of file +gb.youDoNotHaveClonePermission = You are not permitted to clone this repository. +gb.newMilestone = new milestone +gb.editMilestone = edit milestone \ 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 new file mode 100644 index 00000000..66b47848 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html @@ -0,0 +1,38 @@ + + + + + + +
+ +
+ +
+ +
+
+
+ + + + + +
*
+
+
+ +
+
+
 
+
+
+
+
+ + +
+ \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java new file mode 100644 index 00000000..44077884 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -0,0 +1,166 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.RestartResponseException; +import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.parboiled.common.StringUtils; + +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.TicketModel; +import com.gitblit.models.TicketModel.Status; +import com.gitblit.models.UserModel; +import com.gitblit.tickets.TicketMilestone; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; + +/** + * Page for creating a new milestone. + * + * @author James Moger + * + */ +public class EditMilestonePage extends RepositoryPage { + + private final String oldName; + + private IModel nameModel; + + private IModel dueModel; + + private IModel statusModel; + + private IModel notificationModel; + + public EditMilestonePage(PageParameters params) { + super(params); + + RepositoryModel model = getRepositoryModel(); + if (!app().tickets().isAcceptingTicketUpdates(model)) { + // ticket service is read-only + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + UserModel currentUser = GitBlitWebSession.get().getUser(); + if (currentUser == null) { + currentUser = UserModel.ANONYMOUS; + } + + if (!currentUser.isAuthenticated || !currentUser.canAdmin(model)) { + // administration prohibited + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + oldName = WicketUtils.getObject(params); + if (StringUtils.isEmpty(oldName)) { + // milestone not specified + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); + if (tm == null) { + // milestone does not exist + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + setStatelessHint(false); + setOutputMarkupId(true); + + Form form = new Form("editForm") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit() { + + String name = nameModel.getObject(); + if (StringUtils.isEmpty(name)) { + return; + } + + Date due = dueModel.getObject(); + Status status = statusModel.getObject(); + boolean rename = !name.equals(oldName); + boolean notify = notificationModel.getObject(); + + UserModel currentUser = GitBlitWebSession.get().getUser(); + String createdBy = currentUser.username; + + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); + tm.setName(name); + tm.setDue(due); + tm.status = status; + + boolean success = true; + if (rename) { + success = app().tickets().renameMilestone(getRepositoryModel(), oldName, name, createdBy, notify); + } + + if (success && app().tickets().updateMilestone(getRepositoryModel(), tm, createdBy)) { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(getRepositoryModel().name)); + } else { + // TODO error + } + } + }; + add(form); + + nameModel = Model.of(tm.name); + dueModel = Model.of(tm.due); + statusModel = Model.of(tm.status); + notificationModel = Model.of(true); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + List statusChoices = Arrays.asList(Status.Open, Status.Closed); + form.add(new DropDownChoice("status", statusModel, statusChoices)); + + form.add(new Button("save")); + Button cancel = new Button("cancel") { + private static final long serialVersionUID = 1L; + + @Override + public void onSubmit() { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + }; + cancel.setDefaultFormProcessing(false); + form.add(cancel); + + } + + @Override + protected String getPageName() { + return getString("gb.editMilestone"); + } + + @Override + protected Class getRepoNavPageClass() { + return TicketsPage.class; + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html new file mode 100644 index 00000000..1b7e11ae --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html @@ -0,0 +1,37 @@ + + + + + + +
+ +
+ +
+ +
+
+
+ + + + +
+
+
+ +
+
+
 
+
+
+
+
+ + +
+ \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java new file mode 100644 index 00000000..2c95f018 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -0,0 +1,123 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.util.Date; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.RestartResponseException; +import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; + +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.tickets.TicketMilestone; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; + +/** + * Page for creating a new milestone. + * + * @author James Moger + * + */ +public class NewMilestonePage extends RepositoryPage { + + private IModel nameModel; + + private IModel dueModel; + + public NewMilestonePage(PageParameters params) { + super(params); + + RepositoryModel model = getRepositoryModel(); + if (!app().tickets().isAcceptingTicketUpdates(model)) { + // ticket service is read-only + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + UserModel currentUser = GitBlitWebSession.get().getUser(); + if (currentUser == null) { + currentUser = UserModel.ANONYMOUS; + } + + if (!currentUser.isAuthenticated || !currentUser.canAdmin(model)) { + // administration prohibited + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + setStatelessHint(false); + setOutputMarkupId(true); + + Form form = new Form("editForm") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit() { + + String name = nameModel.getObject(); + Date due = dueModel.getObject(); + + UserModel currentUser = GitBlitWebSession.get().getUser(); + String createdBy = currentUser.username; + + TicketMilestone milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); + if (milestone != null) { + milestone.due = due; + app().tickets().updateMilestone(getRepositoryModel(), milestone, createdBy); + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(getRepositoryModel().name)); + } else { + // TODO error + } + } + }; + add(form); + + nameModel = Model.of(""); + dueModel = Model.of(new Date()); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + form.add(new Button("create")); + Button cancel = new Button("cancel") { + private static final long serialVersionUID = 1L; + + @Override + public void onSubmit() { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + }; + cancel.setDefaultFormProcessing(false); + form.add(cancel); + + } + + @Override + protected String getPageName() { + return getString("gb.newMilestone"); + } + + @Override + protected Class getRepoNavPageClass() { + return TicketsPage.class; + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html index 7d13852b..e144bea1 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html @@ -138,10 +138,13 @@
+
+ +

- +
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index ca509e28..984b3754 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -42,6 +42,7 @@ import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Keys; import com.gitblit.models.RegistrantAccessPermission; +import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; import com.gitblit.models.TicketModel.Status; import com.gitblit.models.UserModel; @@ -646,7 +647,19 @@ public class TicketsPage extends TicketBasePage { }; add(ticketsView); - List allMilestones = app().tickets().getMilestones(getRepositoryModel()); + // new milestone link + RepositoryModel repositoryModel = getRepositoryModel(); + final boolean acceptingUpdates = app().tickets().isAcceptingTicketUpdates(repositoryModel) + && user != null && user.canAdmin(getRepositoryModel()); + if (acceptingUpdates) { + add(new LinkPanel("newMilestone", null, getString("gb.newMilestone"), + NewMilestonePage.class, WicketUtils.newRepositoryParameter(repositoryName))); + } else { + add(new Label("newMilestone").setVisible(false)); + } + + // milestones list + List allMilestones = app().tickets().getMilestones(repositoryModel); ListDataProvider allMilestonesDp = new ListDataProvider(allMilestones); DataView milestonesList = new DataView("milestoneList", allMilestonesDp) { private static final long serialVersionUID = 1L; @@ -675,6 +688,12 @@ public class TicketsPage extends TicketBasePage { } else { item.add(WicketUtils.createDatestampLabel("milestoneDue", tm.due, getTimeZone(), getTimeUtils())); } + if (acceptingUpdates) { + item.add(new LinkPanel("editMilestone", null, getString("gb.edit"), EditMilestonePage.class, + WicketUtils.newObjectParameter(repositoryName, tm.name))); + } else { + item.add(new Label("editMilestone").setVisible(false)); + } } }; add(milestonesList); -- cgit v1.2.3 From 01995873731e7efa517ca66246547b3084f8d529 Mon Sep 17 00:00:00 2001 From: James Moger Date: Sat, 26 Apr 2014 13:51:39 -0400 Subject: Allow milestone deletion within the edit milestone page --- .../java/com/gitblit/tickets/ITicketService.java | 11 +++++- src/main/java/com/gitblit/tickets/QueryResult.java | 8 ++++ .../gitblit/wicket/pages/EditMilestonePage.html | 2 +- .../gitblit/wicket/pages/EditMilestonePage.java | 45 +++++++++++++++------- .../com/gitblit/wicket/pages/NewMilestonePage.java | 18 ++++++--- 5 files changed, 62 insertions(+), 22 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index e1a377a6..cce805ed 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -643,7 +643,7 @@ public abstract class ITicketService { public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy) { return renameMilestone(repository, oldName, newName, createdBy, true); } - + /** * Renames a milestone. * @@ -714,6 +714,7 @@ public abstract class ITicketService { } Repository db = null; try { + TicketMilestone tm = getMilestone(repository, milestone); db = repositoryManager.getRepository(repository.name); StoredConfig config = db.getConfig(); config.unsetSection(MILESTONE, milestone); @@ -721,6 +722,14 @@ public abstract class ITicketService { milestonesCache.remove(repository.name); + 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); + } + } return true; } catch (IOException e) { log.error("failed to delete milestone " + milestone + " in " + repository, e); diff --git a/src/main/java/com/gitblit/tickets/QueryResult.java b/src/main/java/com/gitblit/tickets/QueryResult.java index 9f5d3a55..7a2b1abe 100644 --- a/src/main/java/com/gitblit/tickets/QueryResult.java +++ b/src/main/java/com/gitblit/tickets/QueryResult.java @@ -74,6 +74,14 @@ public class QueryResult implements Serializable { return type != null && Type.Proposal == type; } + public boolean isOpen() { + return !status.isClosed(); + } + + public boolean isClosed() { + return status.isClosed(); + } + public boolean isMerged() { return Status.Merged == status && !StringUtils.isEmpty(mergeSha); } diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html index 66b47848..31f76f1c 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html @@ -27,7 +27,7 @@
-
 
+
   
diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java index 44077884..b92ba8ba 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -28,13 +28,13 @@ import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; -import org.parboiled.common.StringUtils; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; import com.gitblit.models.TicketModel.Status; import com.gitblit.models.UserModel; import com.gitblit.tickets.TicketMilestone; +import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; @@ -47,13 +47,13 @@ import com.gitblit.wicket.WicketUtils; public class EditMilestonePage extends RepositoryPage { private final String oldName; - + private IModel nameModel; private IModel dueModel; - + private IModel statusModel; - + private IModel notificationModel; public EditMilestonePage(PageParameters params) { @@ -64,7 +64,7 @@ public class EditMilestonePage extends RepositoryPage { // ticket service is read-only throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { currentUser = UserModel.ANONYMOUS; @@ -74,13 +74,13 @@ public class EditMilestonePage extends RepositoryPage { // administration prohibited throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + oldName = WicketUtils.getObject(params); if (StringUtils.isEmpty(oldName)) { // milestone not specified throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); if (tm == null) { // milestone does not exist @@ -96,30 +96,30 @@ public class EditMilestonePage extends RepositoryPage { @Override protected void onSubmit() { - + String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { return; } - + Date due = dueModel.getObject(); Status status = statusModel.getObject(); boolean rename = !name.equals(oldName); boolean notify = notificationModel.getObject(); - + UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; - + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); tm.setName(name); tm.setDue(due); tm.status = status; - + boolean success = true; if (rename) { success = app().tickets().renameMilestone(getRepositoryModel(), oldName, name, createdBy, notify); } - + if (success && app().tickets().updateMilestone(getRepositoryModel(), tm, createdBy)) { setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(getRepositoryModel().name)); } else { @@ -133,7 +133,7 @@ public class EditMilestonePage extends RepositoryPage { dueModel = Model.of(tm.due); statusModel = Model.of(tm.status); notificationModel = Model.of(true); - + form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); @@ -152,6 +152,23 @@ public class EditMilestonePage extends RepositoryPage { cancel.setDefaultFormProcessing(false); form.add(cancel); + Button delete = new Button("delete") { + private static final long serialVersionUID = 1L; + + @Override + public void onSubmit() { + UserModel currentUser = GitBlitWebSession.get().getUser(); + String createdBy = currentUser.username; + + if (app().tickets().deleteMilestone(getRepositoryModel(), oldName, createdBy)) { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } else { + // TODO error processing + } + } + }; + delete.setDefaultFormProcessing(false); + form.add(delete); } @Override diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java index 2c95f018..4c393786 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -29,6 +29,8 @@ import org.apache.wicket.model.Model; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.tickets.TicketMilestone; +import com.gitblit.utils.StringUtils; +import com.gitblit.utils.TimeUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; @@ -43,7 +45,7 @@ public class NewMilestonePage extends RepositoryPage { private IModel nameModel; private IModel dueModel; - + public NewMilestonePage(PageParameters params) { super(params); @@ -52,7 +54,7 @@ public class NewMilestonePage extends RepositoryPage { // ticket service is read-only throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { currentUser = UserModel.ANONYMOUS; @@ -72,13 +74,17 @@ public class NewMilestonePage extends RepositoryPage { @Override protected void onSubmit() { - + String name = nameModel.getObject(); + if (StringUtils.isEmpty(name)) { + return; + } + Date due = dueModel.getObject(); UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; - + TicketMilestone milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); if (milestone != null) { milestone.due = due; @@ -92,8 +98,8 @@ public class NewMilestonePage extends RepositoryPage { add(form); nameModel = Model.of(""); - dueModel = Model.of(new Date()); - + dueModel = Model.of(new Date(System.currentTimeMillis() + TimeUtils.ONEDAY)); + form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); -- cgit v1.2.3 From 6209dc4fd442887e18e3dd6fe7056f4b842091c2 Mon Sep 17 00:00:00 2001 From: James Moger Date: Sun, 27 Apr 2014 19:49:33 -0400 Subject: Use ajax buttons in the New|Edit Milestone pages --- .../gitblit/wicket/pages/EditMilestonePage.java | 37 +++++++++++----------- .../com/gitblit/wicket/pages/NewMilestonePage.java | 26 ++++++++------- 2 files changed, 33 insertions(+), 30 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java index b92ba8ba..967d8f35 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -21,6 +21,8 @@ import java.util.List; import org.apache.wicket.PageParameters; 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.form.Button; import org.apache.wicket.markup.html.form.DropDownChoice; @@ -90,13 +92,26 @@ public class EditMilestonePage extends RepositoryPage { setStatelessHint(false); setOutputMarkupId(true); - Form form = new Form("editForm") { + Form form = new Form("editForm"); + add(form); + + nameModel = Model.of(tm.name); + dueModel = Model.of(tm.due); + statusModel = Model.of(tm.status); + notificationModel = Model.of(true); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + List statusChoices = Arrays.asList(Status.Open, Status.Closed); + form.add(new DropDownChoice("status", statusModel, statusChoices)); + + form.add(new AjaxButton("save") { private static final long serialVersionUID = 1L; @Override - protected void onSubmit() { - + protected void onSubmit(AjaxRequestTarget target, Form form) { String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { return; @@ -126,21 +141,7 @@ public class EditMilestonePage extends RepositoryPage { // TODO error } } - }; - add(form); - - nameModel = Model.of(tm.name); - dueModel = Model.of(tm.due); - statusModel = Model.of(tm.status); - notificationModel = Model.of(true); - - form.add(new TextField("name", nameModel)); - form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); - - List statusChoices = Arrays.asList(Status.Open, Status.Closed); - form.add(new DropDownChoice("status", statusModel, statusChoices)); - - form.add(new Button("save")); + }); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java index 4c393786..d6e34cb0 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -19,6 +19,8 @@ import java.util.Date; import org.apache.wicket.PageParameters; 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.form.Button; import org.apache.wicket.markup.html.form.Form; @@ -68,13 +70,21 @@ public class NewMilestonePage extends RepositoryPage { setStatelessHint(false); setOutputMarkupId(true); - Form form = new Form("editForm") { + Form form = new Form("editForm"); + add(form); + + nameModel = Model.of(""); + dueModel = Model.of(new Date(System.currentTimeMillis() + TimeUtils.ONEDAY)); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + form.add(new AjaxButton("create") { private static final long serialVersionUID = 1L; @Override - protected void onSubmit() { - + protected void onSubmit(AjaxRequestTarget target, Form form) { String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { return; @@ -94,16 +104,8 @@ public class NewMilestonePage extends RepositoryPage { // TODO error } } - }; - add(form); - - nameModel = Model.of(""); - dueModel = Model.of(new Date(System.currentTimeMillis() + TimeUtils.ONEDAY)); - - form.add(new TextField("name", nameModel)); - form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + }); - form.add(new Button("create")); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; -- cgit v1.2.3 From 667163976e4e51fc3ebf191525e44d97c8a724dc Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 28 Apr 2014 11:08:50 -0400 Subject: Overdue labeling, notify changed tickets control --- .../java/com/gitblit/tickets/ITicketService.java | 38 +++++++++++++++++----- .../java/com/gitblit/tickets/TicketMilestone.java | 10 +++++- .../com/gitblit/wicket/GitBlitWebApp.properties | 4 ++- .../gitblit/wicket/pages/EditMilestonePage.html | 3 +- .../gitblit/wicket/pages/EditMilestonePage.java | 7 +++- .../com/gitblit/wicket/pages/NewMilestonePage.html | 2 +- .../com/gitblit/wicket/pages/NewMilestonePage.java | 11 ++++++- .../java/com/gitblit/wicket/pages/TicketsPage.java | 26 ++++++++++++--- 8 files changed, 82 insertions(+), 19 deletions(-) (limited to 'src/main/java') 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); -- cgit v1.2.3 From 8d2caa7e81fcd995f0a5c07fa4454ae2f8e86e6e Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 30 Apr 2014 17:15:31 -0400 Subject: Show open milestone progress and change milestones list layout --- .../com/gitblit/wicket/GitBlitWebApp.properties | 4 +- .../java/com/gitblit/wicket/pages/TicketsPage.html | 40 ++++++++++- .../java/com/gitblit/wicket/pages/TicketsPage.java | 81 +++++++++++++++++----- 3 files changed, 104 insertions(+), 21 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index e66e53a7..1394890f 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -675,4 +675,6 @@ 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 \ No newline at end of file +gb.overdue = overdue +gb.openMilestones = open milestones +gb.closedMilestones = closed milestones \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html index e144bea1..a40d3126 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html @@ -141,15 +141,49 @@
+ +
+

+

+
+
+
+
+
+
+
-
-

- +

+

+
+
+
+
+
+ +

+ +
+
+ + +
+
+
+
+
+ , + , + +
+
+
+ diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index b7e392a2..5973d473 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -660,27 +660,49 @@ public class TicketsPage extends TicketBasePage { } // milestones list - List allMilestones = new ArrayList(app().tickets().getMilestones(repositoryModel)); - Collections.sort(allMilestones, new Comparator() { + List openMilestones = new ArrayList(); + List closedMilestones = new ArrayList(); + for (TicketMilestone milestone : app().tickets().getMilestones(repositoryModel)) { + if (milestone.isOpen()) { + openMilestones.add(milestone); + } else { + closedMilestones.add(milestone); + } + } + Collections.sort(openMilestones, new Comparator() { + @Override + public int compare(TicketMilestone o1, TicketMilestone o2) { + return o2.due.compareTo(o1.due); + } + }); + + Collections.sort(closedMilestones, 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) { + + DataView openMilestonesList = milestoneList("openMilestonesList", openMilestones, acceptingUpdates); + add(openMilestonesList); + + DataView closedMilestonesList = milestoneList("closedMilestonesList", closedMilestones, acceptingUpdates); + add(closedMilestonesList); + } + + protected DataView milestoneList(String wicketId, List milestones, final boolean acceptingUpdates) { + ListDataProvider milestonesDp = new ListDataProvider(milestones); + DataView milestonesList = new DataView(wicketId, milestonesDp) { private static final long serialVersionUID = 1L; @Override public void populateItem(final Item item) { + Fragment entryPanel = new Fragment("entryPanel", "milestoneListFragment", this); + item.add(entryPanel); + final TicketMilestone tm = item.getModelObject(); - PageParameters params = queryParameters(null, tm.name, null, null, null, desc, 1); - item.add(new LinkPanel("milestoneName", null, tm.name, TicketsPage.class, params).setRenderBodyOnly(true)); + PageParameters params = queryParameters(null, tm.name, null, null, null, true, 1); + entryPanel.add(new LinkPanel("milestoneName", null, tm.name, TicketsPage.class, params).setRenderBodyOnly(true)); String css; String status = tm.status.name(); @@ -699,22 +721,47 @@ public class TicketsPage extends TicketBasePage { } Label stateLabel = new Label("milestoneState", status); WicketUtils.setCssClass(stateLabel, css); - item.add(stateLabel); + entryPanel.add(stateLabel); if (tm.due == null) { - item.add(new Label("milestoneDue", getString("gb.notSpecified"))); + entryPanel.add(new Label("milestoneDue", getString("gb.notSpecified"))); } else { - item.add(WicketUtils.createDatestampLabel("milestoneDue", tm.due, getTimeZone(), getTimeUtils())); + entryPanel.add(WicketUtils.createDatestampLabel("milestoneDue", tm.due, getTimeZone(), getTimeUtils())); } if (acceptingUpdates) { - item.add(new LinkPanel("editMilestone", null, getString("gb.edit"), EditMilestonePage.class, + entryPanel.add(new LinkPanel("editMilestone", null, getString("gb.edit"), EditMilestonePage.class, WicketUtils.newObjectParameter(repositoryName, tm.name))); } else { - item.add(new Label("editMilestone").setVisible(false)); + entryPanel.add(new Label("editMilestone").setVisible(false)); + } + + if (tm.isOpen()) { + // re-load milestone with query results + TicketMilestone m = app().tickets().getMilestone(getRepositoryModel(), tm.name); + + Fragment milestonePanel = new Fragment("milestonePanel", "openMilestoneFragment", this); + Label label = new Label("progress"); + WicketUtils.setCssStyle(label, "width:" + tm.getProgress() + "%;"); + milestonePanel.add(label); + + milestonePanel.add(new LinkPanel("openTickets", null, + MessageFormat.format(getString("gb.nOpenTickets"), m.getOpenTickets()), + TicketsPage.class, + queryParameters(null, tm.name, openStatii, null, null, true, 1))); + + milestonePanel.add(new LinkPanel("closedTickets", null, + MessageFormat.format(getString("gb.nClosedTickets"), m.getClosedTickets()), + TicketsPage.class, + queryParameters(null, tm.name, closedStatii, null, null, true, 1))); + + milestonePanel.add(new Label("totalTickets", MessageFormat.format(getString("gb.nTotalTickets"), m.getTotalTickets()))); + entryPanel.add(milestonePanel); + } else { + entryPanel.add(new Label("milestonePanel").setVisible(false)); } } }; - add(milestonesList); + return milestonesList; } protected PageParameters queryParameters( -- cgit v1.2.3 From 3380373c3123f875f50e48b0290c84dfae0519e4 Mon Sep 17 00:00:00 2001 From: BUISSON Christian Date: Tue, 15 Apr 2014 15:21:33 +0200 Subject: First Step in My Tickets --- .../com/gitblit/tickets/FileTicketService.java | 116 +++++++++++-------- .../java/com/gitblit/tickets/ITicketService.java | 11 +- .../java/com/gitblit/wicket/GitBlitWebApp.java | 2 + .../com/gitblit/wicket/GitBlitWebApp.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_fr.properties | 1 + .../com/gitblit/wicket/pages/MyTicketsPage.html | 50 ++++++++ .../com/gitblit/wicket/pages/MyTicketsPage.java | 128 +++++++++++++++++++++ .../java/com/gitblit/wicket/pages/RootPage.java | 1 + 8 files changed, 262 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/tickets/FileTicketService.java b/src/main/java/com/gitblit/tickets/FileTicketService.java index 4386020f..ea5d065f 100644 --- a/src/main/java/com/gitblit/tickets/FileTicketService.java +++ b/src/main/java/com/gitblit/tickets/FileTicketService.java @@ -207,62 +207,82 @@ public class FileTicketService extends ITicketService { @Override public List getTickets(RepositoryModel repository, TicketFilter filter) { List list = new ArrayList(); - - Repository db = repositoryManager.getRepository(repository.name); - try { - // Collect the set of all json files - File dir = new File(db.getDirectory(), TICKETS_PATH); - List journals = findAll(dir, JOURNAL); - - // Deserialize each ticket and optionally filter out unwanted tickets - for (File journal : journals) { - String json = null; - try { - json = new String(FileUtils.readContent(journal), Constants.ENCODING); - } catch (Exception e) { - log.error(null, e); - } - if (StringUtils.isEmpty(json)) { - // journal was touched but no changes were written - continue; - } - try { - // Reconstruct ticketId from the path - // id/26/326/journal.json - String path = FileUtils.getRelativePath(dir, journal); - String tid = path.split("/")[1]; - long ticketId = Long.parseLong(tid); - List changes = TicketSerializer.deserializeJournal(json); - if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", repository, journal); + List databases = new ArrayList(); + List models = new ArrayList(); + + if(repository == null) + { + List allRepo = repositoryManager.getRepositoryList(); + for(int i = 0; i < allRepo.size(); i++) + { + databases.add(repositoryManager.getRepository(allRepo.get(i))); + models.add(repositoryManager.getRepositoryModel(allRepo.get(i))); + } + } + else + { + databases.add(repositoryManager.getRepository(repository.name)); + models.add(repository); + } + + for(int i = 0; i < databases.size(); i++) + { + Repository db = databases.get(i); + try { + // Collect the set of all json files + File dir = new File(db.getDirectory(), TICKETS_PATH); + List journals = findAll(dir, JOURNAL); + + // Deserialize each ticket and optionally filter out unwanted tickets + for (File journal : journals) { + String json = null; + try { + json = new String(FileUtils.readContent(journal), Constants.ENCODING); + } catch (Exception e) { + log.error(null, e); + } + if (StringUtils.isEmpty(json)) { + // journal was touched but no changes were written continue; } - TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = repository.projectPath; - ticket.repository = repository.name; - ticket.number = ticketId; - - // add the ticket, conditionally, to the list - if (filter == null) { - list.add(ticket); - } else { - if (filter.accept(ticket)) { + try { + // Reconstruct ticketId from the path + // id/26/326/journal.json + String path = FileUtils.getRelativePath(dir, journal); + String tid = path.split("/")[1]; + long ticketId = Long.parseLong(tid); + List changes = TicketSerializer.deserializeJournal(json); + if (ArrayUtils.isEmpty(changes)) { + log.warn("Empty journal for {}:{}", models.get(i), journal); + continue; + } + TicketModel ticket = TicketModel.buildTicket(changes); + ticket.project = models.get(i).projectPath; + ticket.repository = models.get(i).name; + ticket.number = ticketId; + + // add the ticket, conditionally, to the list + if (filter == null) { list.add(ticket); + } else { + if (filter.accept(ticket)) { + list.add(ticket); + } } + } catch (Exception e) { + log.error("failed to deserialize {}/{}\n{}", + new Object [] { models.get(i), journal, e.getMessage()}); + log.error(null, e); } - } catch (Exception e) { - log.error("failed to deserialize {}/{}\n{}", - new Object [] { repository, journal, e.getMessage()}); - log.error(null, e); } + } finally { + db.close(); } - - // sort the tickets by creation - Collections.sort(list); - return list; - } finally { - db.close(); } + + // sort the tickets by creation + Collections.sort(list); + return list; } private List findAll(File dir, String filename) { diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index 3261ca96..e7b4c71d 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -779,12 +779,21 @@ public abstract class ITicketService { * @since 1.4.0 */ public abstract boolean hasTicket(RepositoryModel repository, long ticketId); + + /** + * Returns all tickets. This is not a Lucene search! + * + * @return all tickets + */ + public List getTickets() { + return getTickets(null, null); + } /** * Returns all tickets. This is not a Lucene search! * * @param repository - * @return all tickets + * @return all tickets of a given repository * @since 1.4.0 */ public List getTickets(RepositoryModel repository) { diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index d4c1bc40..9f002d2b 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -81,6 +81,7 @@ import com.gitblit.wicket.pages.TicketsPage; import com.gitblit.wicket.pages.TreePage; import com.gitblit.wicket.pages.UserPage; import com.gitblit.wicket.pages.UsersPage; +import com.gitblit.wicket.pages.MyTicketsPage; public class GitBlitWebApp extends WebApplication { @@ -191,6 +192,7 @@ public class GitBlitWebApp extends WebApplication { mount("/tickets/export", ExportTicketPage.class, "r", "h"); mount("/milestones/new", NewMilestonePage.class, "r"); mount("/milestones/edit", EditMilestonePage.class, "r", "h"); + mount("/mytickets", MyTicketsPage.class, "r", "h"); // setup the markup document urls mount("/docs", DocsPage.class, "r"); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 1394890f..030c5ebe 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -677,4 +677,5 @@ gb.editMilestone = edit milestone gb.notifyChangedOpenTickets = send notification for changed open tickets gb.overdue = overdue gb.openMilestones = open milestones -gb.closedMilestones = closed milestones \ No newline at end of file +gb.closedMilestones = closed milestones +gb.mytickets = my tickets \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties index 8a725cf4..75a3ab7a 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties @@ -670,3 +670,4 @@ gb.repositoryDoesNotAcceptPatchsets = Ce d gb.serverDoesNotAcceptPatchsets = Ce serveur n'accepte pas de patchsets. gb.ticketIsClosed = Ce ticket est clos. gb.mergeToDescription = default integration branch for merging ticket patchsets +gb.mytickets = mes tickets diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html new file mode 100644 index 00000000..bbb2b96b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -0,0 +1,50 @@ + + + + + +
+ Responsible Tickets + + + + + + +
+ + + Author Tickets + + + + + + +
+ + + Voted Tickets + + + + + + +
+ + + Watched Tickets + + + + + + +
+ + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java new file mode 100644 index 00000000..509b00ca --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -0,0 +1,128 @@ +package com.gitblit.wicket.pages; + +import java.util.ArrayList; +import java.util.List; + +import com.gitblit.models.UserModel; +import com.gitblit.models.TicketModel; +import com.gitblit.tickets.ITicketService; +import com.gitblit.wicket.GitBlitWebApp; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.panels.LinkPanel; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.PageParameters; + +public class MyTicketsPage extends RootPage { + + public MyTicketsPage(PageParameters params) + { + this(); + } + + public MyTicketsPage() + { + super(); + setupPage("", ""); + + UserModel currentUser = GitBlitWebSession.get().getUser(); + if (currentUser == null) { + currentUser = UserModel.ANONYMOUS; + } + String username = currentUser.getName(); + + ITicketService tickets = GitBlitWebApp.get().tickets(); + List returnedTickets = tickets.getTickets(null); + + List responsibleTickets = new ArrayList(); + List authorTickets = new ArrayList(); + List votedTickets = new ArrayList(); + List watchedTickets = new ArrayList(); + for(int i = 0; i < returnedTickets.size(); i++) + { + TicketModel ticket = returnedTickets.get(i); + if(ticket.isOpen()) + { + if(ticket.isResponsible(username)) + { + responsibleTickets.add(ticket); + } + if(ticket.isAuthor(username)) + { + authorTickets.add(ticket); + } + if(ticket.isVoter(username)) + { + votedTickets.add(ticket); + } + if(ticket.isWatching(username)) + { + watchedTickets.add(ticket); + } + } + } + + ListView responsibleView = new ListView("responsibleTickets", responsibleTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + ListView authorView = new ListView("authorTickets", authorTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + ListView votedView = new ListView("votedTickets", votedTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + ListView watchedView = new ListView("watchedTickets", watchedTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + add(responsibleView); + add(authorView); + add(votedView); + add(watchedView); + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index 5ccc3a4c..ec413b19 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -173,6 +173,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From 47bfbe3b1da6629655f49b32b917dccb21b83809 Mon Sep 17 00:00:00 2001 From: BUISSON Christian Date: Tue, 15 Apr 2014 15:45:34 +0200 Subject: Deactivate the navbar button for My Tickets (until it is finalized). --- src/main/java/com/gitblit/wicket/pages/RootPage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index ec413b19..f43dc45e 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -173,7 +173,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); + //pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From 556a5853fb7145adc20b2e718eca2e921f3d7399 Mon Sep 17 00:00:00 2001 From: BUISSON Christian Date: Wed, 16 Apr 2014 16:10:51 +0200 Subject: Ajout du nom du repository sur la page "MyTickets". --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 86 ++++++++++++---------- .../com/gitblit/wicket/pages/MyTicketsPage.java | 8 ++ 2 files changed, 55 insertions(+), 39 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index bbb2b96b..5222c35c 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -6,45 +6,53 @@ - - Responsible Tickets - - - - - - -
- - - Author Tickets - - - - - - -
- - - Voted Tickets - - - - - - -
- - - Watched Tickets - - - - - - -
+
+
[my tickets message]
+ + + Responsible Tickets + + + + + + + +
+ + + Author Tickets + + + + + + + +
+ + + Voted Tickets + + + + + + + +
+ + + Watched Tickets + + + + + + + +
+
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 509b00ca..6e656ae4 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -3,6 +3,7 @@ package com.gitblit.wicket.pages; import java.util.ArrayList; import java.util.List; +import com.gitblit.Keys; import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel; import com.gitblit.tickets.ITicketService; @@ -33,6 +34,9 @@ public class MyTicketsPage extends RootPage { } String username = currentUser.getName(); + String message = "Welcome on GitBlit"; + this.add(new Label("myTicketsMessage", message)); + ITicketService tickets = GitBlitWebApp.get().tickets(); List returnedTickets = tickets.getTickets(null); @@ -73,6 +77,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } @@ -87,6 +92,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } @@ -101,6 +107,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } @@ -115,6 +122,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } -- cgit v1.2.3 From 7d19224c99f118351ad15a77942762e74940536f Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Wed, 16 Apr 2014 16:42:18 +0200 Subject: Implementation of the getTickets capability of recovering all tickets from a nullable RepositoryModel --- .../com/gitblit/tickets/BranchTicketService.java | 114 ++++++++++++--------- .../com/gitblit/tickets/FileTicketService.java | 9 +- .../com/gitblit/tickets/RedisTicketService.java | 85 +++++++++------ 3 files changed, 124 insertions(+), 84 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/tickets/BranchTicketService.java b/src/main/java/com/gitblit/tickets/BranchTicketService.java index 284b1be1..7d6926df 100644 --- a/src/main/java/com/gitblit/tickets/BranchTicketService.java +++ b/src/main/java/com/gitblit/tickets/BranchTicketService.java @@ -436,64 +436,84 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi @Override public List getTickets(RepositoryModel repository, TicketFilter filter) { List list = new ArrayList(); - - Repository db = repositoryManager.getRepository(repository.name); - try { - RefModel ticketsBranch = getTicketsBranch(db); - if (ticketsBranch == null) { - return list; + List databases = new ArrayList(); + List models = new ArrayList(); + + if(repository == null) + { + List allRepo = repositoryManager.getRepositoryList(); + for(int i = 0; i < allRepo.size(); i++) + { + databases.add(repositoryManager.getRepository(allRepo.get(i))); + models.add(repositoryManager.getRepositoryModel(allRepo.get(i))); } + } + else + { + databases.add(repositoryManager.getRepository(repository.name)); + models.add(repository); + } - // Collect the set of all json files - List paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH); - - // Deserialize each ticket and optionally filter out unwanted tickets - for (PathModel path : paths) { - String name = path.name.substring(path.name.lastIndexOf('/') + 1); - if (!JOURNAL.equals(name)) { - continue; - } - String json = readTicketsFile(db, path.path); - if (StringUtils.isEmpty(json)) { - // journal was touched but no changes were written - continue; + for(int i = 0; i < databases.size(); i++) + { + Repository db = databases.get(i); + try { + RefModel ticketsBranch = getTicketsBranch(db); + if (ticketsBranch == null) { + return list; } - try { - // Reconstruct ticketId from the path - // id/26/326/journal.json - String tid = path.path.split("/")[2]; - long ticketId = Long.parseLong(tid); - List changes = TicketSerializer.deserializeJournal(json); - if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", repository, path.path); + + // Collect the set of all json files + List paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH); + + // Deserialize each ticket and optionally filter out unwanted tickets + for (PathModel path : paths) { + String name = path.name.substring(path.name.lastIndexOf('/') + 1); + if (!JOURNAL.equals(name)) { + continue; + } + String json = readTicketsFile(db, path.path); + if (StringUtils.isEmpty(json)) { + // journal was touched but no changes were written continue; } - TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = repository.projectPath; - ticket.repository = repository.name; - ticket.number = ticketId; - - // add the ticket, conditionally, to the list - if (filter == null) { - list.add(ticket); - } else { - if (filter.accept(ticket)) { + try { + // Reconstruct ticketId from the path + // id/26/326/journal.json + String tid = path.path.split("/")[2]; + long ticketId = Long.parseLong(tid); + List changes = TicketSerializer.deserializeJournal(json); + if (ArrayUtils.isEmpty(changes)) { + log.warn("Empty journal for {}:{}", models.get(i), path.path); + continue; + } + TicketModel ticket = TicketModel.buildTicket(changes); + ticket.project = models.get(i).projectPath; + ticket.repository = models.get(i).name; + ticket.number = ticketId; + + // add the ticket, conditionally, to the list + if (filter == null) { list.add(ticket); + } else { + if (filter.accept(ticket)) { + list.add(ticket); + } } + } catch (Exception e) { + log.error("failed to deserialize {}/{}\n{}", + new Object [] { repository, path.path, e.getMessage()}); + log.error(null, e); } - } catch (Exception e) { - log.error("failed to deserialize {}/{}\n{}", - new Object [] { repository, path.path, e.getMessage()}); - log.error(null, e); } + } finally { + db.close(); } - - // sort the tickets by creation - Collections.sort(list); - return list; - } finally { - db.close(); } + + // sort the tickets by creation + Collections.sort(list); + return list; } /** diff --git a/src/main/java/com/gitblit/tickets/FileTicketService.java b/src/main/java/com/gitblit/tickets/FileTicketService.java index ea5d065f..7fd9675f 100644 --- a/src/main/java/com/gitblit/tickets/FileTicketService.java +++ b/src/main/java/com/gitblit/tickets/FileTicketService.java @@ -228,6 +228,7 @@ public class FileTicketService extends ITicketService { for(int i = 0; i < databases.size(); i++) { Repository db = databases.get(i); + RepositoryModel model = models.get(i); try { // Collect the set of all json files File dir = new File(db.getDirectory(), TICKETS_PATH); @@ -253,12 +254,12 @@ public class FileTicketService extends ITicketService { long ticketId = Long.parseLong(tid); List changes = TicketSerializer.deserializeJournal(json); if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", models.get(i), journal); + log.warn("Empty journal for {}:{}", model, journal); continue; } TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = models.get(i).projectPath; - ticket.repository = models.get(i).name; + ticket.project = model.projectPath; + ticket.repository = model.name; ticket.number = ticketId; // add the ticket, conditionally, to the list @@ -271,7 +272,7 @@ public class FileTicketService extends ITicketService { } } catch (Exception e) { log.error("failed to deserialize {}/{}\n{}", - new Object [] { models.get(i), journal, e.getMessage()}); + new Object [] { model, journal, e.getMessage()}); log.error(null, e); } } diff --git a/src/main/java/com/gitblit/tickets/RedisTicketService.java b/src/main/java/com/gitblit/tickets/RedisTicketService.java index 2c5b181f..48256b2b 100644 --- a/src/main/java/com/gitblit/tickets/RedisTicketService.java +++ b/src/main/java/com/gitblit/tickets/RedisTicketService.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.eclipse.jgit.lib.Repository; import redis.clients.jedis.Client; import redis.clients.jedis.Jedis; @@ -228,47 +229,65 @@ public class RedisTicketService extends ITicketService { public List getTickets(RepositoryModel repository, TicketFilter filter) { Jedis jedis = pool.getResource(); List list = new ArrayList(); + List models = new ArrayList(); + + if(repository == null) + { + List allRepo = repositoryManager.getRepositoryList(); + for(int i = 0; i < allRepo.size(); i++) + { + models.add(repositoryManager.getRepositoryModel(allRepo.get(i))); + } + } + else + { + models.add(repository); + } + if (jedis == null) { return list; } - try { - // Deserialize each journal, build the ticket, and optionally filter - Set keys = jedis.keys(key(repository, KeyType.journal, "*")); - for (String key : keys) { - // {repo}:journal:{id} - String id = key.split(":")[2]; - long ticketId = Long.parseLong(id); - List changes = getJournal(jedis, repository, ticketId); - if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", repository, ticketId); - continue; - } - TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = repository.projectPath; - ticket.repository = repository.name; - ticket.number = ticketId; - - // add the ticket, conditionally, to the list - if (filter == null) { - list.add(ticket); - } else { - if (filter.accept(ticket)) { + for(int i = 0; i < models.size(); i++) + { + RepositoryModel model = models.get(i); + try { + // Deserialize each journal, build the ticket, and optionally filter + Set keys = jedis.keys(key(model, KeyType.journal, "*")); + for (String key : keys) { + // {repo}:journal:{id} + String id = key.split(":")[2]; + long ticketId = Long.parseLong(id); + List changes = getJournal(jedis, model, ticketId); + if (ArrayUtils.isEmpty(changes)) { + log.warn("Empty journal for {}:{}", model, ticketId); + continue; + } + TicketModel ticket = TicketModel.buildTicket(changes); + ticket.project = model.projectPath; + ticket.repository = model.name; + ticket.number = ticketId; + + // add the ticket, conditionally, to the list + if (filter == null) { list.add(ticket); + } else { + if (filter.accept(ticket)) { + list.add(ticket); + } } } - } - - // sort the tickets by creation - Collections.sort(list); - } catch (JedisException e) { - log.error("failed to retrieve tickets from Redis @ " + getUrl(), e); - pool.returnBrokenResource(jedis); - jedis = null; - } finally { - if (jedis != null) { - pool.returnResource(jedis); + } catch (JedisException e) { + log.error("failed to retrieve tickets from Redis @ " + getUrl(), e); + pool.returnBrokenResource(jedis); + jedis = null; + } finally { + if (jedis != null) { + pool.returnResource(jedis); + } } } + // sort the tickets by creation + Collections.sort(list); return list; } -- cgit v1.2.3 From 75796a0e2798e256a94f725961c9676746fc107a Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Thu, 17 Apr 2014 15:44:16 +0200 Subject: Added git stylesheets to MyTickets. Added links to Repositories containing the tickets. --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 69 +++++------ .../com/gitblit/wicket/pages/MyTicketsPage.java | 137 +++++++++------------ src/main/resources/gitblit.css | 48 ++++++++ 3 files changed, 135 insertions(+), 119 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 5222c35c..5d11fbbb 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -9,49 +9,36 @@
[my tickets message]
- - Responsible Tickets +
+ - - - - - - -
- - - Author Tickets - - - - - - - -
- - - Voted Tickets - - - - - - - -
- - - Watched Tickets - - - - - - - + + + +
+ + + + + + Repository + + Ticket + Description + Responsible + + + + + + + [repository name] + + [ticket name] + [ticket description] + [ticket responsible] +
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 6e656ae4..6cd80a3f 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -1,19 +1,28 @@ package com.gitblit.wicket.pages; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; -import com.gitblit.Keys; +import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel; import com.gitblit.tickets.ITicketService; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.LinkPanel; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.IDataProvider; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.Component; import org.apache.wicket.PageParameters; public class MyTicketsPage extends RootPage { @@ -34,103 +43,75 @@ public class MyTicketsPage extends RootPage { } String username = currentUser.getName(); + // TODO - Recover the Welcome message String message = "Welcome on GitBlit"; - this.add(new Label("myTicketsMessage", message)); + this.add(new Label("myTicketsMessage", message)); + + Fragment fragment = new Fragment("headerContent", "ticketsHeader", this); + add(fragment); ITicketService tickets = GitBlitWebApp.get().tickets(); List returnedTickets = tickets.getTickets(null); + List yourTickets = new ArrayList(); - List responsibleTickets = new ArrayList(); - List authorTickets = new ArrayList(); - List votedTickets = new ArrayList(); - List watchedTickets = new ArrayList(); for(int i = 0; i < returnedTickets.size(); i++) { TicketModel ticket = returnedTickets.get(i); if(ticket.isOpen()) { - if(ticket.isResponsible(username)) - { - responsibleTickets.add(ticket); - } - if(ticket.isAuthor(username)) - { - authorTickets.add(ticket); - } - if(ticket.isVoter(username)) + if(ticket.isResponsible(username) || ticket.isAuthor(username) + || ticket.isVoter(username) || ticket.isWatching(username)) { - votedTickets.add(ticket); - } - if(ticket.isWatching(username)) - { - watchedTickets.add(ticket); + yourTickets.add(ticket); } } } - ListView responsibleView = new ListView("responsibleTickets", responsibleTickets) - { - private static final long serialVersionUID = 1L; - - @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); - } - }; + final ListDataProvider dp = new ListDataProvider(yourTickets); - ListView authorView = new ListView("authorTickets", authorTickets) - { + DataView dataView = new DataView("row", dp) { private static final long serialVersionUID = 1L; - - @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); - } - }; - - ListView votedView = new ListView("votedTickets", votedTickets) - { - private static final long serialVersionUID = 1L; - - @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); - } - }; - - ListView watchedView = new ListView("watchedTickets", watchedTickets) - { - private static final long serialVersionUID = 1L; - + @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); + protected void populateItem(Item item) { + TicketModel ticketModel = item.getModelObject(); + RepositoryModel repository = app().repositories().getRepositoryModel(ticketModel.repository); + + Fragment row = new Fragment("rowContent", "ticketRow", this); + item.add(row); + + Component swatch; + if(repository.isBare) + { + swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); + } + else + { + swatch = new Label("repositorySwatch", "!"); + WicketUtils.setHtmlTooltip(swatch, getString("gb.workingCopyWarning")); + } + WicketUtils.setCssBackground(swatch, repository.toString()); + row.add(swatch); + + PageParameters pp = WicketUtils.newRepositoryParameter(repository.name); + Class linkPage; + if (repository.hasCommits) { + // repository has content + linkPage = SummaryPage.class; + } else { + // new/empty repository OR proposed repository + linkPage = EmptyRepositoryPage.class; + } + + String ticketUrl = app().tickets().getTicketUrl(ticketModel); + + row.add(new LinkPanel("repositoryName", "list", repository.name, linkPage, pp)); + row.add(new LinkPanel("ticketName", "list", ticketModel.title, ticketUrl)); + row.add(new LinkPanel("ticketDescription", "list", ticketModel.body, ticketUrl)); + row.add(new Label("ticketResponsible", ticketModel.responsible)); } }; - add(responsibleView); - add(authorView); - add(votedView); - add(watchedView); + add(dataView); } } diff --git a/src/main/resources/gitblit.css b/src/main/resources/gitblit.css index 748a3198..ea663a66 100644 --- a/src/main/resources/gitblit.css +++ b/src/main/resources/gitblit.css @@ -1599,6 +1599,54 @@ table.repositories tr.group td a { color: black; } +table.tickets { + border:1px solid #ddd; + border-spacing: 0px; + width: 100%; +} + +table.tickets th { + padding: 4px; + border:0; +} + +table.tickets th.right { + border-right: 1px solid #ddd; +} + +table.tickets td { + padding: 2px; + border-left: 0; +} + +table.tickets td.rightAlign { + text-align: right; + border-right: 1px solid #ddd; +} + +table.tickets td.icon img { + vertical-align: top; +} + +table.tickets tr.group { + background-color: #ccc; + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; +} + +table.tickets tr.group td { + font-weight: bold; + color: black; + background-color: #ddd; + padding-left: 5px; + border-top: 1px solid #aaa; + border-bottom: 1px solid #aaa; +} + +table.tickets tr.group td a { + color: black; +} + table.palette { border:0; width: 0 !important; } table.palette td.header { font-weight: bold; -- cgit v1.2.3 From f3b1e099e6ae252f1f1296ce5415b85fef6361cf Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Fri, 18 Apr 2014 10:53:24 +0200 Subject: Added back the "my tickets" button in the navbar. --- src/main/java/com/gitblit/wicket/pages/RootPage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index f43dc45e..ec413b19 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -173,7 +173,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - //pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From e1fa9b763cadcdc44943f805aba83698acafa613 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 21 Apr 2014 21:55:48 -0400 Subject: Revisions demonstrating the direction I'd like this to go --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 55 +++-- .../com/gitblit/wicket/pages/MyTicketsPage.java | 227 ++++++++++++++------- 2 files changed, 180 insertions(+), 102 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 5d11fbbb..063e7511 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -7,38 +7,35 @@
-
[my tickets message]
- - + + + + + + + + - - - - + + + + + + + +
+ + Repository + TicketStatusResponsible
+ + [repository name] + + [ticket icon] + [ticket title] + (#[ticket number]) + [ticket responsible]
- - - - - - Repository - - Ticket - Description - Responsible - - - - - - - [repository name] - - [ticket name] - [ticket description] - [ticket responsible] -
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 6cd80a3f..2c57a051 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -1,41 +1,41 @@ package com.gitblit.wicket.pages; -import java.util.ArrayList; -import java.util.Iterator; import java.util.List; +import org.apache.wicket.Component; +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; + import com.gitblit.models.RepositoryModel; -import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel; +import com.gitblit.models.UserModel; +import com.gitblit.models.TicketModel.Status; +import com.gitblit.models.TicketModel.Type; import com.gitblit.tickets.ITicketService; +import com.gitblit.tickets.QueryBuilder; +import com.gitblit.tickets.QueryResult; +import com.gitblit.tickets.TicketIndexer.Lucene; +import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.GravatarImage; import com.gitblit.wicket.panels.LinkPanel; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.list.ListItem; -import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Fragment; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.markup.repeater.data.DataView; -import org.apache.wicket.markup.repeater.data.IDataProvider; -import org.apache.wicket.markup.repeater.data.ListDataProvider; -import org.apache.wicket.model.IModel; -import org.apache.wicket.Component; -import org.apache.wicket.PageParameters; - public class MyTicketsPage extends RootPage { - public MyTicketsPage(PageParameters params) + public MyTicketsPage() { - this(); + this(null); } - public MyTicketsPage() + public MyTicketsPage(PageParameters params) { super(); - setupPage("", ""); + setupPage("", getString("gb.mytickets")); UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { @@ -43,75 +43,156 @@ public class MyTicketsPage extends RootPage { } String username = currentUser.getName(); - // TODO - Recover the Welcome message - String message = "Welcome on GitBlit"; - this.add(new Label("myTicketsMessage", message)); - - Fragment fragment = new Fragment("headerContent", "ticketsHeader", this); - add(fragment); + QueryBuilder qb = QueryBuilder + .q(Lucene.createdby.matches(username)) + .or(Lucene.responsible.matches(username)) + .or(Lucene.watchedby.matches(username)); ITicketService tickets = GitBlitWebApp.get().tickets(); - List returnedTickets = tickets.getTickets(null); - List yourTickets = new ArrayList(); - - for(int i = 0; i < returnedTickets.size(); i++) - { - TicketModel ticket = returnedTickets.get(i); - if(ticket.isOpen()) - { - if(ticket.isResponsible(username) || ticket.isAuthor(username) - || ticket.isVoter(username) || ticket.isWatching(username)) - { - yourTickets.add(ticket); - } - } - } + List results = tickets.queryFor(qb.build(), 0, 0, Lucene.updated.name(), true); - final ListDataProvider dp = new ListDataProvider(yourTickets); + final ListDataProvider dp = new ListDataProvider(results); - DataView dataView = new DataView("row", dp) { + DataView dataView = new DataView("row", dp) { private static final long serialVersionUID = 1L; @Override - protected void populateItem(Item item) { - TicketModel ticketModel = item.getModelObject(); - RepositoryModel repository = app().repositories().getRepositoryModel(ticketModel.repository); - - Fragment row = new Fragment("rowContent", "ticketRow", this); - item.add(row); + protected void populateItem(Item item) { + QueryResult ticket = item.getModelObject(); + RepositoryModel repository = app().repositories().getRepositoryModel(ticket.repository); - Component swatch; - if(repository.isBare) - { - swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); - } - else - { - swatch = new Label("repositorySwatch", "!"); - WicketUtils.setHtmlTooltip(swatch, getString("gb.workingCopyWarning")); - } + Component swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); WicketUtils.setCssBackground(swatch, repository.toString()); - row.add(swatch); + item.add(swatch); - PageParameters pp = WicketUtils.newRepositoryParameter(repository.name); - Class linkPage; - if (repository.hasCommits) { - // repository has content - linkPage = SummaryPage.class; - } else { - // new/empty repository OR proposed repository - linkPage = EmptyRepositoryPage.class; - } + PageParameters rp = WicketUtils.newRepositoryParameter(ticket.repository); + PageParameters tp = WicketUtils.newObjectParameter(ticket.repository, "" + ticket.number); + item.add(new LinkPanel("repositoryName", "list", StringUtils.stripDotGit(ticket.repository), SummaryPage.class, rp)); - String ticketUrl = app().tickets().getTicketUrl(ticketModel); + item.add(getStateIcon("ticketIcon", ticket.type, ticket.status)); + item.add(new Label("ticketNumber", "" + ticket.number)); + item.add(new LinkPanel("ticketTitle", "list", ticket.title, TicketsPage.class, tp)); + + // votes indicator + Label v = new Label("ticketVotes", "" + ticket.votesCount); + WicketUtils.setHtmlTooltip(v, getString("gb.votes")); + item.add(v.setVisible(ticket.votesCount > 0)); + + Label ticketStatus = new Label("ticketStatus", ticket.status.toString()); + String statusClass = getStatusClass(ticket.status); + WicketUtils.setCssClass(ticketStatus, statusClass); + item.add(ticketStatus); - row.add(new LinkPanel("repositoryName", "list", repository.name, linkPage, pp)); - row.add(new LinkPanel("ticketName", "list", ticketModel.title, ticketUrl)); - row.add(new LinkPanel("ticketDescription", "list", ticketModel.body, ticketUrl)); - row.add(new Label("ticketResponsible", ticketModel.responsible)); + UserModel responsible = app().users().getUserModel(ticket.responsible); + if (responsible == null) { + if (ticket.responsible == null) { + item.add(new Label("ticketResponsibleImg").setVisible(false)); + } else { + item.add(new GravatarImage("ticketResponsibleImg", ticket.responsible, ticket.responsible, null, 16, true)); + } + item.add(new Label("ticketResponsible", ticket.responsible)); + } else { + item.add(new GravatarImage("ticketResponsibleImg", responsible, null, 16, true)); + item.add(new LinkPanel("ticketResponsible", null, responsible.getDisplayName(), UserPage.class, WicketUtils.newUsernameParameter(ticket.responsible))); + } } }; add(dataView); } + + protected Label getStateIcon(String wicketId, TicketModel ticket) { + return getStateIcon(wicketId, ticket.type, ticket.status); + } + + protected Label getStateIcon(String wicketId, Type type, Status state) { + Label label = new Label(wicketId); + if (type == null) { + type = Type.defaultType; + } + switch (type) { + case Proposal: + WicketUtils.setCssClass(label, "fa fa-code-fork"); + break; + case Bug: + WicketUtils.setCssClass(label, "fa fa-bug"); + break; + case Enhancement: + WicketUtils.setCssClass(label, "fa fa-magic"); + break; + case Question: + WicketUtils.setCssClass(label, "fa fa-question"); + break; + default: + // standard ticket + WicketUtils.setCssClass(label, "fa fa-ticket"); + } + WicketUtils.setHtmlTooltip(label, getTypeState(type, state)); + return label; + } + + protected String getTypeState(Type type, Status state) { + return state.toString() + " " + type.toString(); + } + + protected String getLozengeClass(Status status, boolean subtle) { + if (status == null) { + status = Status.New; + } + String css = ""; + switch (status) { + case Declined: + case Duplicate: + case Invalid: + case Wontfix: + case Abandoned: + css = "aui-lozenge-error"; + break; + case Fixed: + case Merged: + case Resolved: + css = "aui-lozenge-success"; + break; + case New: + css = "aui-lozenge-complete"; + break; + case On_Hold: + css = "aui-lozenge-current"; + break; + default: + css = ""; + break; + } + + return "aui-lozenge" + (subtle ? " aui-lozenge-subtle": "") + (css.isEmpty() ? "" : " ") + css; + } + + protected String getStatusClass(Status status) { + String css = ""; + switch (status) { + case Declined: + case Duplicate: + case Invalid: + case Wontfix: + case Abandoned: + css = "resolution-error"; + break; + case Fixed: + case Merged: + case Resolved: + css = "resolution-success"; + break; + case New: + css = "resolution-complete"; + break; + case On_Hold: + css = "resolution-current"; + break; + default: + css = ""; + break; + } + + return "resolution" + (css.isEmpty() ? "" : " ") + css; + } } -- cgit v1.2.3 From 4640f1b689684b805f08a5a937e91dfc65ae977f Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Tue, 22 Apr 2014 12:23:03 +0200 Subject: Now only shows the "my tickets" button in the navbar if you are connected. Redirects to the main page if you try going on "/mytickets" when not connected (or if you disconnect while being on "/mytickets"). --- .../java/com/gitblit/wicket/pages/MyTicketsPage.java | 6 ++++-- src/main/java/com/gitblit/wicket/pages/RootPage.java | 17 +++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 2c57a051..9be3b125 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -34,12 +34,14 @@ public class MyTicketsPage extends RootPage { public MyTicketsPage(PageParameters params) { - super(); + super(params); setupPage("", getString("gb.mytickets")); UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { - currentUser = UserModel.ANONYMOUS; + setRedirect(true); + setResponsePage(getApplication().getHomePage()); + return; } String username = currentUser.getName(); diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index ec413b19..a4d2353d 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -134,6 +134,8 @@ public abstract class RootPage extends BasePage { boolean authenticateView = app().settings().getBoolean(Keys.web.authenticateViewPages, false); boolean authenticateAdmin = app().settings().getBoolean(Keys.web.authenticateAdminPages, true); boolean allowAdmin = app().settings().getBoolean(Keys.web.allowAdministration, true); + boolean allowLucene = app().settings().getBoolean(Keys.web.allowLuceneIndexing, true); + boolean isLoggedIn = GitBlitWebSession.get().isLoggedIn(); if (authenticateAdmin) { showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin(); @@ -151,7 +153,7 @@ public abstract class RootPage extends BasePage { } if (authenticateView || authenticateAdmin) { - if (GitBlitWebSession.get().isLoggedIn()) { + if (isLoggedIn) { UserMenu userFragment = new UserMenu("userPanel", "userMenuFragment", RootPage.this); add(userFragment); } else { @@ -167,14 +169,17 @@ public abstract class RootPage extends BasePage { // navigation links List pages = new ArrayList(); - if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) { - pages.add(new PageRegistration(GitBlitWebSession.get().isLoggedIn() ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, + if (!authenticateView || (authenticateView && isLoggedIn)) { + pages.add(new PageRegistration(isLoggedIn ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); - if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { + if(isLoggedIn) + { + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); + } + if (allowLucene) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } if (showAdmin) { @@ -184,7 +189,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.federation", FederationPage.class)); } - if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) { + if (!authenticateView || (authenticateView && isLoggedIn)) { addDropDownMenus(pages); } } -- cgit v1.2.3 From e7f65dfe56b5b6325a7d7b42f877ae8d63fa4f71 Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Tue, 22 Apr 2014 16:21:35 +0200 Subject: Advanced "my tickets" page. Using filters and search. --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 117 +++++-- .../com/gitblit/wicket/pages/MyTicketsPage.java | 370 ++++++++++++++++++++- 2 files changed, 452 insertions(+), 35 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 063e7511..459d2551 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -7,35 +7,94 @@
- - - - - - - - - - - - - - - - - - -
- - Repository - TicketStatusResponsible
- - [repository name] - - [ticket icon] - [ticket title] - (#[ticket number]) - [ticket responsible]
+ + +
+ +
+ + +
+
+
+ +
+
+ +
+
+ + +
+
+
+ : + +
+ +
+ : + +
+ +
+ +
+
+ + + + + + + + + + +
+ + [repository name] + + [ticket icon] + [ticket title] + (#[ticket number]) + [ticket responsible]
+
+
+
+
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 9be3b125..01a30181 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -1,14 +1,24 @@ package com.gitblit.wicket.pages; +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.target.basic.RedirectRequestTarget; +import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; import com.gitblit.models.UserModel; @@ -18,14 +28,20 @@ import com.gitblit.tickets.ITicketService; import com.gitblit.tickets.QueryBuilder; import com.gitblit.tickets.QueryResult; import com.gitblit.tickets.TicketIndexer.Lucene; +import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.SessionlessForm; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.GravatarImage; import com.gitblit.wicket.panels.LinkPanel; public class MyTicketsPage extends RootPage { + + public static final String [] openStatii = new String [] { Status.New.name().toLowerCase(), Status.Open.name().toLowerCase() }; + + public static final String [] closedStatii = new String [] { "!" + Status.New.name().toLowerCase(), "!" + Status.Open.name().toLowerCase() }; public MyTicketsPage() { @@ -43,15 +59,205 @@ public class MyTicketsPage extends RootPage { setResponsePage(getApplication().getHomePage()); return; } - String username = currentUser.getName(); - QueryBuilder qb = QueryBuilder - .q(Lucene.createdby.matches(username)) - .or(Lucene.responsible.matches(username)) - .or(Lucene.watchedby.matches(username)); + final String username = currentUser.getName(); + final String[] statiiParam = (params == null) ? new String[0] : params.getStringArray(Lucene.status.name()); + final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null); + final String milestoneParam = (params == null) ? "" : params.getString(Lucene.milestone.name(), null); + final String queryParam = (params == null || StringUtils.isEmpty(params.getString("q", null))) ? "watchedby:" + username : params.getString("q", null); + final String searchParam = (params == null) ? "" : params.getString("s", null); + final String sortBy = (params == null) ? "" : Lucene.fromString(params.getString("sort", Lucene.created.name())).name(); + final boolean desc = (params == null) ? true : !"asc".equals(params.getString("direction", "desc")); + + // add search form + TicketSearchForm searchForm = new TicketSearchForm("ticketSearchForm", searchParam); + add(searchForm); + searchForm.setTranslatedAttributes(); + + // standard queries + add(new BookmarkablePageLink("changesQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Proposal.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("bugsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Bug.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("enhancementsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Enhancement.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("tasksQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Task.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("questionsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Question.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("resetQuery", MyTicketsPage.class, + queryParameters( + null, + milestoneParam, + openStatii, + null, + null, + true, + 1))); + + add(new Label("userDivider")); + add(new BookmarkablePageLink("createdQuery", MyTicketsPage.class, + queryParameters( + Lucene.createdby.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("watchedQuery", MyTicketsPage.class, + queryParameters( + Lucene.watchedby.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + add(new BookmarkablePageLink("mentionsQuery", MyTicketsPage.class, + queryParameters( + Lucene.mentions.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + // states + if (ArrayUtils.isEmpty(statiiParam)) { + add(new Label("selectedStatii", getString("gb.all"))); + } else { + add(new Label("selectedStatii", StringUtils.flattenStrings(Arrays.asList(statiiParam), ","))); + } + add(new BookmarkablePageLink("openTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, openStatii, assignedToParam, sortBy, desc, 1))); + add(new BookmarkablePageLink("closedTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, closedStatii, assignedToParam, sortBy, desc, 1))); + add(new BookmarkablePageLink("allTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, 1))); + + // by status + List statii = new ArrayList(Arrays.asList(Status.values())); + statii.remove(Status.Closed); + ListDataProvider resolutionsDp = new ListDataProvider(statii); + DataView statiiLinks = new DataView("statii", resolutionsDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item item) { + final Status status = item.getModelObject(); + PageParameters p = queryParameters(queryParam, milestoneParam, new String [] { status.name().toLowerCase() }, assignedToParam, sortBy, desc, 1); + String css = getStatusClass(status); + item.add(new LinkPanel("statusLink", css, status.toString(), MyTicketsPage.class, p).setRenderBodyOnly(true)); + } + }; + add(statiiLinks); + + List sortChoices = new ArrayList(); + sortChoices.add(new TicketSort(getString("gb.sortNewest"), Lucene.created.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortOldest"), Lucene.created.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostRecentlyUpdated"), Lucene.updated.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastRecentlyUpdated"), Lucene.updated.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostComments"), Lucene.comments.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastComments"), Lucene.comments.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostPatchsetRevisions"), Lucene.patchsets.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastPatchsetRevisions"), Lucene.patchsets.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostVotes"), Lucene.votes.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastVotes"), Lucene.votes.name(), false)); + + TicketSort currentSort = sortChoices.get(0); + for (TicketSort ts : sortChoices) { + if (ts.sortBy.equals(sortBy) && desc == ts.desc) { + currentSort = ts; + break; + } + } + add(new Label("currentSort", currentSort.name)); + + ListDataProvider sortChoicesDp = new ListDataProvider(sortChoices); + DataView sortMenu = new DataView("sort", sortChoicesDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item item) { + final TicketSort ts = item.getModelObject(); + PageParameters params = queryParameters(queryParam, milestoneParam, statiiParam, assignedToParam, ts.sortBy, ts.desc, 1); + item.add(new LinkPanel("sortLink", null, ts.name, MyTicketsPage.class, params).setRenderBodyOnly(true)); + } + }; + add(sortMenu); + + // Build Query here + QueryBuilder qb = new QueryBuilder(queryParam); + if (!qb.containsField(Lucene.responsible.name())) { + // specify the responsible + qb.and(Lucene.responsible.matches(assignedToParam)); + } + if (!qb.containsField(Lucene.milestone.name())) { + // specify the milestone + qb.and(Lucene.milestone.matches(milestoneParam)); + } + if (!qb.containsField(Lucene.status.name()) && !ArrayUtils.isEmpty(statiiParam)) { + // specify the states + boolean not = false; + QueryBuilder q = new QueryBuilder(); + for (String state : statiiParam) { + if (state.charAt(0) == '!') { + not = true; + q.and(Lucene.status.doesNotMatch(state.substring(1))); + } else { + q.or(Lucene.status.matches(state)); + } + } + if (not) { + qb.and(q.toString()); + } else { + qb.and(q.toSubquery().toString()); + } + } + final String luceneQuery = qb.build(); ITicketService tickets = GitBlitWebApp.get().tickets(); - List results = tickets.queryFor(qb.build(), 0, 0, Lucene.updated.name(), true); + List results = tickets.queryFor(luceneQuery, 0, 0, Lucene.updated.name(), true); final ListDataProvider dp = new ListDataProvider(results); @@ -100,6 +306,12 @@ public class MyTicketsPage extends RootPage { } }; + // paging links + int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; + int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); + int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; + buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); + add(dataView); } @@ -197,4 +409,150 @@ public class MyTicketsPage extends RootPage { return "resolution" + (css.isEmpty() ? "" : " ") + css; } + + private class TicketSort implements Serializable { + + private static final long serialVersionUID = 1L; + + final String name; + final String sortBy; + final boolean desc; + + TicketSort(String name, String sortBy, boolean desc) { + this.name = name; + this.sortBy = sortBy; + this.desc = desc; + } + } + + private class TicketSearchForm extends SessionlessForm implements Serializable { + private static final long serialVersionUID = 1L; + + private final IModel searchBoxModel;; + + public TicketSearchForm(String id, String text) { + super(id, MyTicketsPage.this.getClass(), MyTicketsPage.this.getPageParameters()); + + this.searchBoxModel = new Model(text == null ? "" : text); + + TextField searchBox = new TextField("ticketSearchBox", searchBoxModel); + add(searchBox); + } + + void setTranslatedAttributes() { + WicketUtils.setHtmlTooltip(get("ticketSearchBox"), + MessageFormat.format(getString("gb.searchTicketsTooltip"), "")); + WicketUtils.setInputPlaceholder(get("ticketSearchBox"), getString("gb.searchTickets")); + } + + @Override + public void onSubmit() { + String searchString = searchBoxModel.getObject(); + if (StringUtils.isEmpty(searchString)) { + // redirect to self to avoid wicket page update bug + String absoluteUrl = getCanonicalUrl(); + getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); + return; + } + + // use an absolute url to workaround Wicket-Tomcat problems with + // mounted url parameters (issue-111) + PageParameters params = WicketUtils.newRepositoryParameter(""); + params.add("s", searchString); + String absoluteUrl = getCanonicalUrl(MyTicketsPage.class, params); + getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); + } + } + + protected PageParameters queryParameters( + String query, + String milestone, + String[] states, + String assignedTo, + String sort, + boolean descending, + int page) { + + PageParameters params = WicketUtils.newRepositoryParameter(""); + if (!StringUtils.isEmpty(query)) { + params.add("q", query); + } + if (!StringUtils.isEmpty(milestone)) { + params.add(Lucene.milestone.name(), milestone); + } + if (!ArrayUtils.isEmpty(states)) { + for (String state : states) { + params.add(Lucene.status.name(), state); + } + } + if (!StringUtils.isEmpty(assignedTo)) { + params.add(Lucene.responsible.name(), assignedTo); + } + if (!StringUtils.isEmpty(sort)) { + params.add("sort", sort); + } + if (!descending) { + params.add("direction", "asc"); + } + if (page > 1) { + params.add("pg", "" + page); + } + return params; + } + + protected void buildPager( + final String query, + final String milestone, + final String [] states, + final String assignedTo, + final String sort, + final boolean desc, + final int page, + int pageSize, + int count, + int total) { + + boolean showNav = total > (2 * pageSize); + boolean allowPrev = page > 1; + boolean allowNext = (pageSize * (page - 1) + count) < total; + add(new BookmarkablePageLink("prevLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav)); + add(new BookmarkablePageLink("nextLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page + 1)).setEnabled(allowNext).setVisible(showNav)); + + if (total <= pageSize) { + add(new Label("pageLink").setVisible(false)); + return; + } + + // determine page numbers to display + int pages = count == 0 ? 0 : ((total / pageSize) + (total % pageSize == 0 ? 0 : 1)); + // preferred number of pagelinks + int segments = 5; + if (pages < segments) { + // not enough data for preferred number of page links + segments = pages; + } + int minpage = Math.min(Math.max(1, page - 2), pages - (segments - 1)); + int maxpage = Math.min(pages, minpage + (segments - 1)); + List sequence = new ArrayList(); + for (int i = minpage; i <= maxpage; i++) { + sequence.add(i); + } + + ListDataProvider pagesDp = new ListDataProvider(sequence); + DataView pagesView = new DataView("pageLink", pagesDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item item) { + final Integer i = item.getModelObject(); + LinkPanel link = new LinkPanel("page", null, "" + i, TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, i)); + link.setRenderBodyOnly(true); + if (i == page) { + WicketUtils.setCssClass(item, "active"); + } + item.add(link); + } + }; + add(pagesView); + } } -- cgit v1.2.3 From 3f5b8f5d9203aa7ffb7fbe9cdbaf9dba3da6cae6 Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Tue, 22 Apr 2014 17:10:33 +0200 Subject: Fixes sort, page building and search functions on "my tickets" page. --- .../com/gitblit/wicket/pages/MyTicketsPage.java | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 01a30181..32cdaec3 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -61,7 +61,7 @@ public class MyTicketsPage extends RootPage { } final String username = currentUser.getName(); - final String[] statiiParam = (params == null) ? new String[0] : params.getStringArray(Lucene.status.name()); + final String[] statiiParam = (params == null) ? openStatii : params.getStringArray(Lucene.status.name()); final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null); final String milestoneParam = (params == null) ? "" : params.getString(Lucene.milestone.name(), null); final String queryParam = (params == null || StringUtils.isEmpty(params.getString("q", null))) ? "watchedby:" + username : params.getString("q", null); @@ -256,8 +256,22 @@ public class MyTicketsPage extends RootPage { } final String luceneQuery = qb.build(); + // paging links + int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; + int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); + ITicketService tickets = GitBlitWebApp.get().tickets(); - List results = tickets.queryFor(luceneQuery, 0, 0, Lucene.updated.name(), true); + List results; + if(StringUtils.isEmpty(searchParam)) + { + results = tickets.queryFor(luceneQuery, page, pageSize, sortBy, desc); + } + else + { + results = tickets.searchFor(null, searchParam, page, pageSize); + } + int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; + buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); final ListDataProvider dp = new ListDataProvider(results); @@ -306,12 +320,6 @@ public class MyTicketsPage extends RootPage { } }; - // paging links - int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; - int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); - int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; - buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); - add(dataView); } @@ -515,8 +523,8 @@ public class MyTicketsPage extends RootPage { boolean showNav = total > (2 * pageSize); boolean allowPrev = page > 1; boolean allowNext = (pageSize * (page - 1) + count) < total; - add(new BookmarkablePageLink("prevLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav)); - add(new BookmarkablePageLink("nextLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page + 1)).setEnabled(allowNext).setVisible(showNav)); + add(new BookmarkablePageLink("prevLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav)); + add(new BookmarkablePageLink("nextLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page + 1)).setEnabled(allowNext).setVisible(showNav)); if (total <= pageSize) { add(new Label("pageLink").setVisible(false)); @@ -545,7 +553,7 @@ public class MyTicketsPage extends RootPage { @Override public void populateItem(final Item item) { final Integer i = item.getModelObject(); - LinkPanel link = new LinkPanel("page", null, "" + i, TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, i)); + LinkPanel link = new LinkPanel("page", null, "" + i, MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, i)); link.setRenderBodyOnly(true); if (i == page) { WicketUtils.setCssClass(item, "active"); -- cgit v1.2.3 From 6f9908aa9ebcdfbb32e8305b157be177071abe56 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 24 Apr 2014 14:05:36 -0400 Subject: Do not display My Tickets link if ticket service is not ready --- src/main/java/com/gitblit/wicket/pages/RootPage.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index a4d2353d..fb68208f 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -172,13 +172,12 @@ public abstract class RootPage extends BasePage { if (!authenticateView || (authenticateView && isLoggedIn)) { pages.add(new PageRegistration(isLoggedIn ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, getRootPageParameters())); + if (isLoggedIn && app().tickets().isReady()) { + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class)); + } pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - if(isLoggedIn) - { - pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); - } if (allowLucene) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From b3f70e7ed4b4c59fc578f529411f41e3fd6b192f Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 24 Apr 2014 14:06:36 -0400 Subject: Improve generated Lucene query to only show relevant My Tickets results --- .../com/gitblit/wicket/pages/MyTicketsPage.java | 67 ++++++++++++---------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 32cdaec3..083526b6 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -21,9 +21,9 @@ import org.apache.wicket.request.target.basic.RedirectRequestTarget; import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; -import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel.Status; import com.gitblit.models.TicketModel.Type; +import com.gitblit.models.UserModel; import com.gitblit.tickets.ITicketService; import com.gitblit.tickets.QueryBuilder; import com.gitblit.tickets.QueryResult; @@ -42,24 +42,24 @@ public class MyTicketsPage extends RootPage { public static final String [] openStatii = new String [] { Status.New.name().toLowerCase(), Status.Open.name().toLowerCase() }; public static final String [] closedStatii = new String [] { "!" + Status.New.name().toLowerCase(), "!" + Status.Open.name().toLowerCase() }; - + public MyTicketsPage() { - this(null); + this(null); } - + public MyTicketsPage(PageParameters params) { super(params); setupPage("", getString("gb.mytickets")); - + UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { setRedirect(true); setResponsePage(getApplication().getHomePage()); return; } - + final String username = currentUser.getName(); final String[] statiiParam = (params == null) ? openStatii : params.getStringArray(Lucene.status.name()); final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null); @@ -68,12 +68,12 @@ public class MyTicketsPage extends RootPage { final String searchParam = (params == null) ? "" : params.getString("s", null); final String sortBy = (params == null) ? "" : Lucene.fromString(params.getString("sort", Lucene.created.name())).name(); final boolean desc = (params == null) ? true : !"asc".equals(params.getString("direction", "desc")); - + // add search form TicketSearchForm searchForm = new TicketSearchForm("ticketSearchForm", searchParam); add(searchForm); searchForm.setTranslatedAttributes(); - + // standard queries add(new BookmarkablePageLink("changesQuery", MyTicketsPage.class, queryParameters( @@ -164,7 +164,7 @@ public class MyTicketsPage extends RootPage { sortBy, desc, 1))); - + // states if (ArrayUtils.isEmpty(statiiParam)) { add(new Label("selectedStatii", getString("gb.all"))); @@ -174,7 +174,7 @@ public class MyTicketsPage extends RootPage { add(new BookmarkablePageLink("openTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, openStatii, assignedToParam, sortBy, desc, 1))); add(new BookmarkablePageLink("closedTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, closedStatii, assignedToParam, sortBy, desc, 1))); add(new BookmarkablePageLink("allTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, 1))); - + // by status List statii = new ArrayList(Arrays.asList(Status.values())); statii.remove(Status.Closed); @@ -225,17 +225,9 @@ public class MyTicketsPage extends RootPage { } }; add(sortMenu); - + // Build Query here QueryBuilder qb = new QueryBuilder(queryParam); - if (!qb.containsField(Lucene.responsible.name())) { - // specify the responsible - qb.and(Lucene.responsible.matches(assignedToParam)); - } - if (!qb.containsField(Lucene.milestone.name())) { - // specify the milestone - qb.and(Lucene.milestone.matches(milestoneParam)); - } if (!qb.containsField(Lucene.status.name()) && !ArrayUtils.isEmpty(statiiParam)) { // specify the states boolean not = false; @@ -254,12 +246,27 @@ public class MyTicketsPage extends RootPage { qb.and(q.toSubquery().toString()); } } - final String luceneQuery = qb.build(); - + + final String luceneQuery; + if (qb.containsField(Lucene.createdby.name()) + || qb.containsField(Lucene.responsible.name()) + || qb.containsField(Lucene.watchedby.name())) { + // focused "my tickets" query + luceneQuery = qb.build(); + } else { + // general "my tickets" query + QueryBuilder myQuery = new QueryBuilder(); + myQuery.or(Lucene.createdby.matches(username)); + myQuery.or(Lucene.responsible.matches(username)); + myQuery.or(Lucene.watchedby.matches(username)); + myQuery.and(qb.toSubquery().toString()); + luceneQuery = myQuery.build(); + } + // paging links int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); - + ITicketService tickets = GitBlitWebApp.get().tickets(); List results; if(StringUtils.isEmpty(searchParam)) @@ -272,9 +279,9 @@ public class MyTicketsPage extends RootPage { } int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); - + final ListDataProvider dp = new ListDataProvider(results); - + DataView dataView = new DataView("row", dp) { private static final long serialVersionUID = 1L; @@ -282,15 +289,15 @@ public class MyTicketsPage extends RootPage { protected void populateItem(Item item) { QueryResult ticket = item.getModelObject(); RepositoryModel repository = app().repositories().getRepositoryModel(ticket.repository); - + Component swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); WicketUtils.setCssBackground(swatch, repository.toString()); item.add(swatch); - + PageParameters rp = WicketUtils.newRepositoryParameter(ticket.repository); PageParameters tp = WicketUtils.newObjectParameter(ticket.repository, "" + ticket.number); item.add(new LinkPanel("repositoryName", "list", StringUtils.stripDotGit(ticket.repository), SummaryPage.class, rp)); - + item.add(getStateIcon("ticketIcon", ticket.type, ticket.status)); item.add(new Label("ticketNumber", "" + ticket.number)); item.add(new LinkPanel("ticketTitle", "list", ticket.title, TicketsPage.class, tp)); @@ -304,7 +311,7 @@ public class MyTicketsPage extends RootPage { String statusClass = getStatusClass(ticket.status); WicketUtils.setCssClass(ticketStatus, statusClass); item.add(ticketStatus); - + UserModel responsible = app().users().getUserModel(ticket.responsible); if (responsible == null) { if (ticket.responsible == null) { @@ -319,10 +326,10 @@ public class MyTicketsPage extends RootPage { } } }; - + add(dataView); } - + protected Label getStateIcon(String wicketId, TicketModel ticket) { return getStateIcon(wicketId, ticket.type, ticket.status); } -- cgit v1.2.3 From 4062e46eb07c4202d8872ecc02eb246304dda01e Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 24 Apr 2014 15:16:51 -0400 Subject: Revise My Tickets layout and styling --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 183 ++++++++++-------- .../com/gitblit/wicket/pages/MyTicketsPage.java | 209 ++++++++++++++++++--- src/main/resources/gitblit.css | 48 ----- 3 files changed, 290 insertions(+), 150 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 459d2551..9ecc4b6e 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -8,94 +8,123 @@
- -
-