diff options
author | James Moger <james.moger@gitblit.com> | 2013-05-09 22:43:57 -0400 |
---|---|---|
committer | James Moger <james.moger@gitblit.com> | 2013-05-09 22:43:57 -0400 |
commit | 828add77e71a567be98490403bb92d6f1afb9930 (patch) | |
tree | f6211abf4a8ce9eb19ab56d7cf2f75b65afac5ea /src/main | |
parent | 0b086146ffd70574b1069056e35bb11a1d782407 (diff) | |
download | gitblit-828add77e71a567be98490403bb92d6f1afb9930.tar.gz gitblit-828add77e71a567be98490403bb92d6f1afb9930.zip |
Implemented application menus for repository url panel
Diffstat (limited to 'src/main')
21 files changed, 669 insertions, 559 deletions
diff --git a/src/main/distrib/data/clientapps.json b/src/main/distrib/data/clientapps.json index 95e45f98..9aa1e580 100644 --- a/src/main/distrib/data/clientapps.json +++ b/src/main/distrib/data/clientapps.json @@ -1,41 +1,63 @@ [
{
+ "name": "Git",
+ "title": "Git",
+ "description": "a fast, open-source, distributed VCS",
+ "legal": "released under the GPLv2 open source license",
+ "command": "git clone {0}",
+ "productUrl": "http://git-scm.com",
+ "icon": "git-black_32x32.png",
+ "isActive": true
+ },
+ {
"name": "SmartGit/Hg",
+ "title": "syntevo SmartGit/Hg\u2122",
+ "description": "a Git client for Windows, Mac, & Linux",
+ "legal": "\u00a9 2013 syntevo GmbH. All rights reserved.",
"cloneUrl": "smartgit://cloneRepo/{0}",
"productUrl": "http://www.syntevo.com/smartgithg",
- "attribution": "Syntevo SmartGit/Hg\u2122",
"platforms": [ "windows", "macintosh", "linux" ],
+ "icon": "smartgithg_32x32.png",
"isActive": false
},
{
"name": "SourceTree",
+ "title": "Atlassian SourceTree\u2122",
+ "description": "a free Git client for Windows or Mac",
+ "legal": "\u00a9 2013 Atlassian. All rights reserved.",
"cloneUrl": "sourcetree://cloneRepo/{0}",
"productUrl": "http://sourcetreeapp.com",
- "attribution": "Atlassian SourceTree\u2122",
"platforms": [ "windows", "macintosh" ],
+ "icon": "sourcetree_32x32.png",
"isActive": true
},
{
"name": "Tower",
+ "title": "fournova Tower\u2122",
+ "description": "a Git client for Mac",
+ "legal": "\u00a9 2013 fournova Software GmbH. All rights reserved.",
"cloneUrl": "gittower://openRepo/{0}",
"productUrl": "http://www.git-tower.com",
- "attribution": "fournova Tower\u2122",
"platforms": [ "macintosh" ],
"isActive": true
},
{
- "name": "GitHub for Macintosh",
+ "name": "GitHub",
+ "title": "GitHub\u2122 for Macintosh",
+ "description": "a free Git client for Mac OS X",
+ "legal": "\u00a9 2013 GitHub. All rights reserved.",
"cloneUrl": "github-mac://openRepo/{0}",
"productUrl": "http://mac.github.com",
- "attribution": "GitHub\u2122 for Macintosh",
"platforms": [ "macintosh" ],
"isActive": false
},
{
- "name": "GitHub for Windows",
+ "name": "GitHub",
+ "title": "GitHub\u2122 for Windows",
+ "description": "a free Git client for Windows",
+ "legal": "\u00a9 2013 GitHub. All rights reserved.",
"cloneUrl": "github-windows://openRepo/{0}",
"productUrl": "http://windows.github.com",
- "attribution": "GitHub\u2122 for Windows",
"platforms": [ "windows" ],
"isActive": false
}
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index 42a1434b..9346e0ac 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -91,15 +91,16 @@ import com.gitblit.fanout.FanoutNioService; import com.gitblit.fanout.FanoutService;
import com.gitblit.fanout.FanoutSocketService;
import com.gitblit.git.GitDaemon;
-import com.gitblit.models.GitClientApplication;
import com.gitblit.models.FederationModel;
import com.gitblit.models.FederationProposal;
import com.gitblit.models.FederationSet;
import com.gitblit.models.ForkModel;
+import com.gitblit.models.GitClientApplication;
import com.gitblit.models.Metric;
import com.gitblit.models.ProjectModel;
import com.gitblit.models.RegistrantAccessPermission;
import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.RepositoryUrl;
import com.gitblit.models.SearchResult;
import com.gitblit.models.ServerSettings;
import com.gitblit.models.ServerStatus;
@@ -201,7 +202,7 @@ public class GitBlit implements ServletContextListener { private FanoutService fanoutService;
private GitDaemon gitDaemon;
-
+
public GitBlit() {
if (gitblit == null) {
// set the static singleton reference
@@ -460,23 +461,106 @@ public class GitBlit implements ServletContextListener { serverStatus.heapFree = Runtime.getRuntime().freeMemory();
return serverStatus;
}
-
+
/**
- * Returns the list of non-Gitblit clone urls. This allows Gitblit to
- * advertise alternative urls for Git client repository access.
+ * Returns a list of repository URLs and the user access permission.
*
- * @param repositoryName
- * @param userName
- * @return list of non-gitblit clone urls
+ * @param request
+ * @param user
+ * @param repository
+ * @return a list of repository urls
*/
- public List<String> getOtherCloneUrls(String repositoryName, String username) {
- List<String> cloneUrls = new ArrayList<String>();
+ public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
+ if (user == null) {
+ user = UserModel.ANONYMOUS;
+ }
+ String username = UserModel.ANONYMOUS.equals(user) ? "" : user.username;
+
+ List<RepositoryUrl> list = new ArrayList<RepositoryUrl>();
+ // http/https url
+ if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
+ AccessPermission permission = user.getRepositoryPermission(repository).permission;
+ if (permission.exceeds(AccessPermission.NONE)) {
+ list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission));
+ }
+ }
+
+ // git daemon url
+ String gitDaemonUrl = getGitDaemonUrl(request, user, repository);
+ if (!StringUtils.isEmpty(gitDaemonUrl)) {
+ AccessPermission permission = getGitDaemonAccessPermission(user, repository);
+ if (permission.exceeds(AccessPermission.NONE)) {
+ list.add(new RepositoryUrl(gitDaemonUrl, permission));
+ }
+ }
+
+ // add all other urls
+ // {0} = repository
+ // {1} = username
for (String url : settings.getStrings(Keys.web.otherUrls)) {
- cloneUrls.add(MessageFormat.format(url, repositoryName, username));
+ if (url.contains("{1}")) {
+ // external url requires username, only add url IF we have one
+ if(!StringUtils.isEmpty(username)) {
+ list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null));
+ }
+ } else {
+ // external url does not require username
+ list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null));
+ }
}
- return cloneUrls;
+ return list;
}
+ protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(HttpUtils.getGitblitURL(request));
+ sb.append(Constants.GIT_PATH);
+ sb.append(repository.name);
+
+ // inject username into repository url if authentication is required
+ if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE)
+ && !StringUtils.isEmpty(username)) {
+ sb.insert(sb.indexOf("://") + 3, username + "@");
+ }
+ return sb.toString();
+ }
+
+ protected String getGitDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) {
+ if (gitDaemon != null) {
+ String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
+ if (bindInterface.equals("localhost")
+ && (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) {
+ // git daemon is bound to localhost and the request is from elsewhere
+ return null;
+ }
+ if (user.canClone(repository)) {
+ String servername = request.getServerName();
+ String url = gitDaemon.formatUrl(servername, repository.name);
+ return url;
+ }
+ }
+ return null;
+ }
+
+ protected AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) {
+ if (gitDaemon != null && user.canClone(repository)) {
+ 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
+ }
+ }
+ return gitDaemonPermission;
+ }
+ return AccessPermission.NONE;
+ }
+
/**
* Returns the list of custom client applications to be used for the
* repository url panel;
@@ -3283,8 +3367,8 @@ public class GitBlit implements ServletContextListener { }
protected void configureGitDaemon() {
- String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
int port = settings.getInteger(Keys.git.daemonPort, 0);
+ String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
if (port > 0) {
try {
gitDaemon = new GitDaemon(bindInterface, port, getRepositoriesFolder());
diff --git a/src/main/java/com/gitblit/git/GitDaemon.java b/src/main/java/com/gitblit/git/GitDaemon.java index 7050f878..3c45171f 100644 --- a/src/main/java/com/gitblit/git/GitDaemon.java +++ b/src/main/java/com/gitblit/git/GitDaemon.java @@ -177,6 +177,20 @@ public class GitDaemon { }
} };
}
+
+ public int getPort() {
+ return myAddress.getPort();
+ }
+
+ public String formatUrl(String servername, String repository) {
+ if (getPort() == 9418) {
+ // standard port
+ return MessageFormat.format("git://{0}/{1}", servername, repository);
+ } else {
+ // non-standard port
+ return MessageFormat.format("git://{0}:{1,number,0}/{2}", servername, getPort(), repository);
+ }
+ }
/** @return timeout (in seconds) before aborting an IO operation. */
public int getTimeout() {
diff --git a/src/main/java/com/gitblit/models/GitClientApplication.java b/src/main/java/com/gitblit/models/GitClientApplication.java index dbdfa395..fd530593 100644 --- a/src/main/java/com/gitblit/models/GitClientApplication.java +++ b/src/main/java/com/gitblit/models/GitClientApplication.java @@ -31,13 +31,15 @@ public class GitClientApplication implements Serializable { private static final long serialVersionUID = 1L;
public String name;
+ public String title;
+ public String description;
+ public String legal;
+ public String icon;
public String cloneUrl;
public String command;
public String productUrl;
- public String attribution;
- public boolean isApplication = true;
- public boolean isActive = true;
public String[] platforms;
+ public boolean isActive;
public boolean allowsPlatform(String p) {
if (ArrayUtils.isEmpty(platforms)) {
@@ -55,4 +57,9 @@ public class GitClientApplication implements Serializable { }
return false;
}
+
+ @Override
+ public String toString() {
+ return StringUtils.isEmpty(title) ? name : title;
+ }
}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/models/RepositoryUrl.java b/src/main/java/com/gitblit/models/RepositoryUrl.java new file mode 100644 index 00000000..d72959a2 --- /dev/null +++ b/src/main/java/com/gitblit/models/RepositoryUrl.java @@ -0,0 +1,49 @@ +/*
+ * 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.models;
+
+import java.io.Serializable;
+
+import com.gitblit.Constants.AccessPermission;
+
+/**
+ * Represents a git repository url and it's associated access permission for the
+ * current user.
+ *
+ * @author James Moger
+ *
+ */
+public class RepositoryUrl implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public final String url;
+ public final AccessPermission permission;
+
+ public RepositoryUrl(String url, AccessPermission permission) {
+ this.url = url;
+ this.permission = permission;
+ }
+
+ public boolean isExternal() {
+ return permission == null;
+ }
+
+ @Override
+ public String toString() {
+ return url;
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 9355b808..7ebea4eb 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -449,8 +449,5 @@ gb.doesNotExistInTree = {0} does not exist in tree {1} gb.enableIncrementalPushTags = enable incremental push tags
gb.useIncrementalPushTagsDescription = on push, automatically tag each branch tip with an incremental revision number
gb.incrementalPushTagMessage = Auto-tagged [{0}] branch on push
-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.cloneUrl = clone {0}
-gb.visitSite = visit {0} website
\ No newline at end of file +gb.externalPermissions = {0} access permissions are externally maintained
+gb.viewAccess = You do not have Gitblit read or write access
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/WicketUtils.java b/src/main/java/com/gitblit/wicket/WicketUtils.java index 6e03032e..2170d0b7 100644 --- a/src/main/java/com/gitblit/wicket/WicketUtils.java +++ b/src/main/java/com/gitblit/wicket/WicketUtils.java @@ -41,6 +41,7 @@ import org.wicketstuff.googlecharts.AbstractChartData; import org.wicketstuff.googlecharts.IChartData;
import com.gitblit.Constants;
+import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.FederationPullStatus;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
@@ -107,6 +108,29 @@ public class WicketUtils { setCssClass(container, css);
}
}
+
+ public static void setPermissionClass(Component container, AccessPermission permission) {
+ if (permission == null) {
+ setCssClass(container, "badge");
+ return;
+ }
+ switch (permission) {
+ case REWIND:
+ case DELETE:
+ case CREATE:
+ setCssClass(container, "badge badge-success");
+ break;
+ case PUSH:
+ setCssClass(container, "badge badge-info");
+ break;
+ case CLONE:
+ setCssClass(container, "badge badge-inverse");
+ break;
+ default:
+ setCssClass(container, "badge");
+ break;
+ }
+ }
public static void setAlternatingBackground(Component c, int i) {
String clazz = i % 2 == 0 ? "light" : "dark";
diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.java b/src/main/java/com/gitblit/wicket/pages/BasePage.java index 19fa7493..ca3ea908 100644 --- a/src/main/java/com/gitblit/wicket/pages/BasePage.java +++ b/src/main/java/com/gitblit/wicket/pages/BasePage.java @@ -32,11 +32,9 @@ import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.Application;
-import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.PageParameters;
import org.apache.wicket.RedirectToUrlException;
-import org.apache.wicket.RequestCycle;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.markup.html.CSSPackageResource;
import org.apache.wicket.markup.html.basic.Label;
@@ -45,7 +43,6 @@ import org.apache.wicket.markup.html.link.ExternalLink; import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.protocol.http.RequestUtils;
-import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,14 +55,12 @@ import com.gitblit.Constants.FederationStrategy; import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.models.ProjectModel;
-import com.gitblit.models.RepositoryModel;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
import com.gitblit.utils.TimeUtils;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.WicketUtils;
-import com.gitblit.wicket.panels.DetailedRepositoryUrlPanel;
import com.gitblit.wicket.panels.LinkPanel;
public abstract class BasePage extends SessionPage {
@@ -258,60 +253,6 @@ public abstract class BasePage extends SessionPage { return req.getServerName();
}
- public static 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 List<ProjectModel> getProjectModels() {
final UserModel user = GitBlitWebSession.get().getUser();
List<ProjectModel> projects = GitBlit.self().getProjectModels(user, true);
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java index f7e88489..f7042030 100644 --- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java @@ -53,7 +53,7 @@ public class EmptyRepositoryPage extends RootPage { user = UserModel.ANONYMOUS;
}
- RepositoryUrlPanel urlPanel = new RepositoryUrlPanel("pushurl", false, user, repository, getLocalizer(), this);
+ RepositoryUrlPanel urlPanel = new RepositoryUrlPanel("pushurl", false, user, repository);
String primaryUrl = urlPanel.getPrimaryUrl();
add(new Label("repository", repositoryName));
diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.html b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html index 1527436f..78c8f4df 100644 --- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html @@ -19,10 +19,8 @@ <tr><th><wicket:message key="gb.owners">[owner]</wicket:message></th><td><span wicket:id="repositoryOwners"><span wicket:id="owner"></span><span wicket:id="comma"></span></span></td></tr>
<tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>
<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="repositoryUrlPanel">[repository url panel]</div>
- </td>
+ <tr><th style="vertical-align:top;padding-top:4px;"><wicket:message key="gb.repositoryUrl">[URL]</wicket:message></th>
+ <td><div wicket:id="repositoryUrlPanel">[repository url panel]</div></td>
</tr>
</table>
</div>
diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java index 54445f8e..321dff3d 100644 --- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java @@ -42,7 +42,6 @@ import org.wicketstuff.googlecharts.LineStyle; import org.wicketstuff.googlecharts.MarkerType;
import org.wicketstuff.googlecharts.ShapeMarker;
-import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.models.Metric;
@@ -124,32 +123,7 @@ public class SummaryPage extends RepositoryPage { add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class,
WicketUtils.newRepositoryParameter(repositoryName)));
- if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
- AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction;
- switch (accessRestriction) {
- case NONE:
- add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
- break;
- case PUSH:
- add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
- getAccessRestrictions().get(accessRestriction)));
- break;
- case CLONE:
- add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
- getAccessRestrictions().get(accessRestriction)));
- break;
- case VIEW:
- add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
- getAccessRestrictions().get(accessRestriction)));
- break;
- default:
- add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
- }
- } else {
- add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
- }
-
- add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model, getLocalizer(), this));
+ add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model));
add(new LogPanel("commitsPanel", repositoryName, getRepositoryModel().HEAD, r, numberCommits, 0, getRepositoryModel().showRemoteBranches));
add(new TagsPanel("tagsPanel", repositoryName, r, numberRefs).hideIfEmpty());
diff --git a/src/main/java/com/gitblit/wicket/panels/DetailedRepositoryUrlPanel.html b/src/main/java/com/gitblit/wicket/panels/DetailedRepositoryUrlPanel.html deleted file mode 100644 index e671435b..00000000 --- a/src/main/java/com/gitblit/wicket/panels/DetailedRepositoryUrlPanel.html +++ /dev/null @@ -1,42 +0,0 @@ -<!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">
-
-<wicket:panel>
- <span wicket:id="urlPanel"></span>
-
- <!-- Repository url panel -->
- <wicket:fragment wicket:id="repositoryUrlPanel">
- <span class="repositoryUrlContainer">
- <span wicket:id="repositoryProtocol" class="repositoryUrlEndCap">[protocol]</span>
- <span class="repositoryUrl">
- <span wicket:id="repositoryUrl">[repository url]</span>
- <span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span>
- </span>
- <span class="hidden-phone hidden-tablet repositoryUrlEndCap" wicket:id="repositoryUrlPermission">[repository url permission]</span>
- </span>
- </wicket:fragment>
-
- <!-- 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>
- </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>
-</wicket:panel>
-</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/DetailedRepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/DetailedRepositoryUrlPanel.java deleted file mode 100644 index 92c51e41..00000000 --- a/src/main/java/com/gitblit/wicket/panels/DetailedRepositoryUrlPanel.java +++ /dev/null @@ -1,119 +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.panels;
-
-import java.text.MessageFormat;
-
-import org.apache.wicket.Component;
-import org.apache.wicket.Localizer;
-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 com.gitblit.Constants.AccessPermission;
-import com.gitblit.GitBlit;
-import com.gitblit.Keys;
-import com.gitblit.utils.StringUtils;
-import com.gitblit.wicket.WicketUtils;
-
-public class DetailedRepositoryUrlPanel extends BasePanel {
-
- private static final long serialVersionUID = 1L;
- public DetailedRepositoryUrlPanel(String wicketId, Localizer localizer, Component parent, String repository, String url) {
- this(wicketId, localizer, parent, repository, url, null);
- }
-
- public DetailedRepositoryUrlPanel(String wicketId, Localizer localizer, Component parent, String repository, String url, AccessPermission ap) {
- super(wicketId);
-
- String protocol = url.substring(0, url.indexOf(':'));
- String note;
- String permission;
-
- if (ap == null) {
- note = MessageFormat.format(localizer.getString("gb.externalPermissions", parent), protocol, repository);
- permission = "";
- } else {
- note = null;
- permission = ap.toString();
- String key;
- switch (ap) {
- case OWNER:
- case REWIND:
- key = "gb.rewindPermission";
- break;
- case DELETE:
- key = "gb.deletePermission";
- break;
- case CREATE:
- key = "gb.createPermission";
- break;
- case PUSH:
- key = "gb.pushPermission";
- break;
- case CLONE:
- key = "gb.clonePermission";
- break;
- default:
- key = null;
- note = localizer.getString("gb.viewAccess", parent);
- break;
- }
-
- if (note == null) {
- String pattern = localizer.getString(key, parent);
- String description = MessageFormat.format(pattern, permission);
- String permissionPattern = localizer.getString("gb.yourProtocolPermissionIs", parent);
- note = MessageFormat.format(permissionPattern, protocol.toUpperCase(), repository, description);
- }
- }
-
- if (!StringUtils.isEmpty(url) && ((ap == null) || ap.atLeast(AccessPermission.CLONE))) {
- // valid repository url
- Fragment fragment = new Fragment("urlPanel", "repositoryUrlPanel", this);
- add(fragment);
- Label protocolLabel = new Label("repositoryProtocol", protocol + "://");
- WicketUtils.setHtmlTooltip(protocolLabel, note);
- fragment.add(protocolLabel);
- fragment.add(new Label("repositoryUrl", url.substring(url.indexOf("://") + 3)));
- Label permissionLabel = new Label("repositoryUrlPermission", permission);
- WicketUtils.setHtmlTooltip(permissionLabel, note);
- fragment.add(permissionLabel);
-
- if (StringUtils.isEmpty(url)) {
- fragment.add(new Label("copyFunction").setVisible(false));
- } else if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) {
- // clippy: flash-based copy & paste
- Fragment copyFragment = 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));
- copyFragment.add(clippy);
- fragment.add(copyFragment);
- } else {
- // javascript: manual copy & paste with modal browser prompt dialog
- Fragment copyFragment = new Fragment("copyFunction", "jsPanel", this);
- ContextImage img = WicketUtils.newImage("copyIcon", "clippy.png");
- img.add(new JavascriptTextPrompt("onclick", "Copy to Clipboard (Ctrl+C, Enter)", url));
- copyFragment.add(img);
- fragment.add(copyFragment);
- }
- } else {
- // no Git url, there may be a message
- add(new Label("urlPanel", MessageFormat.format("<i>{0}</i>", note)).setEscapeModelStrings(false).setVisible(!StringUtils.isEmpty(note)));
- }
- }
-}
diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html index e67e6416..e9196cda 100644 --- a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html +++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html @@ -59,7 +59,6 @@ <div>
<span class="repositorySwatch" wicket:id="repositorySwatch"></span>
<span class="repository" style="padding-left:3px;color:black;" wicket:id="repositoryName">[repository name]</span>
- <img class="inlineIcon" style="vertical-align:baseline" wicket:id="accessRestrictionIcon" />
</div>
<span wicket:id="originRepository">[origin repository]</span>
</div>
diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java index 7cce74f7..e7fe017e 100644 --- a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java @@ -103,25 +103,6 @@ public class ProjectRepositoryPanel extends BasePanel { } else {
add(WicketUtils.newClearPixel("federatedIcon").setVisible(false));
}
- switch (entry.accessRestriction) {
- case NONE:
- add(WicketUtils.newBlankImage("accessRestrictionIcon").setVisible(false));
- break;
- case PUSH:
- add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
- accessRestrictions.get(entry.accessRestriction)));
- break;
- case CLONE:
- add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
- accessRestrictions.get(entry.accessRestriction)));
- break;
- case VIEW:
- add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
- accessRestrictions.get(entry.accessRestriction)));
- break;
- default:
- add(WicketUtils.newBlankImage("accessRestrictionIcon"));
- }
if (ArrayUtils.isEmpty(entry.owners)) {
add(new Label("repositoryOwner").setVisible(false));
@@ -212,6 +193,6 @@ public class ProjectRepositoryPanel extends BasePanel { add(new ExternalLink("syndication", SyndicationServlet.asLink("", entry.name, null, 0)));
- add(new RepositoryUrlPanel("repositoryPrimaryUrl", true, user, entry, localizer, parent));
+ add(new RepositoryUrlPanel("repositoryPrimaryUrl", true, user, entry));
}
}
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.html index 675ebb58..b22aa714 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.html +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.html @@ -5,33 +5,66 @@ lang="en">
<wicket:panel>
- <div wicket:id="repositoryPrimaryUrl">[repository primary url]</div>
- <div class="btn-toolbar" style="margin-bottom: 0px;">
- <div class="btn-group" wicket:id="urlMenus">
- <a class="btn btn-mini btn-action" data-toggle="dropdown" href="#">
- <i class="icon-download icon-black"></i>
- <span wicket:id="productName"></span>
- <span class="caret"></span>
- </a>
- <ul class="dropdown-menu">
- <li><div style="padding-left: 15px; font-style: italic;" wicket:id="productAttribution"></div></li>
- <li class="divider"></li>
+
+ <div wicket:id="repositoryUrlPanel"></div>
+ <div wicket:id="applicationMenusPanel"></div>
+
+
+ <wicket:fragment wicket:id="repositoryUrlFragment">
+ <div class="btn-toolbar" style="margin: 0px;">
+ <div class="btn-group repositoryUrlContainer">
+ <img style="vertical-align: middle;padding: 0px 0px 1px 3px;" wicket:id="accessRestrictionIcon"></img>
+ <span wicket:id="menu"></span>
+ <span class="repositoryUrl">
+ <span wicket:id="primaryUrl">[repository primary url]</span>
+ <span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span>
+ </span>
+ <span class="hidden-phone hidden-tablet repositoryUrlRightCap" wicket:id="primaryUrlPermission">[repository primary url permission]</span>
+ </div>
+ </div>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="applicationMenusFragment">
+ <div class="btn-toolbar" style="margin: 4px 0px 0px 0px;">
+ <div class="btn-group" wicket:id="appMenus">
+ <a class="btn btn-mini btn-inverse" data-toggle="dropdown" href="#">
+ <span wicket:id="applicationName"></span>
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu applicationMenu">
+ <li>
+ <div class="applicationHeaderMenuItem">
+ <div style="float:right">
+ <img style="padding-right: 5px;vertical-align: middle;" wicket:id="applicationIcon"></img>
+ </div>
+ <span class="applicationTitle" wicket:id="applicationTitle"></span>
+ </div>
+ </li>
+ <li><div class="applicationHeaderMenuItem"><span wicket:id="applicationDescription"></span></div></li>
+ <li><div class="applicationLegalMenuItem"><span wicket:id="applicationLegal"></span></div></li>
+
+ <li class="divider" style="margin: 5px 1px 0px 1px;clear:both;" ></li>
- <li wicket:id="repoLinks">
- <span wicket:id="repoLink"></span>
- </li>
-
- <li style="border-top: 1px solid #eee; margin-top:5px;padding-top:5px;"><span wicket:id="productLink"></span></li>
- </ul>
- </div>
- </div>
+ <li class="action" wicket:id="actionItems">
+ <span wicket:id="actionItem"></span>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </wicket:fragment>
- <wicket:fragment wicket:id="commandFragment">
- <span wicket:id="content"></span><span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span>
+ <wicket:fragment wicket:id="urlProtocolMenuFragment">
+ <a class="" data-toggle="dropdown" href="#">
+ <span class="repositoryUrlLeftCap" wicket:id="menuText">URLs</span>
+ <span class="caret" style="vertical-align: middle;"></span>
+ </a>
+ <ul class="dropdown-menu urlMenu">
+ <li class="url" wicket:id="repoUrls"><span wicket:id="repoUrl"></span></li>
+ </ul>
</wicket:fragment>
-
- <wicket:fragment wicket:id="linkFragment">
- <span wicket:id="content"></span>
+
+ <wicket:fragment wicket:id="actionFragment">
+ <span wicket:id="permission" style="margin: 0px 10px 0px 5px;"></span><span wicket:id="content"></span><span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span>
</wicket:fragment>
<!-- Plain JavaScript manual copy & paste -->
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java index 9640ab00..00c7cf7a 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java @@ -15,13 +15,15 @@ */
package com.gitblit.wicket.panels;
-import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
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.html.image.ContextImage;
@@ -32,7 +34,6 @@ import org.apache.wicket.markup.repeater.data.ListDataProvider; import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.request.WebClientInfo;
-import com.gitblit.Constants;
import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlit;
@@ -40,6 +41,7 @@ import com.gitblit.Keys; import com.gitblit.SparkleShareInviteServlet;
import com.gitblit.models.GitClientApplication;
import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.RepositoryUrl;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
@@ -55,260 +57,314 @@ import com.gitblit.wicket.WicketUtils; public class RepositoryUrlPanel extends BasePanel {
private static final long serialVersionUID = 1L;
-
- private final RepoUrl primaryUrl;
- public RepositoryUrlPanel(String wicketId, boolean onlyPrimary, UserModel user,
- final RepositoryModel repository, Localizer localizer, Component owner) {
+ private final String externalPermission = "?";
+
+ private boolean onlyUrls;
+ private UserModel user;
+ private RepositoryModel repository;
+ private RepositoryUrl primaryUrl;
+ private Map<String, String> urlPermissionsMap;
+ private Map<AccessRestrictionType, String> accessRestrictionsMap;
+
+ public RepositoryUrlPanel(String wicketId, boolean onlyUrls, UserModel user, RepositoryModel repository) {
super(wicketId);
- if (user == null) {
- user = UserModel.ANONYMOUS;
- }
- List<RepoUrl> repositoryUrls = new ArrayList<RepoUrl>();
+ this.onlyUrls = onlyUrls;
+ this.user = user == null ? UserModel.ANONYMOUS : user;
+ this.repository = repository;
+ this.urlPermissionsMap = new HashMap<String, String>();
+ }
+
+ @Override
+ protected void onInitialize() {
+ super.onInitialize();
- // http/https url
- if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
- AccessPermission permission = user.getRepositoryPermission(repository).permission;
- if (permission.exceeds(AccessPermission.NONE)) {
- repositoryUrls.add(new RepoUrl(getRepositoryUrl(repository), permission));
- }
- }
-
- // git daemon url
- String gitDaemonUrl = getGitDaemonUrl(user, repository);
- if (!StringUtils.isEmpty(gitDaemonUrl)) {
- AccessPermission permission = getGitDaemonAccessPermission(user, repository);
- if (permission.exceeds(AccessPermission.NONE)) {
- repositoryUrls.add(new RepoUrl(gitDaemonUrl, permission));
- }
- }
-
- // add all other urls
- for (String url : GitBlit.self().getOtherCloneUrls(repository.name, UserModel.ANONYMOUS.equals(user) ? "" : user.username)) {
- repositoryUrls.add(new RepoUrl(url, null));
- }
-
+ HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
+
+ List<RepositoryUrl> repositoryUrls = GitBlit.self().getRepositoryUrls(req, user, repository);
// grab primary url from the top of the list
primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0);
- add(new DetailedRepositoryUrlPanel("repositoryPrimaryUrl", localizer, owner,
- repository.name, primaryUrl == null ? "" : primaryUrl.url,
- primaryUrl == null ? null : primaryUrl.permission));
-
- if (onlyPrimary) {
- // only displaying the primary url
- add(new Label("urlMenus").setVisible(false));
+ boolean canClone = ((primaryUrl.permission == null) || primaryUrl.permission.atLeast(AccessPermission.CLONE));
+
+ if (repositoryUrls.size() == 0 || !canClone) {
+ // no urls, nothing to show.
+ add(new Label("repositoryUrlPanel").setVisible(false));
+ add(new Label("applicationMenusPanel").setVisible(false));
return;
}
- final String clonePattern = localizer.getString("gb.cloneUrl", owner);
- final String visitSitePattern = localizer.getString("gb.visitSite", owner);
-
- GitClientApplication URLS = new GitClientApplication();
- URLS.name = "URLs";
- URLS.command = "{0}";
- URLS.attribution = "Repository URLs";
- URLS.isApplication = false;
- URLS.isActive = true;
+ // display primary url
+ add(createPrimaryUrlPanel("repositoryUrlPanel", repository, repositoryUrls));
+
+ boolean allowAppLinks = GitBlit.getBoolean(Keys.web.allowAppCloneLinks, true);
+ if (onlyUrls || !canClone || !allowAppLinks) {
+ // only display the url(s)
+ add(new Label("applicationMenusPanel").setVisible(false));
+ return;
+ }
+ // create the git client application menus
+ add(createApplicationMenus("applicationMenusPanel", user, repository, repositoryUrls));
+ }
+
+ public String getPrimaryUrl() {
+ return primaryUrl == null ? "" : primaryUrl.url;
+ }
+
+ protected Fragment createPrimaryUrlPanel(String wicketId, final RepositoryModel repository, List<RepositoryUrl> repositoryUrls) {
+
+ Fragment urlPanel = new Fragment(wicketId, "repositoryUrlFragment", this);
+ urlPanel.setRenderBodyOnly(true);
- GitClientApplication GIT = new GitClientApplication();
- GIT.name = "Git";
- GIT.command = "git clone {0}";
- GIT.productUrl = "http://git-scm.org";
- GIT.attribution = "Git Syntax";
- GIT.isApplication = false;
- GIT.isActive = true;
+ if (repositoryUrls.size() == 1) {
+ //
+ // Single repository url, no dropdown menu
+ //
+ urlPanel.add(new Label("menu").setVisible(false));
+ } else {
+ //
+ // Multiple repository urls, show url drop down menu
+ //
+ ListDataProvider<RepositoryUrl> urlsDp = new ListDataProvider<RepositoryUrl>(repositoryUrls);
+ DataView<RepositoryUrl> repoUrlMenuItems = new DataView<RepositoryUrl>("repoUrls", urlsDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<RepositoryUrl> item) {
+ RepositoryUrl repoUrl = item.getModelObject();
+ // repository url
+ Fragment fragment = new Fragment("repoUrl", "actionFragment", this);
+ Component content = new Label("content", repoUrl.url).setRenderBodyOnly(true);
+ WicketUtils.setCssClass(content, "commandMenuItem");
+ fragment.add(content);
+ item.add(fragment);
+
+ Label permissionLabel = new Label("permission", repoUrl.isExternal() ? externalPermission : repoUrl.permission.toString());
+ WicketUtils.setPermissionClass(permissionLabel, repoUrl.permission);
+ String tooltip = getProtocolPermissionDescription(repository, repoUrl);
+ WicketUtils.setHtmlTooltip(permissionLabel, tooltip);
+ fragment.add(permissionLabel);
+ fragment.add(createCopyFragment(repoUrl.url));
+ }
+ };
+
+ Fragment urlMenuFragment = new Fragment("menu", "urlProtocolMenuFragment", this);
+ urlMenuFragment.setRenderBodyOnly(true);
+ urlMenuFragment.add(new Label("menuText", getString("gb.url")));
+ urlMenuFragment.add(repoUrlMenuItems);
+ urlPanel.add(urlMenuFragment);
+ }
+
+ // access restriction icon and tooltip
+ if (isGitblitServingRepositories()) {
+ switch (repository.accessRestriction) {
+ case NONE:
+ urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ break;
+ case PUSH:
+ urlPanel.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
+ getAccessRestrictions().get(repository.accessRestriction)));
+ break;
+ case CLONE:
+ urlPanel.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
+ getAccessRestrictions().get(repository.accessRestriction)));
+ break;
+ case VIEW:
+ urlPanel.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
+ getAccessRestrictions().get(repository.accessRestriction)));
+ break;
+ default:
+ urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ }
+ } else {
+ urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ }
- final List<GitClientApplication> clientApps = new ArrayList<GitClientApplication>();
- clientApps.add(URLS);
- clientApps.add(GIT);
+ urlPanel.add(new Label("primaryUrl", primaryUrl.url).setRenderBodyOnly(true));
+
+ Label permissionLabel = new Label("primaryUrlPermission", primaryUrl.isExternal() ? externalPermission : primaryUrl.permission.toString());
+ String tooltip = getProtocolPermissionDescription(repository, primaryUrl);
+ WicketUtils.setHtmlTooltip(permissionLabel, tooltip);
+ urlPanel.add(permissionLabel);
+ urlPanel.add(createCopyFragment(primaryUrl.url));
+ return urlPanel;
+ }
+
+ protected Fragment createApplicationMenus(String wicketId, UserModel user, final RepositoryModel repository, List<RepositoryUrl> repositoryUrls) {
+ final List<GitClientApplication> displayedApps = new ArrayList<GitClientApplication>();
final String userAgent = ((WebClientInfo) GitBlitWebSession.get().getClientInfo()).getUserAgent();
- boolean allowAppLinks = GitBlit.getBoolean(Keys.web.allowAppCloneLinks, true);
+
if (user.canClone(repository)) {
for (GitClientApplication app : GitBlit.self().getClientApplications()) {
- if (app.isActive && app.allowsPlatform(userAgent) && (!app.isApplication || (app.isApplication && allowAppLinks))) {
- clientApps.add(app);
+ if (app.isActive && app.allowsPlatform(userAgent)) {
+ displayedApps.add(app);
}
}
- // sparkleshare invite url
- String sparkleshareUrl = getSparkleShareInviteUrl(user, repository);
- if (!StringUtils.isEmpty(sparkleshareUrl) && allowAppLinks) {
- GitClientApplication link = new GitClientApplication();
- link.name = "SparkleShare";
- link.cloneUrl = sparkleshareUrl;
- link.attribution = "SparkleShare\u2122";
- link.platforms = new String [] { "windows", "macintosh", "linux" };
- link.productUrl = "http://sparkleshare.org";
- link.isApplication = true;
- link.isActive = true;
- clientApps.add(link);
+ GitClientApplication sparkleshare = getSparkleShareAppMenu(user, repository);
+ if (sparkleshare != null) {
+ displayedApps.add(sparkleshare);
}
}
-
- final ListDataProvider<RepoUrl> repoUrls = new ListDataProvider<RepoUrl>(repositoryUrls);
- // app clone links
- ListDataProvider<GitClientApplication> appLinks = new ListDataProvider<GitClientApplication>(clientApps);
- DataView<GitClientApplication> urlMenus = new DataView<GitClientApplication>("urlMenus", appLinks) {
+ final ListDataProvider<RepositoryUrl> urlsDp = new ListDataProvider<RepositoryUrl>(repositoryUrls);
+ ListDataProvider<GitClientApplication> displayedAppsDp = new ListDataProvider<GitClientApplication>(displayedApps);
+ DataView<GitClientApplication> appMenus = new DataView<GitClientApplication>("appMenus", displayedAppsDp) {
private static final long serialVersionUID = 1L;
-
+
public void populateItem(final Item<GitClientApplication> item) {
- final GitClientApplication cloneLink = item.getModelObject();
- item.add(new Label("productName", cloneLink.name));
+ final GitClientApplication clientApp = item.getModelObject();
+
+ // menu button
+ item.add(new Label("applicationName", clientApp.name));
+
+ // application icon
+ Component img;
+ if (StringUtils.isEmpty(clientApp.icon)) {
+ img = WicketUtils.newClearPixel("applicationIcon").setVisible(false);
+ } else {
+ img = WicketUtils.newImage("applicationIcon", clientApp.icon);
+ }
+ item.add(img);
+
+ // application menu title, may be a link
+ if (StringUtils.isEmpty(clientApp.productUrl)) {
+ item.add(new Label("applicationTitle", clientApp.toString()));
+ } else {
+ item.add(new LinkPanel("applicationTitle", null, clientApp.toString(), clientApp.productUrl, true));
+ }
+
+ // brief application description
+ if (StringUtils.isEmpty(clientApp.description)) {
+ item.add(new Label("applicationDescription").setVisible(false));
+ } else {
+ item.add(new Label("applicationDescription", clientApp.description));
+ }
+
+ // brief application legal info, copyright, license, etc
+ if (StringUtils.isEmpty(clientApp.legal)) {
+ item.add(new Label("applicationLegal").setVisible(false));
+ } else {
+ item.add(new Label("applicationLegal", clientApp.legal));
+ }
- // a nested repeater for all repo links
- DataView<RepoUrl> repoLinks = new DataView<RepoUrl>("repoLinks", repoUrls) {
+ // a nested repeater for all action items
+ DataView<RepositoryUrl> actionItems = new DataView<RepositoryUrl>("actionItems", urlsDp) {
private static final long serialVersionUID = 1L;
- public void populateItem(final Item<RepoUrl> repoLinkItem) {
- RepoUrl repoUrl = repoLinkItem.getModelObject();
- if (!StringUtils.isEmpty(cloneLink.cloneUrl)) {
+ public void populateItem(final Item<RepositoryUrl> repoLinkItem) {
+ RepositoryUrl repoUrl = repoLinkItem.getModelObject();
+
+ Fragment fragment = new Fragment("actionItem", "actionFragment", this);
+ fragment.add(createPermissionBadge("permission", repoUrl));
+
+ if (!StringUtils.isEmpty(clientApp.cloneUrl)) {
// custom registered url
- Fragment fragment = new Fragment("repoLink", "linkFragment", this);
- String name;
- if (repoUrl.permission != null) {
- name = MessageFormat.format("{0} ({1})", repoUrl.url, repoUrl.permission);
- } else {
- name = repoUrl.url;
- }
- String url = MessageFormat.format(cloneLink.cloneUrl, repoUrl);
- fragment.add(new LinkPanel("content", null, MessageFormat.format(clonePattern, name), url));
+ String url = MessageFormat.format(clientApp.cloneUrl, repoUrl);
+ fragment.add(new LinkPanel("content", "applicationMenuItem", getString("gb.clone") + " " + repoUrl.url, url));
repoLinkItem.add(fragment);
- String tooltip = getProtocolPermissionDescription(repository, repoUrl);
- WicketUtils.setHtmlTooltip(fragment, tooltip);
- } else if (!StringUtils.isEmpty(cloneLink.command)) {
+ fragment.add(new Label("copyFunction").setVisible(false));
+ } else if (!StringUtils.isEmpty(clientApp.command)) {
// command-line
- Fragment fragment = new Fragment("repoLink", "commandFragment", this);
- WicketUtils.setCssClass(fragment, "repositoryUrlMenuItem");
- String command = MessageFormat.format(cloneLink.command, repoUrl);
- fragment.add(new Label("content", command));
+ String command = MessageFormat.format(clientApp.command, repoUrl);
+ Label content = new Label("content", command);
+ WicketUtils.setCssClass(content, "commandMenuItem");
+ fragment.add(content);
repoLinkItem.add(fragment);
- String tooltip = getProtocolPermissionDescription(repository, repoUrl);
- WicketUtils.setHtmlTooltip(fragment, tooltip);
// copy function for command
- if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) {
- // clippy: flash-based copy & paste
- Fragment copyFragment = new Fragment("copyFunction", "clippyPanel", this);
- String baseUrl = WicketUtils.getGitblitURL(getRequest());
- ShockWaveComponent clippy = new ShockWaveComponent("clippy", baseUrl + "/clippy.swf");
- clippy.setValue("flashVars", "text=" + StringUtils.encodeURL(command));
- copyFragment.add(clippy);
- fragment.add(copyFragment);
- } else {
- // javascript: manual copy & paste with modal browser prompt dialog
- Fragment copyFragment = new Fragment("copyFunction", "jsPanel", this);
- ContextImage img = WicketUtils.newImage("copyIcon", "clippy.png");
- img.add(new JavascriptTextPrompt("onclick", "Copy to Clipboard (Ctrl+C, Enter)", command));
- copyFragment.add(img);
- fragment.add(copyFragment);
- }
+ fragment.add(createCopyFragment(command));
}
}};
- item.add(repoLinks);
-
- item.add(new Label("productAttribution", cloneLink.attribution));
- if (!StringUtils.isEmpty(cloneLink.productUrl)) {
- LinkPanel productlinkPanel = new LinkPanel("productLink", null,
- MessageFormat.format(visitSitePattern, cloneLink.name), cloneLink.productUrl, true);
- item.add(productlinkPanel);
- } else {
- item.add(new Label("productLink").setVisible(false));
- }
+ item.add(actionItems);
}
};
- add(urlMenus);
- }
-
- public String getPrimaryUrl() {
- return primaryUrl == null ? "" : primaryUrl.url;
- }
-
- 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 String getGitDaemonUrl(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);
- }
- return gitDaemonUrl;
- }
- return null;
+ Fragment applicationMenus = new Fragment(wicketId, "applicationMenusFragment", this);
+ applicationMenus.add(appMenus);
+ return applicationMenus;
}
- protected AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) {
- int gitDaemonPort = GitBlit.getInteger(Keys.git.daemonPort, 0);
- if (gitDaemonPort > 0 && user.canClone(repository)) {
- 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
- }
- }
- return gitDaemonPermission;
- }
- return AccessPermission.NONE;
- }
-
- protected String getSparkleShareInviteUrl(UserModel user, RepositoryModel repository) {
+ protected GitClientApplication getSparkleShareAppMenu(UserModel user, RepositoryModel repository) {
+ String url = null;
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)) {
+ if (isGitblitServingRepositories()) {
// 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);
+ url = 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);
+ url = SparkleShareInviteServlet.asLink(baseURL, repository.name, username);
}
}
+
+ // sparkleshare invite url
+ if (!StringUtils.isEmpty(url)) {
+ GitClientApplication app = new GitClientApplication();
+ app.name = "SparkleShare";
+ app.title = "SparkleShare\u2122";
+ app.description = "an open source collaboration and sharing tool";
+ app.legal = "released under the GPLv3 open source license";
+ app.cloneUrl = url;
+ app.platforms = new String [] { "windows", "macintosh", "linux" };
+ app.productUrl = "http://sparkleshare.org";
+ app.icon = "star_32x32.png";
+ app.isActive = true;
+ return app;
+ }
return null;
}
- protected String getProtocolPermissionDescription(RepositoryModel repository, RepoUrl repoUrl) {
- String protocol = repoUrl.url.substring(0, repoUrl.url.indexOf("://"));
- String note;
- if (repoUrl.permission == null) {
- note = MessageFormat.format(getString("gb.externalPermissions"), protocol, repository.name);
+ protected boolean isGitblitServingRepositories() {
+ return GitBlit.getBoolean(Keys.git.enableGitServlet, true) || (GitBlit.getInteger(Keys.git.daemonPort, 0) > 0);
+ }
+
+ protected Label createPermissionBadge(String wicketId, RepositoryUrl repoUrl) {
+ Label permissionLabel = new Label(wicketId, repoUrl.isExternal() ? externalPermission : repoUrl.permission.toString());
+ WicketUtils.setPermissionClass(permissionLabel, repoUrl.permission);
+ String tooltip = getProtocolPermissionDescription(repository, repoUrl);
+ WicketUtils.setHtmlTooltip(permissionLabel, tooltip);
+ return permissionLabel;
+ }
+
+ protected Fragment createCopyFragment(String text) {
+ if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) {
+ // clippy: flash-based copy & paste
+ Fragment copyFragment = new Fragment("copyFunction", "clippyPanel", this);
+ String baseUrl = WicketUtils.getGitblitURL(getRequest());
+ ShockWaveComponent clippy = new ShockWaveComponent("clippy", baseUrl + "/clippy.swf");
+ clippy.setValue("flashVars", "text=" + StringUtils.encodeURL(text));
+ copyFragment.add(clippy);
+ return copyFragment;
} else {
- note = null;
- String key;
- switch (repoUrl.permission) {
+ // javascript: manual copy & paste with modal browser prompt dialog
+ Fragment copyFragment = new Fragment("copyFunction", "jsPanel", this);
+ ContextImage img = WicketUtils.newImage("copyIcon", "clippy.png");
+ img.add(new JavascriptTextPrompt("onclick", "Copy to Clipboard (Ctrl+C, Enter)", text));
+ copyFragment.add(img);
+ return copyFragment;
+ }
+ }
+
+ protected String getProtocolPermissionDescription(RepositoryModel repository,
+ RepositoryUrl repoUrl) {
+ if (!urlPermissionsMap.containsKey(repoUrl.url)) {
+ String note;
+ if (repoUrl.isExternal()) {
+ String protocol = repoUrl.url.substring(0, repoUrl.url.indexOf("://"));
+ note = MessageFormat.format(getString("gb.externalPermissions"), protocol);
+ } else {
+ note = null;
+ String key;
+ switch (repoUrl.permission) {
case OWNER:
case REWIND:
key = "gb.rewindPermission";
@@ -329,33 +385,39 @@ public class RepositoryUrlPanel extends BasePanel { key = null;
note = getString("gb.viewAccess");
break;
+ }
+
+ if (note == null) {
+ String pattern = getString(key);
+ String description = MessageFormat.format(pattern, repoUrl.permission.toString());
+ note = description;
+ }
}
-
- if (note == null) {
- String pattern = getString(key);
- String description = MessageFormat.format(pattern, repoUrl.permission.toString());
- String permissionPattern = getString("gb.yourProtocolPermissionIs");
- note = MessageFormat.format(permissionPattern, protocol.toUpperCase(), repository, description);
- }
+ urlPermissionsMap.put(repoUrl.url, note);
}
- return note;
+ return urlPermissionsMap.get(repoUrl.url);
}
- private class RepoUrl implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- final String url;
- final AccessPermission permission;
-
- RepoUrl(String url, AccessPermission permission) {
- this.url = url;
- this.permission = permission;
- }
-
- @Override
- public String toString() {
- return url;
+ protected Map<AccessRestrictionType, String> getAccessRestrictions() {
+ if (accessRestrictionsMap == null) {
+ accessRestrictionsMap = new HashMap<AccessRestrictionType, String>();
+ for (AccessRestrictionType type : AccessRestrictionType.values()) {
+ switch (type) {
+ case NONE:
+ accessRestrictionsMap.put(type, getString("gb.notRestricted"));
+ break;
+ case PUSH:
+ accessRestrictionsMap.put(type, getString("gb.pushRestricted"));
+ break;
+ case CLONE:
+ accessRestrictionsMap.put(type, getString("gb.cloneRestricted"));
+ break;
+ case VIEW:
+ accessRestrictionsMap.put(type, getString("gb.viewRestricted"));
+ break;
+ }
+ }
}
+ return accessRestrictionsMap;
}
}
diff --git a/src/main/resources/git-black_32x32.png b/src/main/resources/git-black_32x32.png Binary files differnew file mode 100644 index 00000000..037f61a1 --- /dev/null +++ b/src/main/resources/git-black_32x32.png diff --git a/src/main/resources/gitblit.css b/src/main/resources/gitblit.css index c22793d7..cfb6cf76 100644 --- a/src/main/resources/gitblit.css +++ b/src/main/resources/gitblit.css @@ -117,6 +117,19 @@ navbar div>ul .menu-dropdown li a:hover,.nav .menu-dropdown li a:hover,.navbar d color: #ffffff !important;
}
+.btn:first-child {
+ border-radius: 4px;
+}
+
+.btn-appmenu {
+ /*background-color: rgb(73, 175, 205);
+ background-image: -moz-linear-gradient(center top , rgb(91, 192, 222), rgb(47, 150, 180));*/
+ background-color: rgb(73, 175, 205);
+ background-image: -moz-linear-gradient(center top , rgb(91, 192, 222), rgb(47, 150, 180));
+ background-repeat: repeat-x;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+}
+
.breadcrumb {
margin-top: 5px !important;
margin-bottom: 5px !important;
@@ -179,33 +192,106 @@ navbar div>ul .menu-dropdown li a:hover,.nav .menu-dropdown li a:hover,.navbar d vertical-align: middle;
}
-span.repositoryUrlContainer {
+div.repositoryUrlContainer {
+ padding: 2px;
+ background-color: #F5F5F5;
+ background-image: -moz-linear-gradient(center top , #FFFFFF, #E6E6E6);
+ background-repeat: repeat-x;
+ border-color: #E6E6E6 #E6E6E6 #B3B3B3;
+ border-image: none;
+ border-radius: 4px;
+ border-style: solid;
+ border-width: 1px;
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2) inset, 0 1px 2px rgba(0, 0, 0, 0.05);
+ color: #333333;
+ vertical-align: middle;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+}
+
+div.repositoryUrlContainer:hover {
+ background-color: #E6E6E6;
+ background-position: 0 -15px;
+ color: #333333;
+ text-decoration: none;
+ transition: background-position 0.1s linear 0s;
+}
+
+div.repositoryUrlContainer:hover .caret {
+ opacity: 1;
+}
+
+div.repositoryUrlContainer:hover a:hover {
+ text-decoration: none;
+}
+
+span.repositoryUrlLeftCap, span.repositoryUrlRightCap {
+ text-align: center;
color: black;
- background-color: whiteSmoke;
- padding: 4px;
- border: 1px solid #ddd;
- border-radius: 3px
+ padding: 3px;
+ font-size: 11px;
}
-span.repositoryUrlEndCap {
- padding: 4px;
+span.repositoryUrlRightCap {
font-weight: bold;
- font-size: 0.85em;
font-family:menlo,consolas,monospace;
}
span.repositoryUrl {
font-size: 1em;
- padding: 4px;
- color: blue;
+ padding: 2px 4px 3px 4px;
background-color: #fff;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
}
-span.repositoryUrlMenuItem {
+ul.urlMenu {
+ min-width: 350px;
+}
+
+ul.urlMenu li.url {
+ background-color: white;
+ padding: 0px 5px;
+ line-height: 24px;
+}
+
+ul.applicationMenu {
+ background-color: whiteSmoke;
+ min-width: 400px;
+}
+
+ul.applicationMenu li.action {
+ background-color: white;
+ padding: 0px 5px;
line-height: 24px;
- padding: 3px 15px;
+}
+
+span.applicationTitle, span.applicationTitle a {
+ display: inline;
+ font-weight: bold;
+ font-size:1.1em;
+ color: black !important;
+ padding: 0px;
+}
+
+div.applicationHeaderMenuItem {
+ padding-left: 10px;
+ color: black;
+}
+
+div.applicationLegalMenuItem {
+ padding-left: 10px;
+ color: #999;
+ font-size: 0.85em;
+}
+
+a.applicationMenuItem, span.commandMenuItem {
+ padding: 3px 10px;
+ color: black;
+ display: inline;
+ padding: 0px;
+}
+
+span.commandMenuItem {
font-size: 0.85em;
font-family: menlo,consolas,monospace;
}
diff --git a/src/main/resources/smartgithg_32x32.png b/src/main/resources/smartgithg_32x32.png Binary files differnew file mode 100644 index 00000000..63d8692c --- /dev/null +++ b/src/main/resources/smartgithg_32x32.png diff --git a/src/main/resources/sourcetree_32x32.png b/src/main/resources/sourcetree_32x32.png Binary files differnew file mode 100644 index 00000000..a5dd96fb --- /dev/null +++ b/src/main/resources/sourcetree_32x32.png |