releases.moxie
@@ -26,6 +26,7 @@ - Use standard ServletRequestWrapper instead of custom wrapper (issue 224) changes: - Improved the repository url display. This display now indicates your repository access permission, per-protocol. - Improve Gerrit change ref decoration in the refs panel (issue 206) - Disable Gson's pretty printing which has a huge performance gain - Properly set application/json content-type on api calls @@ -33,6 +34,7 @@ - Updated Japanese translation additions: - Added 3rd-party app clone links for SourceTree and SparkleShare - Added GO http/https connector thread pool size setting - Added a server setting to force a particular translation/Locale for all sessions - Added smart Git Daemon serving. If enabled, git:// access will be offered for any repository which permits anonymous access. If the repository permits anonymous cloning, anonymous git:// clone will be permitted while anonmymous git:// pushes will be rejected. @@ -81,6 +83,7 @@ - { name: 'git.daemonBindInterface', defaultValue: 'localhost' } - { name: 'git.daemonPort', defaultValue: 0 } - { name: 'git.defaultIncrementalPushTagPrefix', defaultValue: 'r' } - { name: 'web.allowAppCloneLinks', defaultValue: true } - { name: 'web.forceDefaultLocale', defaultValue: ' ' } - { name: 'server.nioThreadPoolSize', defaultValue: 50 } } src/main/distrib/data/gitblit.properties
@@ -766,6 +766,11 @@ # SINCE 0.5.0 web.otherUrls = # Should app-specific clone links be displayed for SourceTree, SparkleShare, etc? # # SINCE 1.3.0 web.allowAppCloneLinks = true # Choose how to present the repositories list. # grouped = group nested/subfolder repositories together (no sorting) # flat = flat list of repositories (sorting allowed) src/main/java/com/gitblit/GitBlitServer.java
src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -452,4 +452,7 @@ gb.externalPermissions = {0} access permissions for {1} are externally maintained gb.viewAccess = You do not have Gitblit read or write access gb.yourProtocolPermissionIs = Your {0} access permission for {1} is {2} gb.sparkleshareInvite = SparkleShare invite gb.cloneWithSparkleShare = clone with SparkleShare\u2122 gb.cloneWithSourceTree = clone with SourceTree\u2122 gb.cloneWithGitHub = clone with GitHub\u2122 for {0} gb.cloneWithSmartGit = clone with SmartGit\u2122 src/main/java/com/gitblit/wicket/pages/BasePage.java
@@ -57,7 +57,6 @@ import com.gitblit.Constants.FederationStrategy; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.SparkleShareInviteServlet; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TeamModel; @@ -311,32 +310,6 @@ // git daemon is not running return new Label(wicketId).setVisible(false); } } protected String getSparkleShareInviteUrl(RepositoryModel repository) { if (repository.isBare && repository.isSparkleshared()) { UserModel user = GitBlitWebSession.get().getUser(); if (user == null) { user = UserModel.ANONYMOUS; } String username = null; if (UserModel.ANONYMOUS != user) { username = user.username; } if (GitBlit.getBoolean(Keys.git.enableGitServlet, true) || (GitBlit.getInteger(Keys.git.daemonPort, 0) > 0)) { // Gitblit as server // ensure user can rewind if (user.canRewindRef(repository)) { String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); return SparkleShareInviteServlet.asLink(baseURL, repository.name, username); } } else { // Gitblit as viewer, assume RW+ permission String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); return SparkleShareInviteServlet.asLink(baseURL, repository.name, username); } } return null; } protected List<ProjectModel> getProjectModels() { src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java
@@ -16,22 +16,17 @@ package com.gitblit.wicket.pages; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label; import com.gitblit.Constants.AccessPermission; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.GitblitRedirectException; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.DetailedRepositoryUrlPanel; import com.gitblit.wicket.panels.RepositoryUrlPanel; public class EmptyRepositoryPage extends RootPage { @@ -53,24 +48,17 @@ setupPage(repositoryName, getString("gb.emptyRepository")); List<String> repositoryUrls = new ArrayList<String>(); if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) { // add the Gitblit repository url repositoryUrls.add(getRepositoryUrl(repository)); } UserModel user = GitBlitWebSession.get().getUser(); if (user == null) { user = UserModel.ANONYMOUS; } repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repositoryName, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.get(0); AccessPermission accessPermission = user.getRepositoryPermission(repository).permission; RepositoryUrlPanel urlPanel = new RepositoryUrlPanel("pushurl", false, user, repository, getLocalizer(), this); String primaryUrl = urlPanel.getPrimaryUrl(); add(new Label("repository", repositoryName)); add(new DetailedRepositoryUrlPanel("pushurl", getLocalizer(), this, repository.name, primaryUrl, accessPermission)); add(new Label("cloneSyntax", MessageFormat.format("git clone {0}", repositoryUrls.get(0)))); add(urlPanel); add(new Label("cloneSyntax", MessageFormat.format("git clone {0}", primaryUrl))); add(new Label("remoteSyntax", MessageFormat.format("git remote add gitblit {0}\ngit push gitblit master", primaryUrl))); } } src/main/java/com/gitblit/wicket/pages/SummaryPage.html
@@ -21,12 +21,10 @@ <tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="branchStats">[branch stats]</span> <span class="link"><a wicket:id="metrics"><wicket:message key="gb.metrics">[metrics]</wicket:message></a></span></td></tr> <tr><th style="vertical-align:top;padding-top:4px;"><wicket:message key="gb.repositoryUrl">[URL]</wicket:message> <img style="vertical-align: top;padding-left:3px;" wicket:id="accessRestrictionIcon" /></th> <td style="padding-top:4px;"> <div wicket:id="repositoryPrimaryUrl">[repository primary url]</div> <div wicket:id="repositoryGitDaemonUrl">[repository git daemon url]</div> <div wicket:id="repositoryUrlPanel">[repository url panel]</div> <div wicket:id="otherUrls" > <div wicket:id="otherUrl" style="padding-top:10px"></div> </div> <div wicket:id="repositorySparkleShareInviteUrl">[repository sparkleshare invite url]</div> </td> </tr> </table> src/main/java/com/gitblit/wicket/pages/SummaryPage.java
@@ -42,7 +42,6 @@ import org.wicketstuff.googlecharts.MarkerType; import org.wicketstuff.googlecharts.ShapeMarker; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.GitBlit; import com.gitblit.Keys; @@ -50,7 +49,6 @@ import com.gitblit.models.PathModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.StringUtils; @@ -60,7 +58,7 @@ import com.gitblit.wicket.panels.DetailedRepositoryUrlPanel; import com.gitblit.wicket.panels.LinkPanel; import com.gitblit.wicket.panels.LogPanel; import com.gitblit.wicket.panels.SparkleShareInvitePanel; import com.gitblit.wicket.panels.RepositoryUrlPanel; import com.gitblit.wicket.panels.TagsPanel; public class SummaryPage extends RepositoryPage { @@ -127,11 +125,7 @@ add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class, WicketUtils.newRepositoryParameter(repositoryName))); List<String> repositoryUrls = new ArrayList<String>(); AccessPermission accessPermission = null; if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) { accessPermission = user.getRepositoryPermission(model).permission; AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction; switch (accessRestriction) { case NONE: @@ -152,32 +146,14 @@ default: add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); } // add the Gitblit repository url repositoryUrls.add(getRepositoryUrl(getRepositoryModel())); } else { add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); } repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repositoryName, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.remove(0); add(new DetailedRepositoryUrlPanel("repositoryPrimaryUrl", getLocalizer(), this, model.name, primaryUrl, accessPermission)); add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model, getLocalizer(), this)); Component gitDaemonUrlPanel = createGitDaemonUrlPanel("repositoryGitDaemonUrl", user, model); if (!StringUtils.isEmpty(primaryUrl) && gitDaemonUrlPanel instanceof DetailedRepositoryUrlPanel) { WicketUtils.setCssStyle(gitDaemonUrlPanel, "padding-top: 10px"); } add(gitDaemonUrlPanel); String sparkleshareUrl = getSparkleShareInviteUrl(model); if (StringUtils.isEmpty(sparkleshareUrl)) { add(new Label("repositorySparkleShareInviteUrl").setVisible(false)); } else { Component sparklesharePanel = new SparkleShareInvitePanel("repositorySparkleShareInviteUrl", getLocalizer(), this, sparkleshareUrl, accessPermission); WicketUtils.setCssStyle(sparklesharePanel, "padding-top: 10px;"); add(sparklesharePanel); } ListDataProvider<String> urls = new ListDataProvider<String>(repositoryUrls); List<String> otherUrls = GitBlit.self().getOtherCloneUrls(repositoryName, UserModel.ANONYMOUS.equals(user) ? "" : user.username); ListDataProvider<String> urls = new ListDataProvider<String>(otherUrls); DataView<String> otherUrlsView = new DataView<String>("otherUrls", urls) { private static final long serialVersionUID = 1L; src/main/java/com/gitblit/wicket/panels/BasePanel.java
@@ -22,6 +22,7 @@ import org.apache.wicket.Component; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; import org.apache.wicket.protocol.http.request.WebClientInfo; import com.gitblit.Constants; import com.gitblit.GitBlit; @@ -58,6 +59,19 @@ return timeUtils; } protected boolean isWindows() { return isPlatform("windows"); } protected boolean isMac() { return isPlatform("macintosh"); } protected boolean isPlatform(String platform) { String ua = ((WebClientInfo) GitBlitWebSession.get().getClientInfo()).getUserAgent(); return ua.toLowerCase().contains(platform); } protected void setPersonSearchTooltip(Component component, String value, Constants.SearchType searchType) { if (searchType.equals(Constants.SearchType.AUTHOR)) { WicketUtils.setHtmlTooltip(component, getString("gb.searchForAuthor") + " " + value); src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java
@@ -16,8 +16,6 @@ package com.gitblit.wicket.panels; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.wicket.Component; @@ -29,7 +27,6 @@ import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.panel.Fragment; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.GitBlit; import com.gitblit.Keys; @@ -40,7 +37,6 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.pages.BasePage; import com.gitblit.wicket.pages.DocsPage; import com.gitblit.wicket.pages.EditRepositoryPage; import com.gitblit.wicket.pages.LogPage; @@ -58,7 +54,6 @@ super(wicketId); final boolean showSwatch = GitBlit.getBoolean(Keys.web.repositoryListSwatches, true); final boolean gitServlet = GitBlit.getBoolean(Keys.git.enableGitServlet, true); final boolean showSize = GitBlit.getBoolean(Keys.web.showRepositorySizes, true); // repository swatch @@ -217,15 +212,6 @@ add(new ExternalLink("syndication", SyndicationServlet.asLink("", entry.name, null, 0))); List<String> repositoryUrls = new ArrayList<String>(); if (gitServlet) { // add the Gitblit repository url repositoryUrls.add(BasePage.getRepositoryUrl(entry)); } repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(entry.name, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); AccessPermission ap = user.getRepositoryPermission(entry).permission; String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.remove(0); add(new DetailedRepositoryUrlPanel("repositoryPrimaryUrl",localizer, parent, entry.name, primaryUrl, ap)); add(new RepositoryUrlPanel("repositoryPrimaryUrl", true, user, entry, localizer, parent)); } } src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.html
@@ -5,26 +5,14 @@ lang="en"> <wicket:panel> <span wicket:id="repositoryUrl" style="color: blue;">[repository url]</span><span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span> <!-- Plain JavaScript manual copy & paste --> <wicket:fragment wicket:id="jsPanel"> <span style="vertical-align:baseline;"> <img wicket:id="copyIcon" wicket:message="title:gb.copyToClipboard"></img> <div wicket:id="repositoryPrimaryUrl">[repository primary url]</div> <div style="padding-top: 2px;"> <span class="link" wicket:id="appCloneLink"> <span wicket:id="icon"></span> <span wicket:id="link"></span> <span wicket:id="separator" style="padding: 0px 5px 0px 5px;"></span> </span> </wicket:fragment> <!-- flash-based button-press copy & paste --> <wicket:fragment wicket:id="clippyPanel"> <object wicket:message="title:gb.copyToClipboard" style="vertical-align:middle;" wicket:id="clippy" width="14" height="14" bgcolor="#ffffff" quality="high" wmode="transparent" scale="noscale" allowScriptAccess="always"></object> </wicket:fragment> </div> <div wicket:id="repositoryGitDaemonUrl">[repository git daemon url]</div> </wicket:panel> </html> src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
@@ -15,37 +15,226 @@ */ package com.gitblit.wicket.panels; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.image.ContextImage; import org.apache.wicket.markup.html.panel.Fragment; import java.io.Serializable; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.apache.wicket.Component; import org.apache.wicket.Localizer; import org.apache.wicket.RequestCycle; 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 org.apache.wicket.protocol.http.WebRequest; import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.GitBlit; import com.gitblit.Keys; import com.gitblit.SparkleShareInviteServlet; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; /** * Smart repository url panel which can display multiple Gitblit repository urls * and also supports 3rd party app clone links. * * @author James Moger * */ public class RepositoryUrlPanel extends BasePanel { private static final long serialVersionUID = 1L; public RepositoryUrlPanel(String wicketId, String url) { private final String primaryUrl; public RepositoryUrlPanel(String wicketId, boolean onlyPrimary, UserModel user, RepositoryModel repository, Localizer localizer, Component owner) { super(wicketId); add(new Label("repositoryUrl", url)); if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) { // clippy: flash-based copy & paste Fragment fragment = new Fragment("copyFunction", "clippyPanel", this); String baseUrl = WicketUtils.getGitblitURL(getRequest()); ShockWaveComponent clippy = new ShockWaveComponent("clippy", baseUrl + "/clippy.swf"); clippy.setValue("flashVars", "text=" + StringUtils.encodeURL(url)); fragment.add(clippy); add(fragment); if (user == null) { user = UserModel.ANONYMOUS; } List<String> repositoryUrls = new ArrayList<String>(); AccessPermission accessPermission = null; if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) { accessPermission = user.getRepositoryPermission(repository).permission; repositoryUrls.add(getRepositoryUrl(repository)); } repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repository.name, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); primaryUrl = repositoryUrls.size() == 0 ? "" : repositoryUrls.remove(0); add(new DetailedRepositoryUrlPanel("repositoryPrimaryUrl", localizer, owner, repository.name, primaryUrl, accessPermission)); if (!onlyPrimary) { Component gitDaemonUrlPanel = createGitDaemonUrlPanel("repositoryGitDaemonUrl", user, repository); if (!StringUtils.isEmpty(primaryUrl) && gitDaemonUrlPanel instanceof DetailedRepositoryUrlPanel) { WicketUtils.setCssStyle(gitDaemonUrlPanel, "padding-top: 10px"); } add(gitDaemonUrlPanel); } else { // javascript: manual copy & paste with modal browser prompt dialog Fragment fragment = new Fragment("copyFunction", "jsPanel", this); ContextImage img = WicketUtils.newImage("copyIcon", "clippy.png"); img.add(new JavascriptTextPrompt("onclick", "Copy to Clipboard (Ctrl+C, Enter)", url)); fragment.add(img); add(fragment); add(new Label("repositoryGitDaemonUrl").setVisible(false)); } final List<AppCloneLink> cloneLinks = new ArrayList<AppCloneLink>(); if (user.canClone(repository) && GitBlit.getBoolean(Keys.web.allowAppCloneLinks, true)) { // universal app clone urls // cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSmartGit", owner), // MessageFormat.format("smartgit://cloneRepo/{0}", primaryUrl), // "Syntevo SmartGit\u2122")); if (isWindows()) { // Windows client app clone urls cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSourceTree", owner), MessageFormat.format("sourcetree://cloneRepo/{0}", primaryUrl), "Atlassian SourceTree\u2122")); // cloneLinks.add(new AppCloneLink( // MessageFormat.format(localizer.getString("gb.cloneWithGitHub", owner), "Windows"), // MessageFormat.format("github-windows://openRepo/{0}", primaryUrl))); } else if (isMac()) { // Mac client app clone urls cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSourceTree", owner), MessageFormat.format("sourcetree://cloneRepo/{0}", primaryUrl), "Atlassian SourceTree\u2122")); // cloneLinks.add(new AppCloneLink( // MessageFormat.format(localizer.getString("gb.cloneWithGitHub", owner), "Mac"), // MessageFormat.format("github-mac://openRepo/{0}", primaryUrl))); } // sparkleshare invite url String sparkleshareUrl = getSparkleShareInviteUrl(user, repository); if (!StringUtils.isEmpty(sparkleshareUrl)) { cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSparkleShare", owner), sparkleshareUrl, "SparkleShare \u2122", "icon-star")); } } // app clone links ListDataProvider<AppCloneLink> appLinks = new ListDataProvider<AppCloneLink>(cloneLinks); DataView<AppCloneLink> appCloneLinks = new DataView<AppCloneLink>("appCloneLink", appLinks) { private static final long serialVersionUID = 1L; int count; public void populateItem(final Item<AppCloneLink> item) { final AppCloneLink appLink = item.getModelObject(); item.add(new Label("icon", MessageFormat.format("<i class=\"{0}\"></i>", appLink.icon)).setEscapeModelStrings(false)); LinkPanel linkPanel = new LinkPanel("link", null, appLink.name, appLink.url); if (!StringUtils.isEmpty(appLink.tooltip)) { WicketUtils.setHtmlTooltip(linkPanel, appLink.tooltip); } item.add(linkPanel); item.add(new Label("separator", "|").setVisible(count < (cloneLinks.size() - 1))); count++; } }; add(appCloneLinks); } public String getPrimaryUrl() { return primaryUrl; } protected String getRepositoryUrl(RepositoryModel repository) { StringBuilder sb = new StringBuilder(); sb.append(WicketUtils.getGitblitURL(RequestCycle.get().getRequest())); sb.append(Constants.GIT_PATH); sb.append(repository.name); // inject username into repository url if authentication is required if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) && GitBlitWebSession.get().isLoggedIn()) { String username = GitBlitWebSession.get().getUsername(); sb.insert(sb.indexOf("://") + 3, username + "@"); } return sb.toString(); } protected Component createGitDaemonUrlPanel(String wicketId, UserModel user, RepositoryModel repository) { int gitDaemonPort = GitBlit.getInteger(Keys.git.daemonPort, 0); if (gitDaemonPort > 0 && user.canClone(repository)) { String servername = ((WebRequest) getRequest()).getHttpServletRequest().getServerName(); String gitDaemonUrl; if (gitDaemonPort == 9418) { // standard port gitDaemonUrl = MessageFormat.format("git://{0}/{1}", servername, repository.name); } else { // non-standard port gitDaemonUrl = MessageFormat.format("git://{0}:{1,number,0}/{2}", servername, gitDaemonPort, repository.name); } AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission;; if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) { if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) { // can not authenticate clone via anonymous git protocol gitDaemonPermission = AccessPermission.NONE; } else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) { // can not authenticate push via anonymous git protocol gitDaemonPermission = AccessPermission.CLONE; } else { // normal user permission } } if (AccessPermission.NONE.equals(gitDaemonPermission)) { // repository prohibits all anonymous access return new Label(wicketId).setVisible(false); } else { // repository allows some form of anonymous access return new DetailedRepositoryUrlPanel(wicketId, getLocalizer(), this, repository.name, gitDaemonUrl, gitDaemonPermission); } } else { // git daemon is not running return new Label(wicketId).setVisible(false); } } protected String getSparkleShareInviteUrl(UserModel user, RepositoryModel repository) { if (repository.isBare && repository.isSparkleshared()) { String username = null; if (UserModel.ANONYMOUS != user) { username = user.username; } if (GitBlit.getBoolean(Keys.git.enableGitServlet, true) || (GitBlit.getInteger(Keys.git.daemonPort, 0) > 0)) { // Gitblit as server // ensure user can rewind if (user.canRewindRef(repository)) { String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); return SparkleShareInviteServlet.asLink(baseURL, repository.name, username); } } else { // Gitblit as viewer, assume RW+ permission String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); return SparkleShareInviteServlet.asLink(baseURL, repository.name, username); } } return null; } static class AppCloneLink implements Serializable { private static final long serialVersionUID = 1L; final String name; final String url; final String tooltip; final String icon; public AppCloneLink(String name, String url, String tooltip) { this(name, url, tooltip, "icon-download"); } public AppCloneLink(String name, String url, String tooltip, String icon) { this.name = name; this.url = url; this.tooltip = tooltip; this.icon = icon; } } } src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.html
File was deleted src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.java
File was deleted