diff options
author | James Moger <james.moger@gitblit.com> | 2014-05-01 17:58:44 -0600 |
---|---|---|
committer | James Moger <james.moger@gitblit.com> | 2014-05-01 17:58:44 -0600 |
commit | 66e4a930dcd8287b35f256eb13c8df9808efcf55 (patch) | |
tree | 3444acccd2a9b9733eb9a47e3c6677a0cf96706e /src | |
parent | c9de84169e407fbf1963e7ad0e1f3f3e57cfae24 (diff) | |
parent | fdd82f02dddd2d4211e9df4239f3be6c8595b2dd (diff) | |
download | gitblit-66e4a930dcd8287b35f256eb13c8df9808efcf55.tar.gz gitblit-66e4a930dcd8287b35f256eb13c8df9808efcf55.zip |
Merged #15 "My Tickets page"
Diffstat (limited to 'src')
20 files changed, 1176 insertions, 491 deletions
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..0ed2ed59 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -672,9 +672,11 @@ 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. +gb.myTickets = my tickets +gb.yourAssignedTickets = assigned to you gb.newMilestone = new milestone 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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties index 8a725cf4..a6d61842 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties @@ -670,3 +670,5 @@ gb.repositoryDoesNotAcceptPatchsets = Ce dépôt n'accepte pas de patchsets. 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 +gb.yourAssignedTickets = dont vous êtes responsable diff --git a/src/main/java/com/gitblit/wicket/SessionlessForm.java b/src/main/java/com/gitblit/wicket/SessionlessForm.java index d228a2e1..6f790717 100644 --- a/src/main/java/com/gitblit/wicket/SessionlessForm.java +++ b/src/main/java/com/gitblit/wicket/SessionlessForm.java @@ -22,6 +22,7 @@ import org.apache.wicket.PageParameters; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.MarkupStream; import org.apache.wicket.markup.html.form.StatelessForm; +import org.apache.wicket.protocol.http.RequestUtils; import org.apache.wicket.protocol.http.WicketURLDecoder; import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy; import org.apache.wicket.util.string.AppendingStringBuffer; @@ -53,9 +54,9 @@ public class SessionlessForm<T> extends StatelessForm<T> { private static final String HIDDEN_DIV_START = "<div style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">"; - private final Class<? extends BasePage> pageClass; + protected final Class<? extends BasePage> pageClass; - private final PageParameters pageParameters; + protected final PageParameters pageParameters; private final Logger log = LoggerFactory.getLogger(SessionlessForm.class); @@ -145,4 +146,14 @@ public class SessionlessForm<T> extends StatelessForm<T> { String un = WicketURLDecoder.QUERY_INSTANCE.decode(s); return Strings.escapeMarkup(un).toString(); } + + protected String getAbsoluteUrl() { + return getAbsoluteUrl(pageClass, pageParameters); + } + + protected String getAbsoluteUrl(Class<? extends BasePage> pageClass, PageParameters pageParameters) { + String relativeUrl = urlFor(pageClass, pageParameters).toString(); + String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl); + return absoluteUrl; + } } diff --git a/src/main/java/com/gitblit/wicket/TicketsUI.java b/src/main/java/com/gitblit/wicket/TicketsUI.java new file mode 100644 index 00000000..a243a7b3 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/TicketsUI.java @@ -0,0 +1,211 @@ +/* + * 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; + +import java.io.Serializable; +import java.text.MessageFormat; + +import org.apache.wicket.markup.html.basic.Label; + +import com.gitblit.models.TicketModel; +import com.gitblit.models.TicketModel.Status; +import com.gitblit.models.TicketModel.Type; +import com.gitblit.utils.StringUtils; + +/** + * Common tickets ui methods and classes. + * + * @author James Moger + * + */ +public class TicketsUI { + + 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 static Label getStateIcon(String wicketId, TicketModel ticket) { + return getStateIcon(wicketId, ticket.type, ticket.status); + } + + public static 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; + } + + public static String getTypeState(Type type, Status state) { + return state.toString() + " " + type.toString(); + } + + public static 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; + } + + public static 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; + } + + public static class TicketSort implements Serializable { + + private static final long serialVersionUID = 1L; + + public final String name; + public final String sortBy; + public final boolean desc; + + public TicketSort(String name, String sortBy, boolean desc) { + this.name = name; + this.sortBy = sortBy; + this.desc = desc; + } + } + + public static class Indicator implements Serializable { + + private static final long serialVersionUID = 1L; + + public final String css; + public final int count; + public final String tooltip; + + public Indicator(String css, String tooltip) { + this.css = css; + this.tooltip = tooltip; + this.count = 0; + } + + public Indicator(String css, int count, String pattern) { + this.css = css; + this.count = count; + this.tooltip = StringUtils.isEmpty(pattern) ? "" : MessageFormat.format(pattern, count); + } + + public String getTooltip() { + return tooltip; + } + } + + public static class TicketQuery implements Serializable, Comparable<TicketQuery> { + + private static final long serialVersionUID = 1L; + + public final String name; + public final String query; + public String color; + + public TicketQuery(String name, String query) { + this.name = name; + this.query = query; + } + + public TicketQuery color(String value) { + this.color = value; + return this; + } + + @Override + public boolean equals(Object o) { + if (o instanceof TicketQuery) { + return ((TicketQuery) o).query.equals(query); + } + return false; + } + + @Override + public int hashCode() { + return query.hashCode(); + } + + @Override + public int compareTo(TicketQuery o) { + return query.compareTo(o.query); + } + } +} diff --git a/src/main/java/com/gitblit/wicket/WicketUtils.java b/src/main/java/com/gitblit/wicket/WicketUtils.java index 2a34ca80..10b21468 100644 --- a/src/main/java/com/gitblit/wicket/WicketUtils.java +++ b/src/main/java/com/gitblit/wicket/WicketUtils.java @@ -300,7 +300,9 @@ public class WicketUtils { public static PageParameters newRepositoryParameter(String repositoryName) {
Map<String, String> parameterMap = new HashMap<String, String>();
- parameterMap.put("r", repositoryName);
+ if (!StringUtils.isEmpty(repositoryName)) {
+ parameterMap.put("r", repositoryName);
+ }
return new PageParameters(parameterMap);
}
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..b0bc1949 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -0,0 +1,84 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd" + xml:lang="en" + lang="en"> + +<body> + <wicket:extend> + <div class="container"> + <div class="row" style="padding-top:15px;min-height:500px;" > + <div class="tab-pane active" id="tickets"> + <!-- query controls --> + <div class="span3"> + <div class="hidden-phone"> + <div wicket:id="userTitlePanel"></div> + + <!-- search tickets form --> + <form class="form-search" style="margin: 10px 0px;" wicket:id="ticketSearchForm"> + <div class="input-append"> + <input type="text" class="input-medium search-query" style="border-radius: 14px 0 0 14px; padding-left: 14px;" id="ticketSearchBox" wicket:id="ticketSearchBox" value=""/> + <button class="btn" style="border-radius: 0 14px 14px 0px;margin-left:-5px;" type="submit"><i class="icon-search"></i></button> + </div> + </form> + + <!-- query list --> + <ul class="nav nav-list"> + <li class="nav-header"><wicket:message key="gb.queries"></wicket:message></li> + <li><a wicket:id="changesQuery"><i class="fa fa-code-fork"></i> <wicket:message key="gb.proposalTickets"></wicket:message></a></li> + <li><a wicket:id="bugsQuery"><i class="fa fa-bug"></i> <wicket:message key="gb.bugTickets"></wicket:message></a></li> + <li><a wicket:id="enhancementsQuery"><i class="fa fa-magic"></i> <wicket:message key="gb.enhancementTickets"></wicket:message></a></li> + <li><a wicket:id="tasksQuery"><i class="fa fa-ticket"></i> <wicket:message key="gb.taskTickets"></wicket:message></a></li> + <li><a wicket:id="questionsQuery"><i class="fa fa-question"></i> <wicket:message key="gb.questionTickets"></wicket:message></a></li> + <li wicket:id="userDivider" class="divider"></li> + <li><a wicket:id="createdQuery"><i class="fa fa-user"></i> <wicket:message key="gb.yourCreatedTickets"></wicket:message></a></li> + <li><a wicket:id="responsibleQuery"><i class="fa fa-user"></i> <wicket:message key="gb.yourAssignedTickets"></wicket:message></a></li> + <li><a wicket:id="watchedQuery"><i class="fa fa-eye"></i> <wicket:message key="gb.yourWatchedTickets"></wicket:message></a></li> + <li><a wicket:id="mentionsQuery"><i class="fa fa-comment"></i> <wicket:message key="gb.mentionsMeTickets"></wicket:message></a></li> + <li class="divider"></li> + <li><a wicket:id="resetQuery"><i class="fa fa-bolt"></i> <wicket:message key="gb.reset"></wicket:message></a></li> + </ul> + + </div> + </div> + + <!-- tickets --> + <div class="span9"> + <div class="btn-toolbar" style="margin-top: 0px;"> + <div class="btn-group"> + <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"><wicket:message key="gb.status"></wicket:message>: <span style="font-weight:bold;" wicket:id="selectedStatii"></span> <span class="caret"></span></a> + <ul class="dropdown-menu"> + <li><a wicket:id="openTickets"><wicket:message key="gb.open"></wicket:message></a></li> + <li><a wicket:id="closedTickets"><wicket:message key="gb.closed"></wicket:message></a></li> + <li><a wicket:id="allTickets"><wicket:message key="gb.all"></wicket:message></a></li> + <li class="divider"></li> + <li wicket:id="statii"><span wicket:id="statusLink"></span></li> + </ul> + </div> + <div class="btn-group"> + <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-sort"></i> <wicket:message key="gb.sort"></wicket:message>: <span style="font-weight:bold;" wicket:id="currentSort"></span> <span class="caret"></span></a> + <ul class="dropdown-menu"> + <li wicket:id="sort"><span wicket:id="sortLink"></span></li> + </ul> + </div> + + <div class="btn-group pull-right"> + <div class="pagination pagination-right pagination-small"> + <ul> + <li><a wicket:id="prevLink"><i class="fa fa-angle-double-left"></i></a></li> + <li wicket:id="pageLink"><span wicket:id="page"></span></li> + <li><a wicket:id="nextLink"><i class="fa fa-angle-double-right"></i></a></li> + </ul> + </div> + </div> + </div> + + <div wicket:id="ticketList"></div> + </div> + </div> + </div> + </div> + +</wicket:extend> +</body> +</html>
\ 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..c207d561 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -0,0 +1,392 @@ +/* + * 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.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.basic.Label; +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 com.gitblit.Keys; +import com.gitblit.models.TicketModel; +import com.gitblit.models.TicketModel.Status; +import com.gitblit.models.UserModel; +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.GitBlitWebSession; +import com.gitblit.wicket.TicketsUI; +import com.gitblit.wicket.TicketsUI.TicketSort; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.LinkPanel; +import com.gitblit.wicket.panels.TicketListPanel; +import com.gitblit.wicket.panels.TicketSearchForm; +import com.gitblit.wicket.panels.UserTitlePanel; + +/** + * My Tickets page + * + * @author Christian Buisson + * @author James Moger + */ +public class MyTicketsPage extends RootPage { + + public MyTicketsPage() { + this(null); + } + + public MyTicketsPage(PageParameters params) { + super(params); + setupPage("", getString("gb.myTickets")); + + UserModel currentUser = GitBlitWebSession.get().getUser(); + if (currentUser == null || UserModel.ANONYMOUS.equals(currentUser)) { + setRedirect(true); + setResponsePage(getApplication().getHomePage()); + return; + } + + final String username = currentUser.getName(); + final String[] statiiParam = (params == null) ? TicketsUI.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); + 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 the user title panel + add(new UserTitlePanel("userTitlePanel", currentUser, getString("gb.myTickets"))); + + // add search form + add(new TicketSearchForm("ticketSearchForm", null, searchParam, getClass(), params)); + + // standard queries + add(new BookmarkablePageLink<Void>("changesQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Proposal.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink<Void>("bugsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Bug.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink<Void>("enhancementsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Enhancement.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink<Void>("tasksQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Task.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink<Void>("questionsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Question.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink<Void>("resetQuery", MyTicketsPage.class, + queryParameters( + null, + milestoneParam, + TicketsUI.openStatii, + null, + null, + true, + 1))); + + add(new Label("userDivider")); + add(new BookmarkablePageLink<Void>("createdQuery", MyTicketsPage.class, + queryParameters( + Lucene.createdby.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink<Void>("watchedQuery", MyTicketsPage.class, + queryParameters( + Lucene.watchedby.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + add(new BookmarkablePageLink<Void>("mentionsQuery", MyTicketsPage.class, + queryParameters( + Lucene.mentions.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + add(new BookmarkablePageLink<Void>("responsibleQuery", MyTicketsPage.class, + queryParameters( + Lucene.responsible.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<Void>("openTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.openStatii, assignedToParam, sortBy, desc, 1))); + add(new BookmarkablePageLink<Void>("closedTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.closedStatii, assignedToParam, sortBy, desc, 1))); + add(new BookmarkablePageLink<Void>("allTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, 1))); + + // by status + List<Status> statii = new ArrayList<Status>(Arrays.asList(Status.values())); + statii.remove(Status.Closed); + ListDataProvider<Status> resolutionsDp = new ListDataProvider<Status>(statii); + DataView<Status> statiiLinks = new DataView<Status>("statii", resolutionsDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item<Status> item) { + final Status status = item.getModelObject(); + PageParameters p = queryParameters(queryParam, milestoneParam, new String [] { status.name().toLowerCase() }, assignedToParam, sortBy, desc, 1); + String css = TicketsUI.getStatusClass(status); + item.add(new LinkPanel("statusLink", css, status.toString(), MyTicketsPage.class, p).setRenderBodyOnly(true)); + } + }; + add(statiiLinks); + + List<TicketSort> sortChoices = new ArrayList<TicketSort>(); + 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<TicketSort> sortChoicesDp = new ListDataProvider<TicketSort>(sortChoices); + DataView<TicketSort> sortMenu = new DataView<TicketSort>("sort", sortChoicesDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item<TicketSort> 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.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; + 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); + + List<QueryResult> results; + if(StringUtils.isEmpty(searchParam)) { + results = app().tickets().queryFor(luceneQuery, page, pageSize, sortBy, desc); + } else { + results = app().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 boolean showSwatch = app().settings().getBoolean(Keys.web.repositoryListSwatches, true); + add(new TicketListPanel("ticketList", results, showSwatch, true)); + } + + 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<Void>("prevLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav)); + add(new BookmarkablePageLink<Void>("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)); + 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<Integer> sequence = new ArrayList<Integer>(); + for (int i = minpage; i <= maxpage; i++) { + sequence.add(i); + } + + ListDataProvider<Integer> pagesDp = new ListDataProvider<Integer>(sequence); + DataView<Integer> pagesView = new DataView<Integer>("pageLink", pagesDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item<Integer> item) { + final Integer i = item.getModelObject(); + 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"); + } + item.add(link); + } + }; + add(pagesView); + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html index cb4f1b67..22544bc8 100644 --- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html @@ -17,7 +17,7 @@ <form class="form-search" style="margin: 0px;" wicket:id="searchForm">
<div class="input-append">
<select class="span2" style="border-radius: 4px;" wicket:id="searchType"/>
- <input type="text" class="search-query" style="width: 170px;border-radius: 14px 0 0 14px; padding-left: 14px;" id="searchBox" wicket:id="searchBox" value=""/>
+ <input type="text" class="input-medium search-query" style="border-radius: 14px 0 0 14px; padding-left: 14px;" id="searchBox" wicket:id="searchBox" value=""/>
<button class="btn" style="border-radius: 0 14px 14px 0px;margin-left:-5px;" type="submit"><i class="icon-search"></i></button>
</div>
</form>
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java index 2b97bc16..5ea99fd8 100644 --- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java @@ -69,6 +69,7 @@ import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.PageRegistration;
import com.gitblit.wicket.PageRegistration.OtherPageLink;
import com.gitblit.wicket.SessionlessForm;
+import com.gitblit.wicket.TicketsUI;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.LinkPanel;
import com.gitblit.wicket.panels.NavigationPanel;
@@ -204,7 +205,7 @@ public abstract class RepositoryPage extends RootPage { pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
if (app().tickets().isReady() && (app().tickets().isAcceptingNewTickets(getRepositoryModel()) || app().tickets().hasTickets(getRepositoryModel()))) {
PageParameters tParams = new PageParameters(params);
- for (String state : TicketsPage.openStatii) {
+ for (String state : TicketsUI.openStatii) {
tParams.add(Lucene.status.name(), state);
}
pages.put("tickets", new PageRegistration("gb.tickets", TicketsPage.class, tParams)); diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index 5ccc3a4c..c59c1892 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,13 +169,16 @@ public abstract class RootPage extends BasePage { // navigation links
List<PageRegistration> pages = new ArrayList<PageRegistration>();
- 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()));
+ 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 (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) {
+ if (allowLucene) {
pages.add(new PageRegistration("gb.search", LuceneSearchPage.class));
}
if (showAdmin) {
@@ -183,7 +188,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);
}
}
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketBasePage.java b/src/main/java/com/gitblit/wicket/pages/TicketBasePage.java deleted file mode 100644 index 60fa6381..00000000 --- a/src/main/java/com/gitblit/wicket/pages/TicketBasePage.java +++ /dev/null @@ -1,126 +0,0 @@ -/*
- * Copyright 2013 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 org.apache.wicket.PageParameters;
-import org.apache.wicket.markup.html.basic.Label;
-
-import com.gitblit.models.TicketModel;
-import com.gitblit.models.TicketModel.Status;
-import com.gitblit.models.TicketModel.Type;
-import com.gitblit.wicket.WicketUtils;
-
-public abstract class TicketBasePage extends RepositoryPage {
-
- public TicketBasePage(PageParameters params) {
- super(params);
- }
-
- 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;
- }
-}
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java index 659acad0..c066f24d 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java @@ -86,6 +86,7 @@ import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.StringUtils;
import com.gitblit.utils.TimeUtils;
import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.TicketsUI;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.BasePanel.JavascriptTextPrompt;
import com.gitblit.wicket.panels.CommentPanel;
@@ -102,7 +103,7 @@ import com.gitblit.wicket.panels.SimpleAjaxLink; * @author James Moger
*
*/
-public class TicketPage extends TicketBasePage {
+public class TicketPage extends RepositoryPage {
static final String NIL = "<nil>";
@@ -154,7 +155,7 @@ public class TicketPage extends TicketBasePage { String href = urlFor(TicketsPage.class, params).toString();
add(new ExternalLink("ticketNumber", href, "#" + ticket.number));
Label headerStatus = new Label("headerStatus", ticket.status.toString());
- WicketUtils.setCssClass(headerStatus, getLozengeClass(ticket.status, false));
+ WicketUtils.setCssClass(headerStatus, TicketsUI.getLozengeClass(ticket.status, false));
add(headerStatus);
add(new Label("ticketTitle", ticket.title));
if (currentPatchset == null) {
@@ -317,10 +318,10 @@ public class TicketPage extends TicketBasePage { * LARGE STATUS INDICATOR WITH ICON (DISCUSSION TAB->SIDE BAR)
*/
Fragment ticketStatus = new Fragment("ticketStatus", "ticketStatusFragment", this);
- Label ticketIcon = getStateIcon("ticketIcon", ticket);
+ Label ticketIcon = TicketsUI.getStateIcon("ticketIcon", ticket);
ticketStatus.add(ticketIcon);
ticketStatus.add(new Label("ticketStatus", ticket.status.toString()));
- WicketUtils.setCssClass(ticketStatus, getLozengeClass(ticket.status, false));
+ WicketUtils.setCssClass(ticketStatus, TicketsUI.getLozengeClass(ticket.status, false));
add(ticketStatus);
@@ -370,7 +371,7 @@ public class TicketPage extends TicketBasePage { setResponsePage(TicketsPage.class, getPageParameters());
}
};
- String css = getStatusClass(item.getModel().getObject());
+ String css = TicketsUI.getStatusClass(item.getModel().getObject());
WicketUtils.setCssClass(link, css);
item.add(link);
}
@@ -665,7 +666,7 @@ public class TicketPage extends TicketBasePage { */
Fragment frag = new Fragment("entry", "statusFragment", this);
Label status = new Label("statusChange", entry.getStatus().toString());
- String css = getLozengeClass(entry.getStatus(), false);
+ String css = TicketsUI.getLozengeClass(entry.getStatus(), false);
WicketUtils.setCssClass(status, css);
for (IBehavior b : status.getBehaviors()) {
if (b instanceof SimpleAttributeModifier) {
@@ -936,7 +937,7 @@ public class TicketPage extends TicketBasePage { case status:
// special handling for status
Status status = event.getStatus();
- String css = getLozengeClass(status, true);
+ String css = TicketsUI.getLozengeClass(status, true);
value = String.format("<span class=\"%1$s\">%2$s</span>", css, status.toString());
break;
default:
@@ -1525,14 +1526,14 @@ public class TicketPage extends TicketBasePage { switch (type) {
case Rebase:
case Rebase_Squash:
- typeCss = getLozengeClass(Status.Declined, false);
+ typeCss = TicketsUI.getLozengeClass(Status.Declined, false);
break;
case Squash:
case Amend:
- typeCss = getLozengeClass(Status.On_Hold, false);
+ typeCss = TicketsUI.getLozengeClass(Status.On_Hold, false);
break;
case Proposal:
- typeCss = getLozengeClass(Status.New, false);
+ typeCss = TicketsUI.getLozengeClass(Status.New, false);
break;
case FastForward:
default:
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html index a40d3126..40060f36 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html @@ -11,7 +11,7 @@ <div class="hidden-phone pull-right">
<form class="form-search" style="margin: 0px;" wicket:id="ticketSearchForm">
<div class="input-append">
- <input type="text" class="search-query" style="width: 170px;border-radius: 14px 0 0 14px; padding-left: 14px;" id="ticketSearchBox" wicket:id="ticketSearchBox" value=""/>
+ <input type="text" class="input-medium search-query" style="border-radius: 14px 0 0 14px; padding-left: 14px;" id="ticketSearchBox" wicket:id="ticketSearchBox" value=""/>
<button class="btn" style="border-radius: 0 14px 14px 0px;margin-left:-5px;" type="submit"><i class="icon-search"></i></button>
</div>
</form>
@@ -88,42 +88,7 @@ </div>
</div>
-
- <table class="table tickets">
- <tbody>
- <tr wicket:id="ticket">
- <td class="ticket-list-icon">
- <i wicket:id="state"></i>
- </td>
- <td>
- <span wicket:id="title">[title]</span> <span wicket:id="labels" style="font-weight: normal;color:white;"><span class="label" wicket:id="label"></span></span>
- <div class="ticket-list-details">
- <span style="padding-right: 10px;" class="hidden-phone">
- <wicket:message key="gb.createdBy"></wicket:message>
- <span style="padding: 0px 2px" wicket:id="createdBy">[createdBy]</span> <span class="date" wicket:id="createDate">[create date]</span>
- </span>
- <span wicket:id="indicators" style="white-space:nowrap;"><i wicket:id="icon"></i> <span style="padding-right:10px;" wicket:id="count"></span></span>
- </div>
- <div class="hidden-phone" wicket:id="updated"></div>
- </td>
- <td class="ticket-list-state">
- <span class="badge badge-info" wicket:id="votes"></span>
- </td>
- <td class="hidden-phone ticket-list-state">
- <i wicket:message="title:gb.watching" style="color:#888;" class="fa fa-eye" wicket:id="watching"></i>
- </td>
- <td class="ticket-list-state">
- <div wicket:id="status"></div>
- </td>
- <td class="indicators">
- <div>
- <b>#<span wicket:id="id">[id]</span></b>
- </div>
- <div wicket:id="responsible"></div>
- </td>
- </tr>
- </tbody>
- </table>
+ <div wicket:id="ticketList"></div>
<div class="btn-group pull-right">
<div class="pagination pagination-right pagination-small">
@@ -240,13 +205,6 @@ </ul>
</wicket:fragment>
-<wicket:fragment wicket:id="updatedFragment">
- <div class="ticket-list-details">
- <wicket:message key="gb.updatedBy"></wicket:message>
- <span style="padding: 0px 2px" wicket:id="updatedBy">[updatedBy]</span> <span class="date" wicket:id="updateDate">[update date]</span>
- </div>
-</wicket:fragment>
-
</wicket:extend>
</body>
</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index 5973d473..d88ccb6b 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -15,7 +15,6 @@ */
package com.gitblit.wicket.pages;
-import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -29,17 +28,12 @@ import org.apache.wicket.Component; import org.apache.wicket.PageParameters;
import org.apache.wicket.behavior.SimpleAttributeModifier;
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.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.ListDataProvider;
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.request.target.basic.RedirectRequestTarget;
-import com.gitblit.Constants;
import com.gitblit.Constants.AccessPermission;
import com.gitblit.Keys;
import com.gitblit.models.RegistrantAccessPermission;
@@ -56,19 +50,18 @@ import com.gitblit.tickets.TicketResponsible; import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
-import com.gitblit.wicket.SessionlessForm;
+import com.gitblit.wicket.TicketsUI;
+import com.gitblit.wicket.TicketsUI.TicketQuery;
+import com.gitblit.wicket.TicketsUI.TicketSort;
import com.gitblit.wicket.WicketUtils;
-import com.gitblit.wicket.panels.GravatarImage;
import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.TicketListPanel;
+import com.gitblit.wicket.panels.TicketSearchForm;
-public class TicketsPage extends TicketBasePage {
+public class TicketsPage extends RepositoryPage {
final TicketResponsible any;
- 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 TicketsPage(PageParameters params) {
super(params);
@@ -102,11 +95,8 @@ public class TicketsPage extends TicketBasePage { final String sortBy = Lucene.fromString(params.getString("sort", Lucene.created.name())).name();
final boolean desc = !"asc".equals(params.getString("direction", "desc"));
-
// add search form
- TicketSearchForm searchForm = new TicketSearchForm("ticketSearchForm", repositoryName, searchParam);
- add(searchForm);
- searchForm.setTranslatedAttributes();
+ add(new TicketSearchForm("ticketSearchForm", repositoryName, searchParam, getClass(), params));
final String activeQuery;
if (!StringUtils.isEmpty(searchParam)) {
@@ -192,12 +182,12 @@ public class TicketsPage extends TicketBasePage { milestonePanel.add(new LinkPanel("openTickets", null,
MessageFormat.format(getString("gb.nOpenTickets"), currentMilestone.getOpenTickets()),
TicketsPage.class,
- queryParameters(null, currentMilestone.name, openStatii, null, sortBy, desc, 1)));
+ queryParameters(null, currentMilestone.name, TicketsUI.openStatii, null, sortBy, desc, 1)));
milestonePanel.add(new LinkPanel("closedTickets", null,
MessageFormat.format(getString("gb.nClosedTickets"), currentMilestone.getClosedTickets()),
TicketsPage.class,
- queryParameters(null, currentMilestone.name, closedStatii, null, sortBy, desc, 1)));
+ queryParameters(null, currentMilestone.name, TicketsUI.closedStatii, null, sortBy, desc, 1)));
milestonePanel.add(new Label("totalTickets", MessageFormat.format(getString("gb.nTotalTickets"), currentMilestone.getTotalTickets())));
add(milestonePanel);
@@ -287,7 +277,7 @@ public class TicketsPage extends TicketBasePage { queryParameters(
null,
milestoneParam,
- openStatii,
+ TicketsUI.openStatii,
null,
null,
true,
@@ -397,8 +387,8 @@ public class TicketsPage extends TicketBasePage { } else {
add(new Label("selectedStatii", StringUtils.flattenStrings(Arrays.asList(statiiParam), ",")));
}
- add(new BookmarkablePageLink<Void>("openTickets", TicketsPage.class, queryParameters(queryParam, milestoneParam, openStatii, assignedToParam, sortBy, desc, 1)));
- add(new BookmarkablePageLink<Void>("closedTickets", TicketsPage.class, queryParameters(queryParam, milestoneParam, closedStatii, assignedToParam, sortBy, desc, 1)));
+ add(new BookmarkablePageLink<Void>("openTickets", TicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.openStatii, assignedToParam, sortBy, desc, 1)));
+ add(new BookmarkablePageLink<Void>("closedTickets", TicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.closedStatii, assignedToParam, sortBy, desc, 1)));
add(new BookmarkablePageLink<Void>("allTickets", TicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, 1)));
// by status
@@ -412,7 +402,7 @@ public class TicketsPage extends TicketBasePage { public void populateItem(final Item<Status> item) {
final Status status = item.getModelObject();
PageParameters p = queryParameters(queryParam, milestoneParam, new String [] { status.name().toLowerCase() }, assignedToParam, sortBy, desc, 1);
- String css = getStatusClass(status);
+ String css = TicketsUI.getStatusClass(status);
item.add(new LinkPanel("statusLink", css, status.toString(), TicketsPage.class, p).setRenderBodyOnly(true));
}
};
@@ -491,162 +481,7 @@ public class TicketsPage extends TicketBasePage { // paging links
buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults);
- ListDataProvider<QueryResult> resultsDataProvider = new ListDataProvider<QueryResult>(results);
- DataView<QueryResult> ticketsView = new DataView<QueryResult>("ticket", resultsDataProvider) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void populateItem(final Item<QueryResult> item) {
- final QueryResult ticket = item.getModelObject();
- item.add(getStateIcon("state", ticket.type, ticket.status));
- item.add(new Label("id", "" + ticket.number));
- UserModel creator = app().users().getUserModel(ticket.createdBy);
- if (creator != null) {
- item.add(new LinkPanel("createdBy", null, creator.getDisplayName(),
- UserPage.class, WicketUtils.newUsernameParameter(ticket.createdBy)));
- } else {
- item.add(new Label("createdBy", ticket.createdBy));
- }
- item.add(WicketUtils.createDateLabel("createDate", ticket.createdAt, GitBlitWebSession
- .get().getTimezone(), getTimeUtils(), false));
-
- if (ticket.updatedAt == null) {
- item.add(new Label("updated").setVisible(false));
- } else {
- Fragment updated = new Fragment("updated", "updatedFragment", this);
- UserModel updater = app().users().getUserModel(ticket.updatedBy);
- if (updater != null) {
- updated.add(new LinkPanel("updatedBy", null, updater.getDisplayName(),
- UserPage.class, WicketUtils.newUsernameParameter(ticket.updatedBy)));
- } else {
- updated.add(new Label("updatedBy", ticket.updatedBy));
- }
- updated.add(WicketUtils.createDateLabel("updateDate", ticket.updatedAt, GitBlitWebSession
- .get().getTimezone(), getTimeUtils(), false));
- item.add(updated);
- }
-
- item.add(new LinkPanel("title", "list subject", StringUtils.trimString(
- ticket.title, Constants.LEN_SHORTLOG), TicketsPage.class, newTicketParameter(ticket)));
-
- ListDataProvider<String> labelsProvider = new ListDataProvider<String>(ticket.getLabels());
- DataView<String> labelsView = new DataView<String>("labels", labelsProvider) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void populateItem(final Item<String> labelItem) {
- String content = bugtraqProcessor().processPlainCommitMessage(getRepository(), repositoryName, labelItem.getModelObject());
- Label label = new Label("label", content);
- label.setEscapeModelStrings(false);
- TicketLabel tLabel = app().tickets().getLabel(getRepositoryModel(), labelItem.getModelObject());
- String background = MessageFormat.format("background-color:{0};", tLabel.color);
- label.add(new SimpleAttributeModifier("style", background));
- labelItem.add(label);
- }
- };
- item.add(labelsView);
-
- if (StringUtils.isEmpty(ticket.responsible)) {
- item.add(new Label("responsible").setVisible(false));
- } else {
- UserModel responsible = app().users().getUserModel(ticket.responsible);
- if (responsible == null) {
- responsible = new UserModel(ticket.responsible);
- }
- GravatarImage avatar = new GravatarImage("responsible", responsible.getDisplayName(),
- responsible.emailAddress, null, 16, true);
- avatar.setTooltip(getString("gb.responsible") + ": " + responsible.getDisplayName());
- item.add(avatar);
- }
-
- // votes indicator
- Label v = new Label("votes", "" + ticket.votesCount);
- WicketUtils.setHtmlTooltip(v, getString("gb.votes"));
- item.add(v.setVisible(ticket.votesCount > 0));
-
- // watching indicator
- item.add(new Label("watching").setVisible(ticket.isWatching(GitBlitWebSession.get().getUsername())));
-
- // status indicator
- String css = getLozengeClass(ticket.status, true);
- Label l = new Label("status", ticket.status.toString());
- WicketUtils.setCssClass(l, css);
- item.add(l);
-
- // add the ticket indicators/icons
- List<Indicator> indicators = new ArrayList<Indicator>();
-
- // comments
- if (ticket.commentsCount > 0) {
- int count = ticket.commentsCount;
- String pattern = "gb.nComments";
- if (count == 1) {
- pattern = "gb.oneComment";
- }
- indicators.add(new Indicator("fa fa-comment", count, pattern));
- }
-
- // participants
- if (!ArrayUtils.isEmpty(ticket.participants)) {
- int count = ticket.participants.size();
- if (count > 1) {
- String pattern = "gb.nParticipants";
- indicators.add(new Indicator("fa fa-user", count, pattern));
- }
- }
-
- // attachments
- if (!ArrayUtils.isEmpty(ticket.attachments)) {
- int count = ticket.attachments.size();
- String pattern = "gb.nAttachments";
- if (count == 1) {
- pattern = "gb.oneAttachment";
- }
- indicators.add(new Indicator("fa fa-file", count, pattern));
- }
-
- // patchset revisions
- if (ticket.patchset != null) {
- int count = ticket.patchset.commits;
- String pattern = "gb.nCommits";
- if (count == 1) {
- pattern = "gb.oneCommit";
- }
- indicators.add(new Indicator("fa fa-code", count, pattern));
- }
-
- // milestone
- if (!StringUtils.isEmpty(ticket.milestone)) {
- indicators.add(new Indicator("fa fa-bullseye", ticket.milestone));
- }
-
- ListDataProvider<Indicator> indicatorsDp = new ListDataProvider<Indicator>(indicators);
- DataView<Indicator> indicatorsView = new DataView<Indicator>("indicators", indicatorsDp) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void populateItem(final Item<Indicator> item) {
- Indicator indicator = item.getModelObject();
- String tooltip = indicator.getTooltip();
-
- Label icon = new Label("icon");
- WicketUtils.setCssClass(icon, indicator.css);
- item.add(icon);
-
- if (indicator.count > 0) {
- Label count = new Label("count", "" + indicator.count);
- item.add(count.setVisible(!StringUtils.isEmpty(tooltip)));
- } else {
- item.add(new Label("count").setVisible(false));
- }
-
- WicketUtils.setHtmlTooltip(item, tooltip);
- }
- };
- item.add(indicatorsView);
- }
- };
- add(ticketsView);
+ add(new TicketListPanel("ticketList", results, false, false));
// new milestone link
RepositoryModel repositoryModel = getRepositoryModel();
@@ -747,12 +582,12 @@ public class TicketsPage extends TicketBasePage { milestonePanel.add(new LinkPanel("openTickets", null,
MessageFormat.format(getString("gb.nOpenTickets"), m.getOpenTickets()),
TicketsPage.class,
- queryParameters(null, tm.name, openStatii, null, null, true, 1)));
+ queryParameters(null, tm.name, TicketsUI.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)));
+ queryParameters(null, tm.name, TicketsUI.closedStatii, null, null, true, 1)));
milestonePanel.add(new Label("totalTickets", MessageFormat.format(getString("gb.nTotalTickets"), m.getTotalTickets())));
entryPanel.add(milestonePanel);
@@ -864,123 +699,4 @@ public class TicketsPage extends TicketBasePage { };
add(pagesView);
}
-
- private class Indicator implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- final String css;
- final int count;
- final String tooltip;
-
- Indicator(String css, String tooltip) {
- this.css = css;
- this.tooltip = tooltip;
- this.count = 0;
- }
-
- Indicator(String css, int count, String pattern) {
- this.css = css;
- this.count = count;
- this.tooltip = StringUtils.isEmpty(pattern) ? "" : MessageFormat.format(getString(pattern), count);
- }
-
- String getTooltip() {
- return tooltip;
- }
- }
-
- private class TicketQuery implements Serializable, Comparable<TicketQuery> {
-
- private static final long serialVersionUID = 1L;
-
- final String name;
- final String query;
- String color;
-
- TicketQuery(String name, String query) {
- this.name = name;
- this.query = query;
- }
-
- TicketQuery color(String value) {
- this.color = value;
- return this;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof TicketQuery) {
- return ((TicketQuery) o).query.equals(query);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return query.hashCode();
- }
-
- @Override
- public int compareTo(TicketQuery o) {
- return query.compareTo(o.query);
- }
- }
-
- 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<Void> implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private final String repositoryName;
-
- private final IModel<String> searchBoxModel;;
-
- public TicketSearchForm(String id, String repositoryName, String text) {
- super(id, TicketsPage.this.getClass(), TicketsPage.this.getPageParameters());
-
- this.repositoryName = repositoryName;
- this.searchBoxModel = new Model<String>(text == null ? "" : text);
-
- TextField<String> searchBox = new TextField<String>("ticketSearchBox", searchBoxModel);
- add(searchBox);
- }
-
- void setTranslatedAttributes() {
- WicketUtils.setHtmlTooltip(get("ticketSearchBox"),
- MessageFormat.format(getString("gb.searchTicketsTooltip"), repositoryName));
- 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(repositoryName);
- params.add("s", searchString);
- String absoluteUrl = getCanonicalUrl(TicketsPage.class, params);
- getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
- }
- }
}
diff --git a/src/main/java/com/gitblit/wicket/panels/TicketListPanel.html b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.html new file mode 100644 index 00000000..6e6d2091 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.html @@ -0,0 +1,55 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<body>
+<wicket:panel>
+<table class="table tickets">
+ <tbody>
+ <tr wicket:id="row">
+ <td class="ticket-list-icon">
+ <i wicket:id="state"></i>
+ </td>
+ <td>
+ <span wicket:id="title">[title]</span> <span wicket:id="labels" style="font-weight: normal;color:white;"><span class="label" wicket:id="label"></span></span>
+ <div class="ticket-list-details">
+ <span style="padding-right: 10px;" class="hidden-phone">
+ <wicket:message key="gb.createdBy"></wicket:message>
+ <span style="padding: 0px 2px" wicket:id="createdBy">[createdBy]</span> <span class="date" wicket:id="createDate">[create date]</span>
+ </span>
+ <span wicket:id="indicators" style="white-space:nowrap;"><i wicket:id="icon"></i> <span style="padding-right:10px;" wicket:id="count"></span></span>
+ </div>
+ <div class="hidden-phone" wicket:id="updated"></div>
+ <div class="ticket-list-details"><span class="activitySwatch" wicket:id="repositoryLink">[repository link]</span></div>
+ </td>
+ <td class="ticket-list-state">
+ <span class="badge badge-info" wicket:id="votes"></span>
+ </td>
+ <td class="hidden-phone ticket-list-state">
+ <i wicket:message="title:gb.watching" style="color:#888;" class="fa fa-eye" wicket:id="watching"></i>
+ </td>
+ <td class="ticket-list-state">
+ <div wicket:id="status"></div>
+ </td>
+ <td class="indicators">
+ <div>
+ <b>#<span wicket:id="id">[id]</span></b>
+ </div>
+ <div wicket:id="responsible"></div>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<wicket:fragment wicket:id="updatedFragment">
+ <div class="ticket-list-details">
+ <wicket:message key="gb.updatedBy"></wicket:message>
+ <span style="padding: 0px 2px" wicket:id="updatedBy">[updatedBy]</span> <span class="date" wicket:id="updateDate">[update date]</span>
+ </div>
+</wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/TicketListPanel.java b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.java new file mode 100644 index 00000000..fc0431fb --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TicketListPanel.java @@ -0,0 +1,243 @@ +/* + * 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.panels; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.behavior.SimpleAttributeModifier; +import org.apache.wicket.markup.html.basic.Label; +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.ListDataProvider; +import org.eclipse.jgit.lib.Repository; + +import com.gitblit.Constants; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.tickets.QueryResult; +import com.gitblit.tickets.TicketLabel; +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.BugtraqProcessor; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.TicketsUI; +import com.gitblit.wicket.TicketsUI.Indicator; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.pages.SummaryPage; +import com.gitblit.wicket.pages.TicketsPage; +import com.gitblit.wicket.pages.UserPage; + +/** + * + * The ticket list panel lists tickets in a table. + * + * @author James Moger + * + */ +public class TicketListPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + public TicketListPanel(String wicketId, List<QueryResult> list, final boolean showSwatch, final boolean showRepository) { + super(wicketId); + + final ListDataProvider<QueryResult> dp = new ListDataProvider<QueryResult>(list); + DataView<QueryResult> dataView = new DataView<QueryResult>("row", dp) { + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(Item<QueryResult> item) { + final QueryResult ticket = item.getModelObject(); + final RepositoryModel repository = app().repositories().getRepositoryModel(ticket.repository); + + if (showSwatch) { + // set repository color + String color = StringUtils.getColor(StringUtils.stripDotGit(repository.name)); + WicketUtils.setCssStyle(item, MessageFormat.format("border-left: 2px solid {0};", color)); + } + + PageParameters rp = WicketUtils.newRepositoryParameter(ticket.repository); + PageParameters tp = WicketUtils.newObjectParameter(ticket.repository, "" + ticket.number); + + if (showRepository) { + String name = StringUtils.stripDotGit(ticket.repository); + LinkPanel link = new LinkPanel("repositoryLink", null, name, SummaryPage.class, rp); + WicketUtils.setCssBackground(link, name); + item.add(link); + } else { + item.add(new Label("repositoryLink").setVisible(false)); + } + + item.add(TicketsUI.getStateIcon("state", ticket.type, ticket.status)); + item.add(new Label("id", "" + ticket.number)); + UserModel creator = app().users().getUserModel(ticket.createdBy); + if (creator != null) { + item.add(new LinkPanel("createdBy", null, creator.getDisplayName(), + UserPage.class, WicketUtils.newUsernameParameter(ticket.createdBy))); + } else { + item.add(new Label("createdBy", ticket.createdBy)); + } + item.add(WicketUtils.createDateLabel("createDate", ticket.createdAt, GitBlitWebSession + .get().getTimezone(), getTimeUtils(), false)); + + if (ticket.updatedAt == null) { + item.add(new Label("updated").setVisible(false)); + } else { + Fragment updated = new Fragment("updated", "updatedFragment", this); + UserModel updater = app().users().getUserModel(ticket.updatedBy); + if (updater != null) { + updated.add(new LinkPanel("updatedBy", null, updater.getDisplayName(), + UserPage.class, WicketUtils.newUsernameParameter(ticket.updatedBy))); + } else { + updated.add(new Label("updatedBy", ticket.updatedBy)); + } + updated.add(WicketUtils.createDateLabel("updateDate", ticket.updatedAt, GitBlitWebSession + .get().getTimezone(), getTimeUtils(), false)); + item.add(updated); + } + + item.add(new LinkPanel("title", "list subject", StringUtils.trimString( + ticket.title, Constants.LEN_SHORTLOG), TicketsPage.class, tp)); + + ListDataProvider<String> labelsProvider = new ListDataProvider<String>(ticket.getLabels()); + DataView<String> labelsView = new DataView<String>("labels", labelsProvider) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item<String> labelItem) { + BugtraqProcessor btp = new BugtraqProcessor(app().settings()); + Repository db = app().repositories().getRepository(repository.name); + String content = btp.processPlainCommitMessage(db, repository.name, labelItem.getModelObject()); + db.close(); + Label label = new Label("label", content); + label.setEscapeModelStrings(false); + TicketLabel tLabel = app().tickets().getLabel(repository, labelItem.getModelObject()); + String background = MessageFormat.format("background-color:{0};", tLabel.color); + label.add(new SimpleAttributeModifier("style", background)); + labelItem.add(label); + } + }; + item.add(labelsView); + + if (StringUtils.isEmpty(ticket.responsible)) { + item.add(new Label("responsible").setVisible(false)); + } else { + UserModel responsible = app().users().getUserModel(ticket.responsible); + if (responsible == null) { + responsible = new UserModel(ticket.responsible); + } + GravatarImage avatar = new GravatarImage("responsible", responsible.getDisplayName(), + responsible.emailAddress, null, 16, true); + avatar.setTooltip(getString("gb.responsible") + ": " + responsible.getDisplayName()); + item.add(avatar); + } + + // votes indicator + Label v = new Label("votes", "" + ticket.votesCount); + WicketUtils.setHtmlTooltip(v, getString("gb.votes")); + item.add(v.setVisible(ticket.votesCount > 0)); + + // watching indicator + item.add(new Label("watching").setVisible(ticket.isWatching(GitBlitWebSession.get().getUsername()))); + + // status indicator + String css = TicketsUI.getLozengeClass(ticket.status, true); + Label l = new Label("status", ticket.status.toString()); + WicketUtils.setCssClass(l, css); + item.add(l); + + // add the ticket indicators/icons + List<Indicator> indicators = new ArrayList<Indicator>(); + + // comments + if (ticket.commentsCount > 0) { + int count = ticket.commentsCount; + String pattern = getString("gb.nComments"); + if (count == 1) { + pattern = getString("gb.oneComment"); + } + indicators.add(new Indicator("fa fa-comment", count, pattern)); + } + + // participants + if (!ArrayUtils.isEmpty(ticket.participants)) { + int count = ticket.participants.size(); + if (count > 1) { + String pattern = getString("gb.nParticipants"); + indicators.add(new Indicator("fa fa-user", count, pattern)); + } + } + + // attachments + if (!ArrayUtils.isEmpty(ticket.attachments)) { + int count = ticket.attachments.size(); + String pattern = getString("gb.nAttachments"); + if (count == 1) { + pattern = getString("gb.oneAttachment"); + } + indicators.add(new Indicator("fa fa-file", count, pattern)); + } + + // patchset revisions + if (ticket.patchset != null) { + int count = ticket.patchset.commits; + String pattern = getString("gb.nCommits"); + if (count == 1) { + pattern = getString("gb.oneCommit"); + } + indicators.add(new Indicator("fa fa-code", count, pattern)); + } + + // milestone + if (!StringUtils.isEmpty(ticket.milestone)) { + indicators.add(new Indicator("fa fa-bullseye", ticket.milestone)); + } + + ListDataProvider<Indicator> indicatorsDp = new ListDataProvider<Indicator>(indicators); + DataView<Indicator> indicatorsView = new DataView<Indicator>("indicators", indicatorsDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item<Indicator> item) { + Indicator indicator = item.getModelObject(); + String tooltip = indicator.getTooltip(); + + Label icon = new Label("icon"); + WicketUtils.setCssClass(icon, indicator.css); + item.add(icon); + + if (indicator.count > 0) { + Label count = new Label("count", "" + indicator.count); + item.add(count.setVisible(!StringUtils.isEmpty(tooltip))); + } else { + item.add(new Label("count").setVisible(false)); + } + + WicketUtils.setHtmlTooltip(item, tooltip); + } + }; + item.add(indicatorsView); + } + }; + + add(dataView); + } +} + diff --git a/src/main/java/com/gitblit/wicket/panels/TicketSearchForm.java b/src/main/java/com/gitblit/wicket/panels/TicketSearchForm.java new file mode 100644 index 00000000..21bf1bab --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TicketSearchForm.java @@ -0,0 +1,78 @@ +/* + * 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.panels; + +import java.io.Serializable; +import java.text.MessageFormat; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.target.basic.RedirectRequestTarget; + +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.SessionlessForm; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.pages.BasePage; + +public class TicketSearchForm extends SessionlessForm<Void> implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String repositoryName; + + private final IModel<String> searchBoxModel; + + public TicketSearchForm(String id, String repositoryName, String text, + Class<? extends BasePage> pageClass, PageParameters params) { + + super(id, pageClass, params); + + this.repositoryName = repositoryName; + this.searchBoxModel = new Model<String>(text == null ? "" : text); + + TextField<String> searchBox = new TextField<String>("ticketSearchBox", searchBoxModel); + add(searchBox); + } + + @Override + protected + void onInitialize() { + super.onInitialize(); + 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 = getAbsoluteUrl(); + 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(repositoryName); + params.add("s", searchString); + String absoluteUrl = getAbsoluteUrl(pageClass, params); + getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); + } +} diff --git a/src/main/java/com/gitblit/wicket/panels/UserTitlePanel.html b/src/main/java/com/gitblit/wicket/panels/UserTitlePanel.html new file mode 100644 index 00000000..432c880c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/UserTitlePanel.html @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<body>
+<wicket:panel>
+<div style="display:inline-block;vertical-align:top;padding: 0px 2px 2px;"><img wicket:id="userGravatar"></img></div>
+ <div style="display:inline-block;">
+ <div style="font-size:1.5em;" wicket:id="userDisplayName"></div>
+ <div style="color:#888;font-size:1.2em;padding-top:4px;"><span wicket:id="userTitle"></span></div>
+</div>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/UserTitlePanel.java b/src/main/java/com/gitblit/wicket/panels/UserTitlePanel.java new file mode 100644 index 00000000..2bf5ee7b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/UserTitlePanel.java @@ -0,0 +1,32 @@ +/*
+ * 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.panels;
+
+import org.apache.wicket.markup.html.basic.Label;
+
+import com.gitblit.models.UserModel;
+
+public class UserTitlePanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public UserTitlePanel(String wicketId, UserModel user, String title) {
+ super(wicketId);
+ add(new GravatarImage("userGravatar", user, "gravatar", 36, false));
+ add(new Label("userDisplayName", user.getDisplayName()));
+ add(new Label("userTitle", title));
+ }
+}
|