User list. Revised home page. Updated Jetty. Secure cookies. Docs.
7 files added
20 files modified
| | |
| | | <attribute name="javadoc_location" value="jar:platform:/resource/gitblit/ext/slf4j-log4j12-1.6.1-javadoc.jar!/"/>
|
| | | </attributes>
|
| | | </classpathentry>
|
| | | <classpathentry kind="lib" path="ext/jetty-all-7.2.2.v20101205.jar" sourcepath="ext/jetty-all-7.2.2.v20101205-sources.jar">
|
| | | <attributes>
|
| | | <attribute name="javadoc_location" value="jar:platform:/resource/gitblit/ext/jetty-all-7.2.2.v20101205-javadoc.jar!/"/>
|
| | | </attributes>
|
| | | </classpathentry>
|
| | | <classpathentry kind="lib" path="ext/jcommander-1.17.jar" sourcepath="ext/jcommander-1.17-sources.jar">
|
| | | <attributes>
|
| | | <attribute name="javadoc_location" value="jar:platform:/resource/gitblit/ext/jcommander-1.17-javadoc.jar!/"/>
|
| | |
| | | <attribute name="javadoc_location" value="jar:platform:/resource/gitblit/ext/bcmail-jdk16-1.46-javadoc.jar!/"/>
|
| | | </attributes>
|
| | | </classpathentry>
|
| | | <classpathentry kind="lib" path="ext/jetty-all-7.4.1.v20110513.jar" sourcepath="ext/jetty-all-7.4.1.v20110513-sources.jar">
|
| | | <attributes>
|
| | | <attribute name="javadoc_location" value="jar:platform:/resource/gitblit/ext/jetty-all-7.2.2.v20101205-javadoc.jar!/"/>
|
| | | </attributes>
|
| | | </classpathentry>
|
| | | <classpathentry kind="output" path="bin"/>
|
| | | </classpath>
|
| | |
| | |
|
| | | <target name="main">
|
| | |
|
| | | <!-- extract version number from source code -->
|
| | | <!-- build dsate -->
|
| | | <tstamp>
|
| | | <format property="gb.buildDate" pattern="yyyy-MM-dd" />
|
| | | </tstamp>
|
| | |
|
| | | <!-- extract Git:Blit version number from source code -->
|
| | | <loadfile property="gb.version" srcfile="${basedir}/src/com/gitblit/Constants.java">
|
| | | <filterchain>
|
| | | <linecontains>
|
| | |
| | | <striplinebreaks />
|
| | | <tokenfilter>
|
| | | <replacestring from="public final static String VERSION = "" to="" />
|
| | | <replacestring from="";" to="" />
|
| | | <trim />
|
| | | </tokenfilter>
|
| | | </filterchain> |
| | | </loadfile>
|
| | |
|
| | | <!-- extract JGit version number from source code -->
|
| | | <loadfile property="jgit.version" srcfile="${basedir}/src/com/gitblit/Constants.java">
|
| | | <filterchain>
|
| | | <linecontains>
|
| | | <contains value="public final static String JGIT_VERSION = " />
|
| | | </linecontains>
|
| | | <striplinebreaks />
|
| | | <tokenfilter>
|
| | | <replacestring from="public final static String JGIT_VERSION = "" to="" />
|
| | | <replacestring from="";" to="" />
|
| | | <trim />
|
| | | </tokenfilter>
|
| | |
| | | <include name="book_16x16.png" />
|
| | | <include name="blank.png" />
|
| | | </fileset>
|
| | | |
| | |
|
| | | <!-- Copy Doc images -->
|
| | | <fileset dir="${basedir}/docs">
|
| | | <include name="*.png" />
|
| | | <include name="*.js" />
|
| | | </fileset>
|
| | | </copy>
|
| | | |
| | |
|
| | | <!-- Copy Fancybox -->
|
| | | <mkdir dir="${basedir}/site/fancybox" />
|
| | | <copy todir="${basedir}/site/fancybox"> |
| | | <fileset dir="${basedir}/docs/fancybox" >
|
| | | <copy todir="${basedir}/site/fancybox">
|
| | | <fileset dir="${basedir}/docs/fancybox">
|
| | | <exclude name="thumbs.db" />
|
| | | </fileset>
|
| | | </copy>
|
| | | |
| | |
|
| | | <!-- Copy screenshot thumbnails -->
|
| | | <mkdir dir="${basedir}/site/thumbs" />
|
| | | <copy todir="${basedir}/site/thumbs">
|
| | |
| | | <include name="*.png" />
|
| | | </fileset>
|
| | | </copy>
|
| | | |
| | |
|
| | | <!-- Copy screenshots -->
|
| | | <mkdir dir="${basedir}/site/screenshots" />
|
| | | <copy todir="${basedir}/site/screenshots">
|
| | |
| | | </fileset>
|
| | | </copy>
|
| | |
|
| | | <!-- Build site pages -->
|
| | | <java classpath="${project.build.dir}" classname="com.gitblit.BuildSite">
|
| | | <classpath refid="master-classpath" />
|
| | | <arg value="--sourceFolder" />
|
| | | <arg value="${basedir}/docs" />
|
| | | |
| | |
|
| | | <arg value="--outputFolder" />
|
| | | <arg value="${basedir}/site" />
|
| | |
|
| | |
| | |
|
| | | <arg value="--pageFooter" />
|
| | | <arg value="${basedir}/docs/page_footer.html" />
|
| | | |
| | |
|
| | | <arg value="--alias" />
|
| | | <arg value="index=overview" />
|
| | |
|
| | | <arg value="--substitute" />
|
| | | <arg value="%VERSION%=${gb.version}" />
|
| | |
|
| | | <arg value="--substitute" />
|
| | | <arg value="%DISTRIBUTION%=${distribution.zipfile}" />
|
| | |
|
| | | <arg value="--substitute" />
|
| | | <arg value="%BUILDDATE%=${gb.buildDate}" />
|
| | |
|
| | | <arg value="--substitute" />
|
| | | <arg value="%JGIT%=${jgit.version}" />
|
| | | </java>
|
| | |
|
| | | </target>
|
| | |
| | | # Choose how to present the repositories list.
|
| | | # grouped = group nested/subfolder repositories together (no sorting)
|
| | | # flat = flat list of repositories (sorting allowed)
|
| | | web.repositoryListType = flat
|
| | | web.repositoryListType = grouped
|
| | |
|
| | | # If using a grouped repository list and there are repositories at the
|
| | | # root level of your repositories folder, you may specify the displayed
|
| | |
| | | ## Overview
|
| | | Git:Blit is an open-source, integrated pure Java stack for managing, viewing, and serving [Git][git] repositories.
|
| | | Its designed primarily as a tool for small workgroups who want to host [Git][git] repositories on a Windows machine.
|
| | |
|
| | | Of course, since its pure Java it should run with any JVM on any platform, but there are already [many compelling Git solutions](https://git.wiki.kernel.org/index.php/InterfacesFrontendsAndTools) for non-Windows environments.
|
| | | Its designed primarily as a tool for small workgroups who want to host [Git][git] repositories on a Windows machine. Having said that, it works equally well on any standard Linux distribution.
|
| | |
|
| | | ### Current Version
|
| | |
|
| | | [{0}](http://gitblit.com/{1}) based on [{2}][jgit] (*{3}*)
|
| | | [%VERSION%](http://gitblit.com/%DISTRIBUTION%) based on [%JGIT%][jgit] (*%BUILDDATE%*)
|
| | |
|
| | | sources @ [Github][gitbltsrc]
|
| | |
|
| | | ### Design Principles
|
| | | 1. [KISS](http://en.wikipedia.org/wiki/KISS_principle)
|
| | | 2. Offer useful features for serving Git repositories. If feature is complex, refer to #1.
|
| | | 3. All dependencies must be retrievable from a publicly accessible Maven repository.<br/>This is to ensure authenticity of dependencies and to keep the Git:Blit distribution svelte. |
| | | 3. All dependencies must be retrievable from a publicly accessible [Maven](http://maven.apache.org) repository.<br/>This is to ensure authenticity of dependencies and to keep the Git:Blit distribution svelte. |
| | |
|
| | | ### Features
|
| | | - Out-of-the-box integrated stack requiring minimal configuration
|
| | |
| | | </ul>
|
| | | - Gitweb inspired UI
|
| | | - Administrators may create, edit, rename, or delete repositories through the web UI
|
| | | - Administrators may create, edit, rename, or delete users through the web UI
|
| | | - Administrators may create, edit, or delete users through the web UI
|
| | | - Repository Owners may edit repositories through the web UI
|
| | | - Automatically generates a self-signed certificate for https communications
|
| | | - Dates can optionally be displayed using the browser''s reported timezone
|
| | |
| | | - Git:Blit is an integrated, full-stack solution. There is no WAR build at this time.
|
| | |
|
| | | ### Todo List
|
| | | - Manual certificate generation with BouncyCastle
|
| | | - User list with edit and delete links
|
| | | - Review spots where Git:Blit can cache data instead of abusing the disk
|
| | | - stats
|
| | | - users.properties access
|
| | |
| | |
|
| | | - [google-code-prettify](http://code.google.com/p/google-code-prettify) (Apache 2.0)
|
| | | - [JavaService](http://forge.ow2.org/projects/javaservice) (BSD and LGPL)
|
| | | - icons courtesy of [FatCow Hosting](http://www.fatcow.com/free-icons) (Creative Commons CC-BY)
|
| | | - magnifying glass search icon courtesy of [Gnome](http://gnome.org) (Creative Commons CC-BY)
|
| | | - modified Git logo originally designed by [Henrik Nyh](http://henrik.nyh.se/2007/06/alternative-git-logo-and-favicon)
|
| | | - other icons courtesy of [FatCow Hosting](http://www.fatcow.com/free-icons) (Creative Commons CC-BY)
|
| | |
|
| | | ### Downloaded Dependencies
|
| | | The following dependencies are automatically downloaded from the Apache Maven repository and from the Eclipse Maven repository when Git:Blit is launched for the first time.
|
| | |
| | | ## Setup and Configuration
|
| | |
|
| | | 1. Download and unzip Git:Blit.<br/>
|
| | | 1. Download and unzip [%VERSION%](http://gitblit.com/%DISTRIBUTION%).<br/>
|
| | | *Its best to eliminate spaces in the path name as that can cause troubleshooting headaches.*
|
| | | 2. The server itself is configured through a simple text file.<br/>
|
| | | Open `gitblit.properties` in your favorite text editor and make sure to review and set:
|
| | |
| | | No. Git:Blit is based on [JGit][jgit] which is a pure Java implementation of the [Git version control system][git].<br/>
|
| | | Everything you need for Git:Blit is either in the zip distribution file or automatically downloaded on execution.
|
| | |
|
| | | ### Why doesn't Git:Blit support SSH?
|
| | | Git:Blit could integrate [Apache Mina](http://mina.apache.org) to provide SSH access. However, doing so violates design principle #1: KISS. SSH supports requires creating, exchanging, and managing SSH keys. While this is doable, its not simple like JGit's SmartHTTP implementation.
|
| | | ### Does Git:Blit use a database to store its data?
|
| | | No. Git:Blit stores its repository configuration information within the `.git/config` file and its user information in `users.properties` or whatever filename is configured in `gitblit.properties`.
|
| | |
|
| | | You might consider [Gerrit](http://gerrit.googlecode.org) which supports SSH.
|
| | | ### I want to deploy Git:Blit into my own servlet container. Where is the WAR?
|
| | | At this time there is no WAR build available.
|
| | |
|
| | | ### Why doesn't Git:Blit support SSH?
|
| | | Git:Blit could integrate [Apache Mina][mina] to provide SSH access. However, doing so violates Git:Blit's first design principle: [KISS](http://en.wikipedia.org/wiki/KISS_principle).<br/>
|
| | | SSH supports requires creating, exchanging, and managing SSH keys. While this is doable, its not simple like JGit's SmartHTTP implementation.
|
| | |
|
| | | You might consider running [Gerrit](http://gerrit.googlecode.org) which does integrate [Apache Mina][mina] and supports SSH or you might consider serving [Git][git] on Linux which would offer real SSH support and also allow use of [many other compelling Git solutions](https://git.wiki.kernel.org/index.php/InterfacesFrontendsAndTools).
|
| | |
|
| | | ### What types of Search does Git:Blit support?
|
| | | Git:Blit supports case-insensitive searches of *commit message* (default), *author*, and *committer*.<br/>
|
| | |
| | | Alternatively, you could enable the search type dropdown list in your `gitblit.properties` file.
|
| | |
|
| | | ### How do I run Git:Blit on port 80 or 443 in Linux?
|
| | | Tricky. Linux requires root permissions to serve on ports < 1024.<br/>
|
| | | Linux requires root permissions to serve on ports < 1024.<br/>
|
| | | Run the server as *root* (security concern) or change the ports you are serving to 8080 (http) or 8443 (https).
|
| | |
|
| | | [bitblt]: http://en.wikipedia.org/wiki/Bit_blit "Wikipedia Bitblt"
|
| | | [jgit]: http://eclipse.org/jgit "Eclipse JGit Site"
|
| | | [git]: http://git-scm.com "Official Git Site" |
| | | [git]: http://git-scm.com "Official Git Site"
|
| | | [mina]: http://mina.apache.org " Apache Mina" |
| | |
| | | ## Screenshots
|
| | | <table class="screenshots">
|
| | | <tr><td>
|
| | | <a rel="screenshots_group" href="screenshots/00.png" title="Repository List"></a>
|
| | | <br/>Repository List
|
| | | <a rel="screenshots_group" href="screenshots/00.png" title="Repository & User List"></a>
|
| | | <br/>Repository & User List
|
| | | </td><td>
|
| | | <a rel="screenshots_group" href="screenshots/01.png" title="New User"></a>
|
| | | <br/>New User
|
| | |
| | |
|
| | | public static final MavenObject JCOMMANDER = new MavenObject("jCommander", "com/beust", "jcommander", "1.17", 34000, 32000, 141000, "219a3540f3b27d7cc3b1d91d6ea046cd8723290e", "0bb50eec177acf0e94d58e0cf07262fe5164331d", "c7adc475ca40c288c93054e0f4fe58f3a98c0cb5");
|
| | |
|
| | | public static final MavenObject JETTY = new MavenObject("Jetty", "org/eclipse/jetty/aggregate", "jetty-all", "7.2.2.v20101205", 1430000, 965000, 3871000, "b9b7c812a732721c427e208c54fbb71ca17a2ee1", "cbc4fc72c4a646d8822bf7369c2101d4d5d1ff98", "34c87e11bba426fe97bfe23ccff12eda477c8f57");
|
| | | public static final MavenObject JETTY = new MavenObject("Jetty", "org/eclipse/jetty/aggregate", "jetty-all", "7.4.1.v20110513", 1500000, 1000000, 4100000, "1e2de9ed25a7c6ae38717d5ffdc7cfcd6be4bd46", "7b6279d16ce8f663537d9faf55ea353e748dbbaa", "fa06212e751296f1a7abc15c843b135bf49a112b");
|
| | |
|
| | | public static final MavenObject SERVLET = new MavenObject("Servlet 2.5", "javax/servlet", "servlet-api", "2.5", 105000, 158000, 0, "5959582d97d8b61f4d154ca9e495aafd16726e34", "021599814ad9a605b86f3e6381571beccd861a32", null);
|
| | |
|
| | |
| | | Arrays.sort(markdownFiles);
|
| | |
|
| | | Map<String, String> aliasMap = new HashMap<String, String>();
|
| | | for (String alias:params.aliases) {
|
| | | String [] values = alias.split("=");
|
| | | for (String alias : params.aliases) {
|
| | | String[] values = alias.split("=");
|
| | | aliasMap.put(values[0], values[1]);
|
| | | }
|
| | | |
| | |
|
| | | System.out.println(MessageFormat.format("Generating site from {0} Markdown Docs in {1} ", markdownFiles.length, sourceFolder.getAbsolutePath()));
|
| | | String linkPattern = "<a href=''{0}''>{1}</a>";
|
| | | StringBuilder sb = new StringBuilder();
|
| | |
| | | }
|
| | | sb.setLength(sb.length() - 3);
|
| | | sb.trimToSize();
|
| | | |
| | |
|
| | | String html_header = readContent(new File(params.pageHeader));
|
| | | String html_footer = readContent(new File(params.pageFooter));
|
| | | final String links = sb.toString();
|
| | |
| | | for (File file : markdownFiles) {
|
| | | try {
|
| | | String documentName = getDocumentName(file);
|
| | | String displayName = documentName;
|
| | | if (aliasMap.containsKey(documentName)) {
|
| | | displayName = aliasMap.get(documentName);
|
| | | }
|
| | | String fileName = documentName + ".html";
|
| | | System.out.println(MessageFormat.format(" {0} => {1}", file.getName(), fileName));
|
| | | InputStreamReader reader = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
|
| | | String content = MarkdownUtils.transformMarkdown(reader);
|
| | | if (displayName.equalsIgnoreCase("overview")) {
|
| | | content = MessageFormat.format(content, Constants.VERSION, "gitblit-" + Constants.VERSION + ".zip", Constants.getJGitVersion(), date);
|
| | | for (String token : params.substitutions) {
|
| | | String [] kv = token.split("=");
|
| | | content = content.replace(kv[0], kv[1]);
|
| | | }
|
| | | OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(destinationFolder, fileName)), Charset.forName("UTF-8"));
|
| | | writer.write(header);
|
| | |
| | | // trim leading ##_ which is to control display order
|
| | | return displayName.substring(3);
|
| | | }
|
| | | |
| | |
|
| | | private static void usage(JCommander jc, ParameterException t) {
|
| | | System.out.println(Constants.getRunningVersion());
|
| | | System.out.println();
|
| | |
| | | }
|
| | | System.exit(0);
|
| | | }
|
| | | |
| | |
|
| | | @Parameters(separators = " ")
|
| | | private static class Params {
|
| | |
|
| | |
| | | @Parameter(names = { "--alias" }, description = "Filename=Linkname aliases", required = false)
|
| | | public List<String> aliases = new ArrayList<String>();
|
| | |
|
| | | @Parameter(names = { "--substitute" }, description = "@TOKEN@=value", required = false)
|
| | | public List<String> substitutions = new ArrayList<String>();
|
| | |
|
| | | }
|
| | | }
|
| | |
| | | // and only use A-Z a-z 0-9 .-_ in the string.
|
| | | public final static String VERSION = "0.1.0-SNAPSHOT";
|
| | |
|
| | | // The build script extracts this exact line so be careful editing it
|
| | | // and only use A-Z a-z 0-9 .-_ in the string.
|
| | | public final static String JGIT_VERSION = "JGit 0.12.1";
|
| | |
|
| | | public final static String ADMIN_ROLE = "#admin";
|
| | |
|
| | | public final static String PROPERTIES_FILE = "gitblit.properties";
|
| | |
| | | }
|
| | |
|
| | | public static String getJGitVersion() {
|
| | | return "JGit 0.12.1";
|
| | | return JGIT_VERSION;
|
| | | }
|
| | |
|
| | | public static String getRunningVersion() {
|
| | |
| | | import org.eclipse.jetty.server.Server;
|
| | | import org.eclipse.jetty.server.bio.SocketConnector;
|
| | | import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
| | | import org.eclipse.jetty.server.session.HashSessionManager;
|
| | | import org.eclipse.jetty.server.ssl.SslConnector;
|
| | | import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
| | | import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
| | |
| | | rootContext.setServer(server);
|
| | | rootContext.setWar(location.toExternalForm());
|
| | | rootContext.setTempDirectory(tempDir);
|
| | | |
| | | // Mark all cookies HttpOnly so they are not accessible to JavaScript
|
| | | // engines.
|
| | | // http://erlend.oftedal.no/blog/?blogid=33
|
| | | // https://www.owasp.org/index.php/HttpOnly#Browsers_Supporting_HttpOnly
|
| | | HashSessionManager sessionManager = new HashSessionManager();
|
| | | sessionManager.setHttpOnly(true);
|
| | | // Use secure cookies if only serving https
|
| | | sessionManager.setSecureCookies(params.port <= 0 && params.securePort > 0);
|
| | | rootContext.getSessionHandler().setSessionManager(sessionManager);
|
| | |
|
| | | // Wicket Filter
|
| | | String wicketPathSpec = "/*";
|
| | |
| | | gb.blame = blame
|
| | | gb.login = Login
|
| | | gb.logout = Logout
|
| | | gb.username = Username
|
| | | gb.password = Password
|
| | | gb.username = username
|
| | | gb.password = password
|
| | | gb.tagger = tagger
|
| | | gb.moreHistory = more history...
|
| | | gb.difftocurrent = diff to current
|
| | |
| | | return new ContextRelativeResource("/com/gitblit/wicket/resources/" + file);
|
| | | }
|
| | |
|
| | | public static PageParameters newUsernameParameter(String username) {
|
| | | return new PageParameters("user=" + username);
|
| | | }
|
| | |
|
| | | public static PageParameters newRepositoryParameter(String repositoryName) {
|
| | | return new PageParameters("r=" + repositoryName);
|
| | | }
|
| | |
| | | <form wicket:id="editForm">
|
| | | <table class="plain">
|
| | | <tbody>
|
| | | <tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input type="text" wicket:id="username" id="username" size="30" tabindex="1" /></td></tr>
|
| | | <tr><th><wicket:message key="gb.username"></wicket:message></th><td class="edit"><input type="text" wicket:id="username" id="username" size="30" tabindex="1" /></td></tr>
|
| | | <tr><th><wicket:message key="gb.password"></wicket:message></th><td class="edit"><input type="password" wicket:id="password" size="30" tabindex="2" /></td></tr>
|
| | | <tr><th><wicket:message key="gb.confirmPassword"></wicket:message></th><td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="3" /></td></tr>
|
| | | <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <i><wicket:message key="gb.canAdminDescription"></wicket:message></i></td></tr>
|
| | |
| | |
|
| | | <div class="markdown" style="margin-top:-0.5em;padding-bottom:5px;" wicket:id="repositoriesMessage">[repositories message]</div>
|
| | |
|
| | | <div wicket:id="adminPanel">[admin links]</div>
|
| | | |
| | | <table class="repositories">
|
| | | <span wicket:id="headerContent"></span>
|
| | | <tbody> |
| | | <tr wicket:id="row">
|
| | | <span wicket:id="rowContent"></span>
|
| | | </tr>
|
| | | </tbody>
|
| | | </table>
|
| | | |
| | | <wicket:fragment wicket:id="adminLinks">
|
| | | <!-- page nav links --> |
| | | <div style="text-align: right;" class="admin_nav">
|
| | | <a wicket:id="newRepository"><wicket:message key="gb.newRepository"></wicket:message></a> | <a wicket:id="newUser"><wicket:message key="gb.newUser"></wicket:message></a> | <a wicket:id="editUsers"><wicket:message key="gb.editUsers"></wicket:message></a>
|
| | | </div> |
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="repositoryAdminLinks">
|
| | | <span class="link"><a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a> | <a wicket:id="renameRepository"><wicket:message key="gb.rename">[rename]</wicket:message></a> | <a wicket:id="deleteRepository"><wicket:message key="gb.delete">[delete]</wicket:message></a></span>
|
| | | </wicket:fragment>
|
| | | <div wicket:id="repositoriesPanel">[repositories panel]</div>
|
| | |
|
| | | <wicket:fragment wicket:id="repositoryOwnerLinks">
|
| | | <span class="link"><a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a></span>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="flatHeader">
|
| | | <tr>
|
| | | <th wicket:id="orderByRepository"><wicket:message key="gb.repository">Repository</wicket:message></th>
|
| | | <th wicket:id="orderByDescription"><wicket:message key="gb.description">Description</wicket:message></th>
|
| | | <th wicket:id="orderByOwner"><wicket:message key="gb.owner">Owner</wicket:message></th>
|
| | | <th></th>
|
| | | <th wicket:id="orderByDate"><wicket:message key="gb.lastChange">Last Change</wicket:message></th>
|
| | | <th></th>
|
| | | </tr>
|
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="groupHeader">
|
| | | <tr>
|
| | | <th><wicket:message key="gb.repository">Repository</wicket:message></th>
|
| | | <th><wicket:message key="gb.description">Description</wicket:message></th>
|
| | | <th><wicket:message key="gb.owner">Owner</wicket:message></th>
|
| | | <th></th>
|
| | | <th><wicket:message key="gb.lastChange">Last Change</wicket:message></th>
|
| | | <th></th>
|
| | | </tr>
|
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="groupRow">
|
| | | <td colspan="6"><span wicket:id="groupName">[group name]</span></td>
|
| | | </wicket:fragment>
|
| | | <div style="padding-top: 10px;"wicket:id="usersPanel">[users panel]</div>
|
| | |
|
| | | <wicket:fragment wicket:id="repositoryRow">
|
| | | <td><div class="list" wicket:id="repositoryName">[repository name]</div></td>
|
| | | <td><div class="list" wicket:id="repositoryDescription">[repository description]</div></td>
|
| | | <td class="author"><span wicket:id="repositoryOwner">[repository owner]</span></td>
|
| | | <td style="text-align: right;padding-right:10px;"><img class="inlineIcon" wicket:id="ticketsIcon" /><img class="inlineIcon" wicket:id="docsIcon" /><img class="inlineIcon" wicket:id="frozenIcon" /><img class="inlineIcon" wicket:id="accessRestrictionIcon" /></td>
|
| | | <td><span wicket:id="repositoryLastChange">[last change]</span></td>
|
| | | <td class="rightAlign"><span wicket:id="repositoryLinks"></span></td>
|
| | | </wicket:fragment>
|
| | | |
| | | </wicket:extend>
|
| | | </body>
|
| | | </html> |
| | |
| | | import java.io.FileReader;
|
| | | import java.io.InputStream;
|
| | | import java.io.InputStreamReader;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Collections;
|
| | | import java.util.Comparator;
|
| | | import java.util.Date;
|
| | | import java.util.HashMap;
|
| | | import java.util.Iterator;
|
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | |
|
| | | import org.apache.wicket.Component;
|
| | | import org.apache.wicket.PageParameters;
|
| | | import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;
|
| | | import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
|
| | | import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | 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.IDataProvider;
|
| | | import org.apache.wicket.markup.repeater.data.ListDataProvider;
|
| | | import org.apache.wicket.model.IModel;
|
| | | import org.apache.wicket.model.Model;
|
| | | import org.apache.wicket.resource.ContextRelativeResource;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.utils.MarkdownUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.TimeUtils;
|
| | | import com.gitblit.wicket.BasePage;
|
| | | import com.gitblit.wicket.GitBlitWebSession;
|
| | | import com.gitblit.wicket.LinkPanel;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.models.RepositoryModel;
|
| | | import com.gitblit.wicket.models.UserModel;
|
| | | import com.gitblit.wicket.panels.RepositoriesPanel;
|
| | | import com.gitblit.wicket.panels.UsersPanel;
|
| | |
|
| | | public class RepositoriesPage extends BasePage {
|
| | |
|
| | | public RepositoriesPage() {
|
| | | super();
|
| | | setupPage("", "");
|
| | | |
| | |
|
| | | final boolean showAdmin;
|
| | | if (GitBlit.self().settings().getBoolean(Keys.web.authenticateAdminPages, true)) {
|
| | | boolean allowAdmin = GitBlit.self().settings().getBoolean(Keys.web.allowAdministration, false);
|
| | |
| | | setStatelessHint(true);
|
| | | }
|
| | | }
|
| | |
|
| | | Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);
|
| | | adminLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));
|
| | | adminLinks.add(new BookmarkablePageLink<Void>("newUser", EditUserPage.class));
|
| | | adminLinks.add(new BookmarkablePageLink<Void>("editUsers", RepositoriesPage.class));
|
| | | add(adminLinks.setVisible(showAdmin));
|
| | |
|
| | | // display an error message cached from a redirect
|
| | | String cachedMessage = GitBlitWebSession.get().clearErrorMessage();
|
| | |
| | | }
|
| | | Component repositoriesMessage = new Label("repositoriesMessage", message).setEscapeModelStrings(false);
|
| | | add(repositoriesMessage);
|
| | |
|
| | | final Map<AccessRestrictionType, String> accessRestrictionTranslations = getAccessRestrictions();
|
| | | final UserModel user = GitBlitWebSession.get().getUser();
|
| | | List<RepositoryModel> models = GitBlit.self().getRepositoryModels(user);
|
| | | IDataProvider<RepositoryModel> dp;
|
| | | |
| | | if (GitBlit.self().settings().getString(Keys.web.repositoryListType, "flat").equalsIgnoreCase("grouped")) {
|
| | | Map<String, List<RepositoryModel>> groups = new HashMap<String, List<RepositoryModel>>();
|
| | | for (RepositoryModel model : models) {
|
| | | String rootPath = StringUtils.getRootPath(model.name);
|
| | | if (StringUtils.isEmpty(rootPath)) {
|
| | | rootPath = GitBlit.self().settings().getString(Keys.web.repositoryRootGroupName, " ");
|
| | | }
|
| | | if (!groups.containsKey(rootPath)) {
|
| | | groups.put(rootPath, new ArrayList<RepositoryModel>());
|
| | | }
|
| | | groups.get(rootPath).add(model);
|
| | | }
|
| | | List<String> roots = new ArrayList<String>(groups.keySet());
|
| | | Collections.sort(roots);
|
| | | List<RepositoryModel> groupedModels = new ArrayList<RepositoryModel>();
|
| | | for (String root : roots) {
|
| | | groupedModels.add(new GroupRepositoryModel(root));
|
| | | groupedModels.addAll(groups.get(root));
|
| | | }
|
| | | dp = new ListDataProvider<RepositoryModel>(groupedModels);
|
| | | } else {
|
| | | dp = new DataProvider(models);
|
| | | }
|
| | |
|
| | | DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("row", dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | | int counter = 0;
|
| | |
|
| | | public void populateItem(final Item<RepositoryModel> item) {
|
| | | final RepositoryModel entry = item.getModelObject();
|
| | | if (entry instanceof GroupRepositoryModel) {
|
| | | Fragment row = new Fragment("rowContent", "groupRow", this);
|
| | | item.add(row);
|
| | | row.add(new Label("groupName", entry.name));
|
| | | WicketUtils.setCssClass(item, "group");
|
| | | return;
|
| | | }
|
| | | Fragment row = new Fragment("rowContent", "repositoryRow", this);
|
| | | item.add(row);
|
| | | if (entry.hasCommits) {
|
| | | // Existing repository
|
| | | PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);
|
| | | row.add(new LinkPanel("repositoryName", "list", entry.name, SummaryPage.class, pp));
|
| | | row.add(new LinkPanel("repositoryDescription", "list", entry.description, SummaryPage.class, pp));
|
| | | } else {
|
| | | // New repository
|
| | | row.add(new Label("repositoryName", entry.name + "<span class='empty'>(empty)</span>").setEscapeModelStrings(false));
|
| | | row.add(new Label("repositoryDescription", entry.description));
|
| | | }
|
| | |
|
| | | if (entry.useTickets) {
|
| | | row.add(WicketUtils.newImage("ticketsIcon", "bug_16x16.png", getString("gb.tickets")));
|
| | | } else {
|
| | | row.add(WicketUtils.newBlankImage("ticketsIcon"));
|
| | | }
|
| | |
|
| | | if (entry.useDocs) {
|
| | | row.add(WicketUtils.newImage("docsIcon", "book_16x16.png", getString("gb.docs")));
|
| | | } else {
|
| | | row.add(WicketUtils.newBlankImage("docsIcon"));
|
| | | }
|
| | |
|
| | | if (entry.isFrozen) {
|
| | | row.add(WicketUtils.newImage("frozenIcon", "cold_16x16.png", getString("gb.isFrozen")));
|
| | | } else {
|
| | | row.add(WicketUtils.newClearPixel("frozenIcon").setVisible(false));
|
| | | }
|
| | | switch (entry.accessRestriction) {
|
| | | case NONE:
|
| | | row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
|
| | | break;
|
| | | case PUSH:
|
| | | row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
|
| | | break;
|
| | | case CLONE:
|
| | | row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
|
| | | break;
|
| | | case VIEW:
|
| | | row.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
|
| | | break;
|
| | | default:
|
| | | row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
|
| | | }
|
| | |
|
| | | row.add(new Label("repositoryOwner", entry.owner));
|
| | |
|
| | | String lastChange = TimeUtils.timeAgo(entry.lastChange);
|
| | | Label lastChangeLabel = new Label("repositoryLastChange", lastChange);
|
| | | row.add(lastChangeLabel);
|
| | | WicketUtils.setCssClass(lastChangeLabel, TimeUtils.timeAgoCss(entry.lastChange));
|
| | |
|
| | | boolean showOwner = user != null && user.getUsername().equalsIgnoreCase(entry.owner); |
| | | if (showAdmin) {
|
| | | Fragment repositoryLinks = new Fragment("repositoryLinks", "repositoryAdminLinks", this);
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("editRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)));
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("renameRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)).setEnabled(false));
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("deleteRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)).setEnabled(false));
|
| | | row.add(repositoryLinks);
|
| | | } else if (showOwner) {
|
| | | Fragment repositoryLinks = new Fragment("repositoryLinks", "repositoryOwnerLinks", this);
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("editRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)));
|
| | | row.add(repositoryLinks);
|
| | | } else {
|
| | | row.add(new Label("repositoryLinks"));
|
| | | }
|
| | | WicketUtils.setAlternatingBackground(item, counter);
|
| | | counter++;
|
| | | }
|
| | | };
|
| | | add(dataView);
|
| | |
|
| | | if (dp instanceof SortableDataProvider<?>) {
|
| | | // add sortable header
|
| | | SortableDataProvider<?> sdp = (SortableDataProvider<?>) dp;
|
| | | Fragment fragment = new Fragment("headerContent", "flatHeader", this);
|
| | | fragment.add(newSort("orderByRepository", SortBy.repository, sdp, dataView));
|
| | | fragment.add(newSort("orderByDescription", SortBy.description, sdp, dataView));
|
| | | fragment.add(newSort("orderByOwner", SortBy.owner, sdp, dataView));
|
| | | fragment.add(newSort("orderByDate", SortBy.date, sdp, dataView));
|
| | | add(fragment);
|
| | | } else {
|
| | | // not sortable
|
| | | Fragment fragment = new Fragment("headerContent", "groupHeader", this);
|
| | | add(fragment);
|
| | | }
|
| | | }
|
| | |
|
| | | protected enum SortBy {
|
| | | repository, description, owner, date;
|
| | | }
|
| | |
|
| | | protected OrderByBorder newSort(String wicketId, SortBy field, SortableDataProvider<?> dp, final DataView<?> dataView) {
|
| | | return new OrderByBorder(wicketId, field.name(), dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | @Override
|
| | | protected void onSortChanged() {
|
| | | dataView.setCurrentPage(0);
|
| | | }
|
| | | };
|
| | | }
|
| | |
|
| | | private class DataProvider extends SortableDataProvider<RepositoryModel> {
|
| | | private static final long serialVersionUID = 1L;
|
| | | private List<RepositoryModel> list = null;
|
| | |
|
| | | protected DataProvider(List<RepositoryModel> list) {
|
| | | this.list = list;
|
| | | setSort(SortBy.date.name(), false);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int size() {
|
| | | if (list == null)
|
| | | return 0;
|
| | | return list.size();
|
| | | }
|
| | |
|
| | | @Override
|
| | | public IModel<RepositoryModel> model(RepositoryModel header) {
|
| | | return new Model<RepositoryModel>(header);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public Iterator<RepositoryModel> iterator(int first, int count) {
|
| | | SortParam sp = getSort();
|
| | | String prop = sp.getProperty();
|
| | | final boolean asc = sp.isAscending();
|
| | |
|
| | | if (prop == null || prop.equals(SortBy.date.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.lastChange.compareTo(o2.lastChange);
|
| | | return o2.lastChange.compareTo(o1.lastChange);
|
| | | }
|
| | | });
|
| | | } else if (prop.equals(SortBy.repository.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.name.compareTo(o2.name);
|
| | | return o2.name.compareTo(o1.name);
|
| | | }
|
| | | });
|
| | | } else if (prop.equals(SortBy.owner.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.owner.compareTo(o2.owner);
|
| | | return o2.owner.compareTo(o1.owner);
|
| | | }
|
| | | });
|
| | | } else if (prop.equals(SortBy.description.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.description.compareTo(o2.description);
|
| | | return o2.description.compareTo(o1.description);
|
| | | }
|
| | | });
|
| | | }
|
| | | return list.subList(first, first + count).iterator();
|
| | | }
|
| | | }
|
| | |
|
| | | private class GroupRepositoryModel extends RepositoryModel {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | GroupRepositoryModel(String name) {
|
| | | super(name, "", "", new Date(0));
|
| | | }
|
| | | add(new RepositoriesPanel("repositoriesPanel", showAdmin, getAccessRestrictions())); |
| | | add(new UsersPanel("usersPanel", showAdmin).setVisible(showAdmin));
|
| | | }
|
| | | }
|
New file |
| | |
| | | <!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 wicket:id="adminPanel">[admin links]</div>
|
| | |
|
| | | <table class="repositories">
|
| | | <span wicket:id="headerContent"></span>
|
| | | <tbody> |
| | | <tr wicket:id="row">
|
| | | <span wicket:id="rowContent"></span>
|
| | | </tr>
|
| | | </tbody>
|
| | | </table>
|
| | | |
| | | <wicket:fragment wicket:id="adminLinks">
|
| | | <!-- page nav links --> |
| | | <div class="admin_nav">
|
| | | <wicket:link>
|
| | | <img style="vertical-align: top;" src="/com/gitblit/wicket/resources/add_16x16.png"/>
|
| | | </wicket:link> |
| | | <a wicket:id="newRepository">
|
| | | <wicket:message key="gb.newRepository"></wicket:message>
|
| | | </a>
|
| | | </div> |
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="repositoryAdminLinks">
|
| | | <span class="link"><a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a> | <a wicket:id="renameRepository"><wicket:message key="gb.rename">[rename]</wicket:message></a> | <a wicket:id="deleteRepository"><wicket:message key="gb.delete">[delete]</wicket:message></a></span>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="repositoryOwnerLinks">
|
| | | <span class="link"><a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a></span>
|
| | | </wicket:fragment>
|
| | |
|
| | | <wicket:fragment wicket:id="flatRepositoryHeader">
|
| | | <tr>
|
| | | <th class="left" wicket:id="orderByRepository">
|
| | | <wicket:link>
|
| | | <img style="vertical-align: top; border: 1px solid #888;" src="/com/gitblit/wicket/resources/gitweb-favicon.png"/>
|
| | | </wicket:link>
|
| | | <wicket:message key="gb.repository">Repository</wicket:message>
|
| | | </th>
|
| | | <th wicket:id="orderByDescription"><wicket:message key="gb.description">Description</wicket:message></th>
|
| | | <th wicket:id="orderByOwner"><wicket:message key="gb.owner">Owner</wicket:message></th>
|
| | | <th></th>
|
| | | <th wicket:id="orderByDate"><wicket:message key="gb.lastChange">Last Change</wicket:message></th>
|
| | | <th clas="right"></th>
|
| | | </tr>
|
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="groupRepositoryHeader">
|
| | | <tr>
|
| | | <th class="left">
|
| | | <wicket:link>
|
| | | <img style="vertical-align: top; border: 1px solid #888;" src="/com/gitblit/wicket/resources/gitweb-favicon.png"/>
|
| | | </wicket:link>
|
| | | <wicket:message key="gb.repository">Repository</wicket:message>
|
| | | </th>
|
| | | <th><wicket:message key="gb.description">Description</wicket:message></th>
|
| | | <th><wicket:message key="gb.owner">Owner</wicket:message></th>
|
| | | <th></th>
|
| | | <th><wicket:message key="gb.lastChange">Last Change</wicket:message></th>
|
| | | <th class="right"></th>
|
| | | </tr>
|
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="groupRepositoryRow">
|
| | | <td colspan="6"><span wicket:id="groupName">[group name]</span></td>
|
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="repositoryRow">
|
| | | <td class="left"><div class="list" wicket:id="repositoryName">[repository name]</div></td>
|
| | | <td><div class="list" wicket:id="repositoryDescription">[repository description]</div></td>
|
| | | <td class="author"><span wicket:id="repositoryOwner">[repository owner]</span></td>
|
| | | <td style="text-align: right;padding-right:10px;"><img class="inlineIcon" wicket:id="ticketsIcon" /><img class="inlineIcon" wicket:id="docsIcon" /><img class="inlineIcon" wicket:id="frozenIcon" /><img class="inlineIcon" wicket:id="accessRestrictionIcon" /></td>
|
| | | <td><span wicket:id="repositoryLastChange">[last change]</span></td>
|
| | | <td class="rightAlign"><span wicket:id="repositoryLinks"></span></td>
|
| | | </wicket:fragment>
|
| | | |
| | | </wicket:panel>
|
| | | </body>
|
| | | </html> |
New file |
| | |
| | | package com.gitblit.wicket.panels;
|
| | |
|
| | | import java.util.ArrayList;
|
| | | import java.util.Collections;
|
| | | import java.util.Comparator;
|
| | | import java.util.Date;
|
| | | import java.util.HashMap;
|
| | | import java.util.Iterator;
|
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | |
|
| | | import org.apache.wicket.PageParameters;
|
| | | import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;
|
| | | import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
|
| | | import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
|
| | | import org.apache.wicket.markup.html.basic.Label;
|
| | | 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.IDataProvider;
|
| | | import org.apache.wicket.markup.repeater.data.ListDataProvider;
|
| | | import org.apache.wicket.model.IModel;
|
| | | import org.apache.wicket.model.Model;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.TimeUtils;
|
| | | import com.gitblit.wicket.GitBlitWebSession;
|
| | | import com.gitblit.wicket.LinkPanel;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.models.RepositoryModel;
|
| | | import com.gitblit.wicket.models.UserModel;
|
| | | import com.gitblit.wicket.pages.EditRepositoryPage;
|
| | | import com.gitblit.wicket.pages.SummaryPage;
|
| | |
|
| | |
|
| | | public class RepositoriesPanel extends BasePanel {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | | |
| | | public RepositoriesPanel(String wicketId, final boolean showAdmin, final Map<AccessRestrictionType, String> accessRestrictionTranslations) {
|
| | | super(wicketId);
|
| | | |
| | | final UserModel user = GitBlitWebSession.get().getUser();
|
| | | List<RepositoryModel> models = GitBlit.self().getRepositoryModels(user);
|
| | | IDataProvider<RepositoryModel> dp;
|
| | | |
| | | Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);
|
| | | adminLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));
|
| | | add(adminLinks.setVisible(showAdmin));
|
| | | |
| | | if (GitBlit.self().settings().getString(Keys.web.repositoryListType, "flat").equalsIgnoreCase("grouped")) {
|
| | | Map<String, List<RepositoryModel>> groups = new HashMap<String, List<RepositoryModel>>();
|
| | | for (RepositoryModel model : models) {
|
| | | String rootPath = StringUtils.getRootPath(model.name);
|
| | | if (StringUtils.isEmpty(rootPath)) {
|
| | | rootPath = GitBlit.self().settings().getString(Keys.web.repositoryRootGroupName, " ");
|
| | | }
|
| | | if (!groups.containsKey(rootPath)) {
|
| | | groups.put(rootPath, new ArrayList<RepositoryModel>());
|
| | | }
|
| | | groups.get(rootPath).add(model);
|
| | | }
|
| | | List<String> roots = new ArrayList<String>(groups.keySet());
|
| | | Collections.sort(roots);
|
| | | List<RepositoryModel> groupedModels = new ArrayList<RepositoryModel>();
|
| | | for (String root : roots) {
|
| | | List<RepositoryModel> subModels = groups.get(root);
|
| | | groupedModels.add(new GroupRepositoryModel(root + " (" + subModels.size() + ")"));
|
| | | groupedModels.addAll(subModels);
|
| | | }
|
| | | dp = new ListDataProvider<RepositoryModel>(groupedModels);
|
| | | } else {
|
| | | dp = new DataProvider(models);
|
| | | }
|
| | |
|
| | | DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("row", dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | | int counter = 0;
|
| | |
|
| | | public void populateItem(final Item<RepositoryModel> item) {
|
| | | final RepositoryModel entry = item.getModelObject();
|
| | | if (entry instanceof GroupRepositoryModel) {
|
| | | Fragment row = new Fragment("rowContent", "groupRepositoryRow", this);
|
| | | item.add(row);
|
| | | row.add(new Label("groupName", entry.name));
|
| | | WicketUtils.setCssClass(item, "group");
|
| | | return;
|
| | | }
|
| | | Fragment row = new Fragment("rowContent", "repositoryRow", this);
|
| | | item.add(row);
|
| | | if (entry.hasCommits) {
|
| | | // Existing repository
|
| | | PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);
|
| | | row.add(new LinkPanel("repositoryName", "list", entry.name, SummaryPage.class, pp));
|
| | | row.add(new LinkPanel("repositoryDescription", "list", entry.description, SummaryPage.class, pp));
|
| | | } else {
|
| | | // New repository
|
| | | row.add(new Label("repositoryName", entry.name + "<span class='empty'>(empty)</span>").setEscapeModelStrings(false));
|
| | | row.add(new Label("repositoryDescription", entry.description));
|
| | | }
|
| | |
|
| | | if (entry.useTickets) {
|
| | | row.add(WicketUtils.newImage("ticketsIcon", "bug_16x16.png", getString("gb.tickets")));
|
| | | } else {
|
| | | row.add(WicketUtils.newBlankImage("ticketsIcon"));
|
| | | }
|
| | |
|
| | | if (entry.useDocs) {
|
| | | row.add(WicketUtils.newImage("docsIcon", "book_16x16.png", getString("gb.docs")));
|
| | | } else {
|
| | | row.add(WicketUtils.newBlankImage("docsIcon"));
|
| | | }
|
| | |
|
| | | if (entry.isFrozen) {
|
| | | row.add(WicketUtils.newImage("frozenIcon", "cold_16x16.png", getString("gb.isFrozen")));
|
| | | } else {
|
| | | row.add(WicketUtils.newClearPixel("frozenIcon").setVisible(false));
|
| | | }
|
| | | switch (entry.accessRestriction) {
|
| | | case NONE:
|
| | | row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
|
| | | break;
|
| | | case PUSH:
|
| | | row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
|
| | | break;
|
| | | case CLONE:
|
| | | row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
|
| | | break;
|
| | | case VIEW:
|
| | | row.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
|
| | | break;
|
| | | default:
|
| | | row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
|
| | | }
|
| | |
|
| | | row.add(new Label("repositoryOwner", entry.owner));
|
| | |
|
| | | String lastChange = TimeUtils.timeAgo(entry.lastChange);
|
| | | Label lastChangeLabel = new Label("repositoryLastChange", lastChange);
|
| | | row.add(lastChangeLabel);
|
| | | WicketUtils.setCssClass(lastChangeLabel, TimeUtils.timeAgoCss(entry.lastChange));
|
| | |
|
| | | boolean showOwner = user != null && user.getUsername().equalsIgnoreCase(entry.owner); |
| | | if (showAdmin) {
|
| | | Fragment repositoryLinks = new Fragment("repositoryLinks", "repositoryAdminLinks", this);
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("editRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)));
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("renameRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)).setEnabled(false));
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("deleteRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)).setEnabled(false));
|
| | | row.add(repositoryLinks);
|
| | | } else if (showOwner) {
|
| | | Fragment repositoryLinks = new Fragment("repositoryLinks", "repositoryOwnerLinks", this);
|
| | | repositoryLinks.add(new BookmarkablePageLink<Void>("editRepository", EditRepositoryPage.class, WicketUtils.newRepositoryParameter(entry.name)));
|
| | | row.add(repositoryLinks);
|
| | | } else {
|
| | | row.add(new Label("repositoryLinks"));
|
| | | }
|
| | | WicketUtils.setAlternatingBackground(item, counter);
|
| | | counter++;
|
| | | }
|
| | | };
|
| | | add(dataView);
|
| | |
|
| | | if (dp instanceof SortableDataProvider<?>) {
|
| | | // add sortable header
|
| | | SortableDataProvider<?> sdp = (SortableDataProvider<?>) dp;
|
| | | Fragment fragment = new Fragment("headerContent", "flatRepositoryHeader", this);
|
| | | fragment.add(newSort("orderByRepository", SortBy.repository, sdp, dataView));
|
| | | fragment.add(newSort("orderByDescription", SortBy.description, sdp, dataView));
|
| | | fragment.add(newSort("orderByOwner", SortBy.owner, sdp, dataView));
|
| | | fragment.add(newSort("orderByDate", SortBy.date, sdp, dataView));
|
| | | add(fragment);
|
| | | } else {
|
| | | // not sortable
|
| | | Fragment fragment = new Fragment("headerContent", "groupRepositoryHeader", this);
|
| | | add(fragment);
|
| | | }
|
| | | }
|
| | | |
| | | private class GroupRepositoryModel extends RepositoryModel {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | GroupRepositoryModel(String name) {
|
| | | super(name, "", "", new Date(0));
|
| | | }
|
| | | }
|
| | | |
| | | protected enum SortBy {
|
| | | repository, description, owner, date;
|
| | | }
|
| | |
|
| | | protected OrderByBorder newSort(String wicketId, SortBy field, SortableDataProvider<?> dp, final DataView<?> dataView) {
|
| | | return new OrderByBorder(wicketId, field.name(), dp) {
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | @Override
|
| | | protected void onSortChanged() {
|
| | | dataView.setCurrentPage(0);
|
| | | }
|
| | | };
|
| | | }
|
| | |
|
| | | private class DataProvider extends SortableDataProvider<RepositoryModel> {
|
| | | private static final long serialVersionUID = 1L;
|
| | | private List<RepositoryModel> list = null;
|
| | |
|
| | | protected DataProvider(List<RepositoryModel> list) {
|
| | | this.list = list;
|
| | | setSort(SortBy.date.name(), false);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public int size() {
|
| | | if (list == null)
|
| | | return 0;
|
| | | return list.size();
|
| | | }
|
| | |
|
| | | @Override
|
| | | public IModel<RepositoryModel> model(RepositoryModel header) {
|
| | | return new Model<RepositoryModel>(header);
|
| | | }
|
| | |
|
| | | @Override
|
| | | public Iterator<RepositoryModel> iterator(int first, int count) {
|
| | | SortParam sp = getSort();
|
| | | String prop = sp.getProperty();
|
| | | final boolean asc = sp.isAscending();
|
| | |
|
| | | if (prop == null || prop.equals(SortBy.date.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.lastChange.compareTo(o2.lastChange);
|
| | | return o2.lastChange.compareTo(o1.lastChange);
|
| | | }
|
| | | });
|
| | | } else if (prop.equals(SortBy.repository.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.name.compareTo(o2.name);
|
| | | return o2.name.compareTo(o1.name);
|
| | | }
|
| | | });
|
| | | } else if (prop.equals(SortBy.owner.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.owner.compareTo(o2.owner);
|
| | | return o2.owner.compareTo(o1.owner);
|
| | | }
|
| | | });
|
| | | } else if (prop.equals(SortBy.description.name())) {
|
| | | Collections.sort(list, new Comparator<RepositoryModel>() {
|
| | | @Override
|
| | | public int compare(RepositoryModel o1, RepositoryModel o2) {
|
| | | if (asc)
|
| | | return o1.description.compareTo(o2.description);
|
| | | return o2.description.compareTo(o1.description);
|
| | | }
|
| | | });
|
| | | }
|
| | | return list.subList(first, first + count).iterator();
|
| | | }
|
| | | }
|
| | | }
|
New file |
| | |
| | | <!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 wicket:id="adminPanel">[admin links]</div>
|
| | | |
| | | <table class="repositories">
|
| | | <tr>
|
| | | <th class="left">
|
| | | <wicket:link>
|
| | | <img style="vertical-align: top; border: 1px solid #888; background-color: white;" src="/com/gitblit/wicket/resources/user_16x16.png"/>
|
| | | </wicket:link>
|
| | | <wicket:message key="gb.username">[username]</wicket:message>
|
| | | </th>
|
| | | <th class="right"></th>
|
| | | </tr>
|
| | | <tbody> |
| | | <tr wicket:id="userRow">
|
| | | <td class="left" ><div class="list" wicket:id="username">[username]</div></td>
|
| | | <td class="rightAlign"><span wicket:id="userLinks"></span></td> |
| | | </tr>
|
| | | </tbody>
|
| | | </table>
|
| | | |
| | | <wicket:fragment wicket:id="adminLinks">
|
| | | <!-- page nav links --> |
| | | <div class="admin_nav">
|
| | | <wicket:link>
|
| | | <img style="vertical-align: top;" src="/com/gitblit/wicket/resources/add_16x16.png"/>
|
| | | </wicket:link> |
| | | <a wicket:id="newUser">
|
| | | <wicket:message key="gb.newUser"></wicket:message>
|
| | | </a>
|
| | | </div> |
| | | </wicket:fragment>
|
| | | |
| | | <wicket:fragment wicket:id="userAdminLinks">
|
| | | <span class="link"><a wicket:id="editUser"><wicket:message key="gb.edit">[edit]</wicket:message></a> | <a wicket:id="deleteUser"><wicket:message key="gb.delete">[delete]</wicket:message></a></span>
|
| | | </wicket:fragment>
|
| | | |
| | | </wicket:panel>
|
| | | </body>
|
| | | </html> |
New file |
| | |
| | | package com.gitblit.wicket.panels;
|
| | |
|
| | | 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 com.gitblit.GitBlit;
|
| | | import com.gitblit.wicket.LinkPanel;
|
| | | import com.gitblit.wicket.WicketUtils;
|
| | | import com.gitblit.wicket.pages.EditUserPage;
|
| | | import com.gitblit.wicket.pages.RepositoriesPage;
|
| | |
|
| | | public class UsersPanel extends BasePanel {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public UsersPanel(String wicketId, final boolean showAdmin) {
|
| | | super(wicketId);
|
| | |
|
| | | Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);
|
| | | adminLinks.add(new BookmarkablePageLink<Void>("newUser", EditUserPage.class));
|
| | | add(adminLinks.setVisible(showAdmin));
|
| | | |
| | | DataView<String> usersView = new DataView<String>("userRow", new ListDataProvider<String>(GitBlit.self().getAllUsernames())) {
|
| | | private static final long serialVersionUID = 1L;
|
| | | private int counter = 0;
|
| | |
|
| | | public void populateItem(final Item<String> item) {
|
| | | final String entry = item.getModelObject();
|
| | | LinkPanel editLink = new LinkPanel("username", "list", entry, EditUserPage.class, WicketUtils.newUsernameParameter(entry));
|
| | | WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry);
|
| | | item.add(editLink);
|
| | | Fragment userLinks = new Fragment("userLinks", "userAdminLinks", this);
|
| | | userLinks.add(new BookmarkablePageLink<Void>("editUser", EditUserPage.class, WicketUtils.newUsernameParameter(entry)));
|
| | | userLinks.add(new BookmarkablePageLink<Void>("deleteUser", RepositoriesPage.class, WicketUtils.newUsernameParameter(entry)).setEnabled(false));
|
| | | item.add(userLinks);
|
| | |
|
| | | WicketUtils.setAlternatingBackground(item, counter);
|
| | | counter++;
|
| | | }
|
| | | };
|
| | | add(usersView.setVisible(showAdmin));
|
| | | }
|
| | | }
|
| | |
| | | }
|
| | |
|
| | | div.admin_nav {
|
| | | border: 1px solid #888;
|
| | | border-bottom: 0px;
|
| | | background:#dae0d2;
|
| | | text-align: right;
|
| | | padding: 5px 5px 5px 2px;
|
| | | }
|
| | |
|
| | |
| | | border: 1px solid orange;
|
| | | }
|
| | |
|
| | | table.pretty, table.repositories, table.comments {
|
| | | table.pretty, table.comments {
|
| | | margin-bottom:5px;
|
| | | border-spacing: 0px;
|
| | | border-left: 1px solid #bbb;
|
| | |
| | | line-height: 17px;
|
| | | }
|
| | |
|
| | | table.repositories {
|
| | | margin-bottom:5px;
|
| | | border-spacing: 0px;
|
| | | }
|
| | |
|
| | | table.repositories th {
|
| | | background-color:#D2C3AF;
|
| | | padding: 4px;
|
| | |
| | | border-bottom: 1px solid #808080;
|
| | | }
|
| | |
|
| | | table.repositories th.left, table.repositories td.left {
|
| | | border-left: 1px solid #808080;
|
| | | padding-left: 5px;
|
| | | }
|
| | |
|
| | | table.repositories td.left {
|
| | | padding-left: 10px;
|
| | | }
|
| | |
|
| | | table.repositories th.right, table.repositories td.right {
|
| | | border-right: 1px solid #808080;
|
| | | }
|
| | |
|
| | | table.repositories td {
|
| | | padding: 2px;
|
| | | }
|
| | |
|
| | | table.repositories td.rightAlign { |
| | | text-align: right;
|
| | | border-right: 1px solid #808080;
|
| | | } |
| | |
|
| | | table.repositories td.icon img {
|
| | | vertical-align: top;
|
| | |
| | | font-weight: bold;
|
| | | }
|
| | |
|
| | | table.repositories tr.group {
|
| | | background-color: #E66C2C;
|
| | | }
|
| | |
|
| | | table.repositories tr.group td {
|
| | | font-weight: bold; |
| | | border-bottom: 1px solid orange;
|
| | | color: white;
|
| | | background-color: #E66C2C;
|
| | | border-left: 1px solid #808080;
|
| | | border-right: 1px solid #808080;
|
| | | padding-left: 5px;
|
| | | }
|
| | |
|
| | | table.palette { border:0;}
|
| | | table.palette td.header {
|
| | | font-weight: bold;
|
| | |
| | | tr th.wicket_orderDown a {background-image: url(arrow_down.png); }
|
| | | tr th.wicket_orderUp a { background-image: url(arrow_up.png); }
|
| | | tr th.wicket_orderNone a { background-image: url(arrow_off.png); }
|
| | |
|
| | | tr.group {
|
| | | background-color: #E66C2C;
|
| | | }
|
| | |
|
| | | tr.group td {
|
| | | font-weight: bold;
|
| | | border-bottom: 1px solid orange;
|
| | | color: white;
|
| | | background-color: #E66C2C; |
| | | }
|
| | |
|
| | | tr.light {
|
| | | background-color: #ffffff;
|