From 42972d830611fa4b1aa2c2c49c824a15e1987597 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Tue, 03 Jun 2014 10:38:55 -0400
Subject: [PATCH] Merged #76 "Simplify repository creation with a new page"

---
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html      |    2 
 src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html           |   41 +
 .gitmodules                                                             |    3 
 src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java   |    3 
 src/main/java/com/gitblit/Constants.java                                |    8 
 src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.java    |   78 ++
 src/main/java/com/gitblit/wicket/panels/TextOption.html                 |   20 
 src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java          |    5 
 src/main/java/com/gitblit/wicket/GitBlitWebApp.java                     |   10 
 src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java           |  373 +++++++++++
 src/main/java/com/gitblit/wicket/panels/ChoiceOption.java               |   52 +
 src/main/distrib/data/gitblit.properties                                |    5 
 src/main/java/com/gitblit/wicket/pages/RootPage.java                    |    2 
 src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html    |   19 
 src/main/java/com/gitblit/wicket/panels/ChoiceOption.html               |   19 
 src/main/java/com/gitblit/wicket/panels/CheckboxOption.java             |   54 +
 src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java          |  192 ++++++
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html      |    2 
 src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html        |   30 
 src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html          |  219 ++++--
 src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java        |  176 +++++
 src/main/java/com/gitblit/wicket/panels/CheckboxOption.html             |   17 
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html      |    2 
 src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html          |   28 
 src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java          |  404 ++++++------
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html   |    2 
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html         |    2 
 src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html |    2 
 src/main/java/com/gitblit/servlet/GitblitContext.java                   |   16 
 src/main/java/com/gitblit/wicket/pages/UserPage.java                    |    4 
 src/main/distrib/data/gitignore                                         |    1 
 src/main/java/com/gitblit/wicket/GitBlitWebApp.properties               |   45 +
 README.markdown                                                         |   13 
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pt_BR.html   |    2 
 releases.moxie                                                          |    3 
 build.xml                                                               |    6 
 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html      |    2 
 src/main/java/com/gitblit/wicket/panels/TextOption.java                 |   53 +
 38 files changed, 1,625 insertions(+), 290 deletions(-)

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..01eaa2c
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "src/main/distrib/data/gitignore"]
+	path = src/main/distrib/data/gitignore
+	url = https://github.com/github/gitignore.git
diff --git a/README.markdown b/README.markdown
index 348afae..76c15fc 100644
--- a/README.markdown
+++ b/README.markdown
@@ -4,13 +4,18 @@
 Gitblit is an open source, pure Java Git solution for managing, viewing, and serving [Git](http://git-scm.com) repositories.
 More information about Gitblit can be found [here](http://gitblit.com).
 
-[ ![Download](https://api.bintray.com/packages/gitblit/releases/stable/images/download.png) ](https://bintray.com/gitblit/releases/stable/_latestVersion)
+<a href='https://bintray.com/gitblit/releases/gitblit/_latestVersion'><img src='https://api.bintray.com/packages/gitblit/releases/gitblit/images/download.png'></a>
 
 License
 -------
 
 Gitblit is distributed under the terms of the [Apache Software Foundation license, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
 The text of the license is included in the file LICENSE in the root of the project.
+
+Contributing
+------------
+
+GitHub pull requests are preferred.  Any contributions must be distributed under the terms of the [Apache Software Foundation license, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
 
 Java Runtime Requirement
 ------------------------------------
@@ -25,6 +30,10 @@
 
 Building Gitblit
 ----------------
+
+Gitblit uses submodules.
+Make sure to clone using `--recursive` OR to execute `git submodule update --init --recursive`.
+
 [Eclipse](http://eclipse.org) is recommended for development as the project settings are preconfigured.
 
 1. Import the gitblit project into your Eclipse workspace.
@@ -39,4 +48,4 @@
 Building Tips & Tricks
 ----------------------
 1. If you are running Ant from an ANSI-capable console, consider setting the `MX_COLOR` environment variable before executing Ant.<pre>set MX_COLOR=true</pre>
-2. The build script will honor your Maven proxy settings.  If you need to fine-tune this, please review the [settings.moxie](http://gitblit.github.io/moxie/settings.html) documentation.
\ No newline at end of file
+2. The build script will honor your Maven proxy settings.  If you need to fine-tune this, please review the [settings.moxie](http://gitblit.github.io/moxie/settings.html) documentation.
diff --git a/build.xml b/build.xml
index f45c4ca..be6f1dd 100644
--- a/build.xml
+++ b/build.xml
@@ -919,6 +919,12 @@
 					<include name="subgit.groovy" />
 				</fileset>
 			</copy>
+			<mkdir dir="@{toDir}/gitignore" />
+			<copy todir="@{toDir}/gitignore">
+				<fileset dir="${project.distrib.dir}/data/gitignore">					
+					<include name="*.gitignore" />
+				</fileset>
+			</copy>
       </sequential>
 	</macrodef>
 	
diff --git a/releases.moxie b/releases.moxie
index 4332238..7635e06 100644
--- a/releases.moxie
+++ b/releases.moxie
@@ -27,6 +27,7 @@
     - Move repository deletion functions to the edit repository page AND allow deletion to be disabled (pr-180, ticket-67)
     - Update the Korean translation (pr-184, ticket-69)
     - Overhaul the EmptyRepositoryPage (ticket-73)
+    - Overhauled the edit repository page (ticket-76)
     - Process bugtraq links in the ticket description and comments (ticket-78)
     additions:
     - Add My Tickets page (issue-215, ticket-15)
@@ -36,6 +37,7 @@
     - Add FORK_REPOSITORY RPC request type (issue-371, pr-161, ticket-65)
     - Add object type (ot) parameter for RSS queries to retrieve tag details (pr-165, ticket-66)
     - Add setting to allow STARTTLS without requiring SMTPS (pr-183)
+    - Simplified repository creation, offer simple README generation, and insertion of a pre-defined .gitignore file (ticket-76)
     - Added an extension point for monitoring onStartup and onShutdown (ticket-79)
     - Tag server-side merges when incremental push tags are enabled (issue-432, ticket-85)
     - Add setting to control default thread pool size for miscellaneous background tasks (ticket-92)
@@ -55,6 +57,7 @@
     - { name: 'web.allowDeletingNonEmptyRepositories', defaultValue: 'true' }
     - { name: 'mail.starttls', defaultValue: 'false' }
     - { name: 'execution.defaultThreadPoolSize', defaultValue: '1' }
+    - { name: 'git.gitignoreFolder', defaultValue: '${baseFolder}/gitignore' }
 }
 
 #
diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties
index 6f55a3e..d5623cd 100644
--- a/src/main/distrib/data/gitblit.properties
+++ b/src/main/distrib/data/gitblit.properties
@@ -271,6 +271,11 @@
 # SINCE 1.4.0
 git.createRepositoriesShared = false
 
+# Directory for gitignore templates used during repository creation.
+#
+# SINCE 1.6.0
+git.gitignoreFolder = ${baseFolder}/gitignore
+
 # Enable JGit-based garbage collection. (!!EXPERIMENTAL!!)
 #
 # USE AT YOUR OWN RISK!
diff --git a/src/main/distrib/data/gitignore b/src/main/distrib/data/gitignore
new file mode 160000
index 0000000..097db81
--- /dev/null
+++ b/src/main/distrib/data/gitignore
@@ -0,0 +1 @@
+Subproject commit 097db81c08b138dea7cb031eb18eeb16afe44bdf
diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java
index 95eb944..3e30753 100644
--- a/src/main/java/com/gitblit/Constants.java
+++ b/src/main/java/com/gitblit/Constants.java
@@ -122,6 +122,14 @@
 
 	public static final String R_TICKETS_PATCHSETS = "refs/tickets/";
 
+	public static final String R_MASTER = "refs/heads/master";
+
+	public static final String MASTER = "master";
+
+	public static final String R_DEVELOP = "refs/heads/develop";
+
+	public static final String DEVELOP = "develop";
+
 	public static String getVersion() {
 		String v = Constants.class.getPackage().getImplementationVersion();
 		if (v == null) {
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index 110e553..50f22d5 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -372,6 +372,22 @@
 			}
 		}
 
+		// Copy the included gitignore files to the configured gitignore folder
+		String gitignorePath = webxmlSettings.getString(Keys.git.gitignoreFolder, "gitignore");
+		File localGitignores = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, base, gitignorePath);
+		if (!localGitignores.exists()) {
+			File warGitignores = new File(contextFolder, "/WEB-INF/data/gitignore");
+			if (!warGitignores.equals(localGitignores)) {
+				try {
+					com.gitblit.utils.FileUtils.copy(localGitignores, warGitignores.listFiles());
+				} catch (IOException e) {
+					logger.error(MessageFormat.format(
+							"Failed to copy included .gitignore files from {0} to {1}",
+							warGitignores, localGitignores));
+				}
+			}
+		}
+
 		// merge the WebXmlSettings into the runtime settings (for backwards-compatibilty)
 		runtimeSettings.merge(webxmlSettings);
 
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index 7291d03..f63ff3d 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -57,6 +57,7 @@
 import com.gitblit.wicket.pages.DocPage;
 import com.gitblit.wicket.pages.DocsPage;
 import com.gitblit.wicket.pages.EditMilestonePage;
+import com.gitblit.wicket.pages.EditRepositoryPage;
 import com.gitblit.wicket.pages.EditTicketPage;
 import com.gitblit.wicket.pages.ExportTicketPage;
 import com.gitblit.wicket.pages.FederationRegistrationPage;
@@ -71,6 +72,7 @@
 import com.gitblit.wicket.pages.MyDashboardPage;
 import com.gitblit.wicket.pages.MyTicketsPage;
 import com.gitblit.wicket.pages.NewMilestonePage;
+import com.gitblit.wicket.pages.NewRepositoryPage;
 import com.gitblit.wicket.pages.NewTicketPage;
 import com.gitblit.wicket.pages.OverviewPage;
 import com.gitblit.wicket.pages.PatchPage;
@@ -91,6 +93,8 @@
 public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
 
 	private final Class<? extends WebPage> homePageClass = MyDashboardPage.class;
+
+	private final Class<? extends WebPage> newRepositoryPageClass = NewRepositoryPage.class;
 
 	private final Map<String, CacheControl> cacheablePages = new HashMap<String, CacheControl>();
 
@@ -207,6 +211,8 @@
 		mount("/proposal", ReviewProposalPage.class, "t");
 		mount("/registration", FederationRegistrationPage.class, "u", "n");
 
+		mount("/new", NewRepositoryPage.class);
+		mount("/edit", EditRepositoryPage.class, "r");
 		mount("/activity", ActivityPage.class, "r", "h");
 		mount("/lucene", LuceneSearchPage.class);
 		mount("/project", ProjectPage.class, "p");
@@ -262,6 +268,10 @@
 		return homePageClass;
 	}
 
+	public Class<? extends WebPage> getNewRepositoryPage() {
+		return newRepositoryPageClass;
+	}
+
 	/* (non-Javadoc)
 	 * @see com.gitblit.wicket.Webapp#isCacheablePage(java.lang.String)
 	 */
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
index 12430ad..d6fd57e 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
@@ -133,7 +133,7 @@
 gb.status = status
 gb.origin = origin
 gb.headRef = default branch (HEAD)
-gb.headRefDescription = change the ref that HEAD links to. e.g. refs/heads/master
+gb.headRefDescription = The default branch that will be cloned and displayed on the Summary page.
 gb.federationStrategy = federation strategy
 gb.federationRegistration = federation registration
 gb.federationResults = federation pull results
@@ -223,8 +223,8 @@
 gb.noHits = no hits
 gb.authored = authored
 gb.committed = committed
-gb.indexedBranches = indexed branches
-gb.indexedBranchesDescription = select the branches to include in your Lucene index
+gb.indexedBranches = Indexed Branches
+gb.indexedBranchesDescription = Select the branches to be indexed by Lucene
 gb.noIndexedRepositoriesWarning = none of your repositories are configured for Lucene indexing
 gb.undefinedQueryWarning = query is undefined!
 gb.noSelectedRepositoriesWarning = please select one or more repositories!
@@ -685,4 +685,41 @@
 gb.administration = administration
 gb.plugins = plugins
 gb.extensions = extensions
-
+gb.pleaseSelectProject = Please select the project!
+gb.accessPolicy = Access Policy
+gb.accessPolicyDescription = Choose an access policy to control repository visibility and git permissions.
+gb.anonymousPolicy = Anonymous View, Clone, & Push
+gb.anonymousPolicyDescription = Anyone can see, clone, and push to this repository.
+gb.authenticatedPushPolicy = Restrict Push (Authenticated)
+gb.authenticatedPushPolicyDescription = Anyone can see and clone this repository. All authenticated users have RW+ push permission.
+gb.namedPushPolicy = Restrict Push (Named)
+gb.namedPushPolicyDescription = Anyone can see and clone this repository. You choose who can push.
+gb.clonePolicy = Restrict Clone & Push
+gb.clonePolicyDescription = Anyone can see this repository. You choose who can clone and push.
+gb.viewPolicy  = Restrict View, Clone, & Push
+gb.viewPolicyDescription = You choose who can see, clone, and push to this repository.
+gb.initialCommit = Initial Commit
+gb.initialCommitDescription = This will allow you to <code>git clone</code> this repository immediately. Skip this step if you have already run <code>git init</code> locally.
+gb.initWithReadme = Include a README
+gb.initWithReadmeDescription = This will generate a simple README document for your repository.
+gb.initWithGitignore = Include a .gitignore file
+gb.initWithGitignoreDescription = This will insert a config file that instructs your Git clients to ignore files or directories that match defined patterns.
+gb.pleaseSelectGitIgnore = Please select a .gitignore file
+gb.receive = receive
+gb.permissions = permissions
+gb.ownersDescription = Owners can manage all repository settings but they are not allowed to rename a repository unless it is their personal repository.
+gb.userPermissionsDescription = You can specify individual user permissions. These settings will override team or regex permissions.
+gb.teamPermissionsDescription = You can specify individual team permissions. These settings will override regex permissions.
+gb.ticketSettings = Ticket Settings
+gb.receiveSettings = Receive Settings
+gb.receiveSettingsDescription = The receive settings control pushes to the repository.
+gb.preReceiveDescription = Pre-receive hooks are executed after commits are received but <em>BEFORE</em> the refs are updated.<p>This is the appropriate hook for rejecting a push.</p>
+gb.postReceiveDescription = Post-receive hooks are executed after commits are received but <em>AFTER</em> the refs are updated.<p>This is the appropriate hook for notifications, build triggers, etc.</p>
+gb.federationStrategyDescription = Control if and how to federate this repository with another Gitblit.
+gb.federationSetsDescription = This repository will be included in the selected federation sets.
+gb.miscellaneous = miscellaneous
+gb.originDescription = The url from which this repository was cloned.
+gb.gc = GC 
+gb.garbageCollection = Garbage Collection
+gb.garbageCollectionDescription = The garbage collector will pack loose objects pushed from clients and will remove unreferenced objects from the repository.
+gb.commitMessageRendererDescription = Commit messages can be displayed as plaintext or as rendered markup.
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
index b7a1976..1e683b4 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
@@ -9,14 +9,17 @@
 	<form style="padding-top:5px;" wicket:id="editForm">
 <div class="row">
 <div class="span12">
-<div class="tabbable">
+<div class="tabbable tabs-left">
 	<!-- tab titles -->
 	<ul class="nav nav-tabs">
 		<li class="active"><a href="#general" data-toggle="tab"><wicket:message key="gb.general"></wicket:message></a></li>
-		<li><a href="#permissions" data-toggle="tab"><wicket:message key="gb.accessPermissions"></wicket:message></a></li>
+		<li><a href="#permissions" data-toggle="tab"><wicket:message key="gb.permissions"></wicket:message></a></li>
+		<li><a href="#receive" data-toggle="tab"><wicket:message key="gb.receive"></wicket:message></a></li>
+		<li><a href="#tickets" data-toggle="tab"><wicket:message key="gb.tickets"></wicket:message></a></li>
 		<li><a href="#federation" data-toggle="tab"><wicket:message key="gb.federation"></wicket:message></a></li>
 		<li><a href="#search" data-toggle="tab"><wicket:message key="gb.search"></wicket:message></a></li>
-		<li><a href="#hooks" data-toggle="tab"><wicket:message key="gb.hookScripts"></wicket:message></a></li>
+		<li><a href="#gc" data-toggle="tab"><wicket:message key="gb.gc"></wicket:message></a></li>
+		<li><a href="#misc" data-toggle="tab"><wicket:message key="gb.miscellaneous"></wicket:message></a></li>
 	</ul>
 
 	<!-- tab content -->
@@ -24,99 +27,167 @@
 
 		<!-- general tab -->
 		<div class="tab-pane active" id="general">
-		<table class="plain">
-			<tbody class="settings">
-				<tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input class="span4" type="text" wicket:id="name" id="name" size="40" tabindex="1" /> &nbsp;<span class="help-inline"><wicket:message key="gb.nameDescription"></wicket:message></span></td></tr>
-				<tr><th><wicket:message key="gb.description"></wicket:message></th><td class="edit"><input class="span4" type="text" wicket:id="description" size="40" tabindex="2" /></td></tr>
-				<tr><th colspan="2"><hr/></th></tr>
-				<tr><th><wicket:message key="gb.origin"></wicket:message></th><td class="edit"><input class="span5" type="text" wicket:id="origin" size="80" tabindex="3" /></td></tr>
-				<tr><th><wicket:message key="gb.headRef"></wicket:message></th><td class="edit"><select class="span3" wicket:id="HEAD" tabindex="4" /> &nbsp;<span class="help-inline"><wicket:message key="gb.headRefDescription"></wicket:message></span></td></tr>
-				<tr><th><wicket:message key="gb.gcPeriod"></wicket:message></th><td class="edit"><select class="span2" wicket:id="gcPeriod" tabindex="5" /> &nbsp;<span class="help-inline"><wicket:message key="gb.gcPeriodDescription"></wicket:message></span></td></tr>
-				<tr><th><wicket:message key="gb.gcThreshold"></wicket:message></th><td class="edit"><input class="span1" type="text" wicket:id="gcThreshold" tabindex="6" /> &nbsp;<span class="help-inline"><wicket:message key="gb.gcThresholdDescription"></wicket:message></span></td></tr>
-				<tr><th colspan="2"><hr/></th></tr>
-				<tr><th><wicket:message key="gb.acceptNewTickets"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="acceptNewTickets" tabindex="7" /> &nbsp;<span class="help-inline"><wicket:message key="gb.acceptNewTicketsDescription"></wicket:message></span></label></td></tr>
-				<tr><th><wicket:message key="gb.acceptNewPatchsets"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="acceptNewPatchsets" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.acceptNewPatchsetsDescription"></wicket:message></span></label></td></tr>
-				<tr><th><wicket:message key="gb.requireApproval"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="requireApproval" tabindex="9" /> &nbsp;<span class="help-inline"><wicket:message key="gb.requireApprovalDescription"></wicket:message></span></label></td></tr>
-				<tr><th><wicket:message key="gb.mergeTo"></wicket:message></th><td class="edit"><select class="span2" wicket:id="mergeTo" tabindex="10" /> &nbsp;<span class="help-inline"><wicket:message key="gb.mergeToDescription"></wicket:message></span></td></tr>
-				<tr><th colspan="2"><hr/></th></tr>
-				<tr><th><wicket:message key="gb.enableIncrementalPushTags"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="useIncrementalPushTags" tabindex="11" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useIncrementalPushTagsDescription"></wicket:message></span></label></td></tr>
-				<tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="12" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></span></label></td></tr>
-				<tr><th><wicket:message key="gb.skipSizeCalculation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSizeCalculation" tabindex="13" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></label></td></tr>
-				<tr><th><wicket:message key="gb.skipSummaryMetrics"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSummaryMetrics" tabindex="14" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSummaryMetricsDescription"></wicket:message></span></label></td></tr>
-				<tr><th><wicket:message key="gb.maxActivityCommits"></wicket:message></th><td class="edit"><select class="span2" wicket:id="maxActivityCommits" tabindex="15" /> &nbsp;<span class="help-inline"><wicket:message key="gb.maxActivityCommitsDescription"></wicket:message></span></td></tr>
-				<tr><th><wicket:message key="gb.metricAuthorExclusions"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="metricAuthorExclusions" size="40" tabindex="16" /></td></tr>
-				<tr><th><wicket:message key="gb.commitMessageRenderer"></wicket:message></th><td class="edit"><select class="span2" wicket:id="commitMessageRenderer" tabindex="17" /></td></tr>
-				<tr><th colspan="2"><hr/></th></tr>
-				<tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="18" /></td></tr>
-			</tbody>
-		</table>
+
+			<div wicket:id="namePanel"></div>
+		
+			<hr/>
+		
+			<div wicket:id="accessPolicyPanel"></div>
+		
 		</div>
 
 		<!-- access permissions -->
 		<div class="tab-pane" id="permissions">
-			<table class="plain">
-				<tbody class="settings">
-					<tr><th><wicket:message key="gb.owners"></wicket:message></th><td class="edit"><span wicket:id="owners" tabindex="19" /> </td></tr>
-					<tr><th colspan="2"><hr/></th></tr>
-					<tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="20" /></td></tr>
-					<tr><th colspan="2"><hr/></th></tr>
-					<tr><th><wicket:message key="gb.authorizationControl"></wicket:message></th><td style="padding:2px;"><span class="authorizationControl" wicket:id="authorizationControl"></span></td></tr>
-					<tr><th colspan="2"><hr/></th></tr>
-					<tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="isFrozen" tabindex="21" /> &nbsp;<span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></label></td></tr>
-					<tr><th><wicket:message key="gb.allowForks"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="allowForks" tabindex="22" /> &nbsp;<span class="help-inline"><wicket:message key="gb.allowForksDescription"></wicket:message></span></label></td></tr>
-					<tr><th><wicket:message key="gb.verifyCommitter"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="verifyCommitter" tabindex="23" /> &nbsp;<span class="help-inline"><wicket:message key="gb.verifyCommitterDescription"></wicket:message></span><br/><span class="help-inline" style="padding-left:10px;"><wicket:message key="gb.verifyCommitterNote"></wicket:message></span></label></td></tr>
-					<tr><th colspan="2"><hr/></th></tr>
-					<tr><th><wicket:message key="gb.userPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>
-					<tr><th colspan="2"><hr/></th></tr>
-					<tr><th><wicket:message key="gb.teamPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="teams"></span></td></tr>
-				</tbody>
-			</table>
+		
+			<h4><wicket:message key="gb.owners"></wicket:message></h4>
+			<p><wicket:message key="gb.ownersDescription"></wicket:message></p>
+			<div wicket:id="owners"></div>
+			
+			<hr />
+
+			<h4><wicket:message key="gb.userPermissions"></wicket:message></h4>
+			<p><wicket:message key="gb.userPermissionsDescription"></wicket:message></p>
+			<div wicket:id="users"></div>
+			
+			<hr />
+
+			<h4><wicket:message key="gb.teamPermissions"></wicket:message></h4>
+			<p><wicket:message key="gb.teamPermissionsDescription"></wicket:message></p>
+			<div wicket:id="teams"></div>
+			
 		</div>
 
-		<!-- federation -->
-		<div class="tab-pane" id="federation">
+		<!-- receive -->
+		<div class="tab-pane" id="receive">
+			<h4><wicket:message key="gb.receiveSettings"></wicket:message></h4>
+			<p><wicket:message key="gb.receiveSettingsDescription"></wicket:message></p>
+					
+			<hr/>
+			
+			<div wicket:id="isFrozen"></div>
+			<div wicket:id="verifyCommitter"></div>
+			<div wicket:id="incrementalPushTags"></div>
+			
+			<hr />
+			
+			<h4><wicket:message key="gb.preReceiveScripts"></wicket:message></h4>
+			<p><wicket:message key="gb.preReceiveDescription"></wicket:message></p>
+			
 			<table class="plain">
 				<tbody class="settings">
-					<tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="24" /></td></tr>
-					<tr><th><wicket:message key="gb.federationSets"></wicket:message></th><td style="padding:2px;"><span wicket:id="federationSets"></span></td></tr>
+					<tr>
+						<td style="padding:2px;"><span wicket:id="preReceiveScripts"></span></td>
+						<td style="vertical-align: top;"><span wicket:id="inheritedPreReceive"></span></td>
+					</tr>
 				</tbody>
 			</table>
+
+			<hr />
+			
+			<h4><wicket:message key="gb.postReceiveScripts"></wicket:message></h4>
+			<p><wicket:message key="gb.postReceiveDescription"></wicket:message></p>
+			
+			<table class="plain">
+				<tbody class="settings">
+					<tr>
+						<td style="padding:2px;"><span wicket:id="postReceiveScripts"></span></td>
+						<td style="vertical-align: top;"><span wicket:id="inheritedPostReceive"></span></td>
+					</tr>
+				</tbody>
+			</table>
+
+			<div wicket:id="customFieldsSection">
+				<hr />
+				
+				<h4><wicket:message key="gb.customFields"></wicket:message></h4>
+				<p><wicket:message key="gb.customFieldsDescription"></wicket:message></p>
+				<table class="plain">
+					<tbody class="settings">
+						<tr wicket:id="customFieldsListView"><th><span wicket:id="customFieldLabel"></span></th><td class="edit"><input class="span8" type="text" wicket:id="customFieldValue" /></td></tr>
+					</tbody>
+				</table>
+			</div>
+			
+		</div>
+
+		<!-- tickets tab -->		
+		<div class="tab-pane" id="tickets">
+
+			<h4><wicket:message key="gb.ticketSettings"></wicket:message></h4>
+			<p><wicket:message key="gb.ticketsWelcome"></wicket:message></p>
+				
+			<hr/>
+		
+			<div wicket:id="acceptNewPatchsets"></div>
+			<div wicket:id="acceptNewTickets"></div>
+			<div wicket:id="requireApproval"></div>
+			<div wicket:id="mergeTo"></div>
+		
+		</div>
+				
+		<!-- federation -->
+		<div class="tab-pane" id="federation">
+			<h4><wicket:message key="gb.federation"></wicket:message></h4>
+			<p><wicket:message key="gb.federationRepositoryDescription"></wicket:message></p>
+					
+			<hr/>
+			
+			<div wicket:id="federationStrategy"></div>
+
+			<hr />
+			
+			<h4><wicket:message key="gb.federationSets"></wicket:message></h4>
+			<p><wicket:message key="gb.federationSetsDescription"></wicket:message></p>
+
+			<div wicket:id="federationSets"></div>
 		</div>
 
 		<!-- search -->
 		<div class="tab-pane" id="search">
-			<table class="plain">
-				<tbody class="settings">
-					<tr><th><wicket:message key="gb.indexedBranches"></wicket:message></th><td style="padding:2px;"><span wicket:id="indexedBranches"></span></td></tr>
-				</tbody>
-			</table>
+		
+			<h4><wicket:message key="gb.indexedBranches"></wicket:message></h4>
+			<p><wicket:message key="gb.indexedBranchesDescription"></wicket:message></p>
+		
+			<div wicket:id="indexedBranches"></div>
 		</div>
 
-		<!-- hooks -->
-		<div class="tab-pane" id="hooks">
-			<table class="plain">
-				<tbody class="settings">
-					<tr><th><wicket:message key="gb.preReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPreReceive"></span></th><td style="padding:2px;"><span wicket:id="preReceiveScripts"></span></td></tr>
-					<tr><th><wicket:message key="gb.postReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPostReceive"></span></th><td style="padding:2px;"><span wicket:id="postReceiveScripts"></span></td></tr>
-					<div wicket:id="customFieldsSection">
-						<tr><td colspan="2"><h3><wicket:message key="gb.customFields"></wicket:message> &nbsp;<small><wicket:message key="gb.customFieldsDescription"></wicket:message></small></h3></td></tr>
-						<tr wicket:id="customFieldsListView"><th><span wicket:id="customFieldLabel"></span></th><td class="edit"><input class="span8" type="text" wicket:id="customFieldValue" /></td></tr>
-					</div>
-				</tbody>
-			</table>
+		<!-- garbage collection -->
+		<div class="tab-pane" id="gc">
+
+			<h4><wicket:message key="gb.garbageCollection"></wicket:message></h4>
+			<p><wicket:message key="gb.garbageCollectionDescription"></wicket:message></p>
+		
+			<div wicket:id="gcPeriod"></div>
+			<div wicket:id="gcThreshold"></div>
+		</div>
+		
+		<!-- misc -->
+		<div class="tab-pane" id="misc">
+
+			<div wicket:id="origin"></div>
+			<div wicket:id="head"></div>
+
+			<hr/>
+			
+			<div wicket:id="showRemoteBranches"></div>
+			<div wicket:id="skipSizeCalculation"></div>
+			<div wicket:id="skipSummaryMetrics"></div>
+			<div wicket:id="maxActivityCommits"></div>
+			<div wicket:id="commitMessageRenderer"></div>
+			<div wicket:id="metricAuthorExclusions"></div>
+			<div wicket:id="mailingLists"></div>
+		
+		</div>
+		
+		<div class="form-actions"><input class="btn btn-appmenu" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" /> &nbsp; <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" /> &nbsp; <input class="btn btn-danger" type="submit" value="Delete" wicket:message="value:gb.delete" wicket:id="delete" /></div>
+		
 		</div>
 	</div>
-</div>
-</div>
-</div>
-
-<div class="row">
-<div class="span12">
-	<div class="form-actions"><input class="btn btn-appmenu" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" /> &nbsp; <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" /> &nbsp; <input class="btn btn-danger" type="submit" value="Delete" wicket:message="value:gb.delete" wicket:id="delete" /></div>
 </div>
 </div>
 
 </form>	
 </body>
+
 </wicket:extend>
 </html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
index 412c0ec..f891595 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -29,7 +29,6 @@
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
-import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
 import org.apache.wicket.behavior.SimpleAttributeModifier;
 import org.apache.wicket.extensions.markup.html.form.palette.Palette;
 import org.apache.wicket.markup.html.WebMarkupContainer;
@@ -40,7 +39,6 @@
 import org.apache.wicket.markup.html.form.DropDownChoice;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.IChoiceRenderer;
-import org.apache.wicket.markup.html.form.RadioChoice;
 import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.markup.html.list.ListItem;
@@ -48,6 +46,7 @@
 import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
 import org.apache.wicket.model.util.CollectionModel;
 import org.apache.wicket.model.util.ListModel;
 import org.eclipse.jgit.lib.Repository;
@@ -69,13 +68,22 @@
 import com.gitblit.wicket.GitBlitWebSession;
 import com.gitblit.wicket.StringChoiceRenderer;
 import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.AccessPolicyPanel;
 import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation;
 import com.gitblit.wicket.panels.BulletListPanel;
+import com.gitblit.wicket.panels.CheckboxOption;
+import com.gitblit.wicket.panels.ChoiceOption;
 import com.gitblit.wicket.panels.RegistrantPermissionsPanel;
+import com.gitblit.wicket.panels.RepositoryNamePanel;
+import com.gitblit.wicket.panels.TextOption;
 
 public class EditRepositoryPage extends RootSubPage {
 
 	private final boolean isCreate;
+
+	RepositoryNamePanel namePanel;
+
+	AccessPolicyPanel accessPolicyPanel;
 
 	private boolean isAdmin;
 
@@ -196,7 +204,7 @@
 			}
 		}
 		final Palette<UserChoice> ownersPalette = new Palette<UserChoice>("owners", new ListModel<UserChoice>(owners), new CollectionModel<UserChoice>(
-		      persons), new ChoiceRenderer<UserChoice>(null, "userId"), 12, true);
+		      persons), new ChoiceRenderer<UserChoice>(null, "userId"), 12, false);
 
 		// indexed local branches palette
 		List<String> allLocalBranches = new ArrayList<String>();
@@ -263,59 +271,8 @@
 			@Override
 			protected void onSubmit() {
 				try {
-					// confirm a repository name was entered
-					if (repositoryModel.name == null && StringUtils.isEmpty(repositoryModel.name)) {
-						error(getString("gb.pleaseSetRepositoryName"));
+					if (!namePanel.updateModel(repositoryModel)) {
 						return;
-					}
-
-					// ensure name is trimmed
-					repositoryModel.name = repositoryModel.name.trim();
-
-					// automatically convert backslashes to forward slashes
-					repositoryModel.name = repositoryModel.name.replace('\\', '/');
-					// Automatically replace // with /
-					repositoryModel.name = repositoryModel.name.replace("//", "/");
-
-					// prohibit folder paths
-					if (repositoryModel.name.startsWith("/")) {
-						error(getString("gb.illegalLeadingSlash"));
-						return;
-					}
-					if (repositoryModel.name.startsWith("../")) {
-						error(getString("gb.illegalRelativeSlash"));
-						return;
-					}
-					if (repositoryModel.name.contains("/../")) {
-						error(getString("gb.illegalRelativeSlash"));
-						return;
-					}
-					if (repositoryModel.name.endsWith("/")) {
-						repositoryModel.name = repositoryModel.name.substring(0, repositoryModel.name.length() - 1);
-					}
-
-					// confirm valid characters in repository name
-					Character c = StringUtils.findInvalidCharacter(repositoryModel.name);
-					if (c != null) {
-						error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"),
-								c));
-						return;
-					}
-
-					if (user.canCreate() && !user.canAdmin() && allowEditName) {
-						// ensure repository name begins with the user's path
-						if (!repositoryModel.name.startsWith(user.getPersonalPath())) {
-							error(MessageFormat.format(getString("gb.illegalPersonalRepositoryLocation"),
-									user.getPersonalPath()));
-							return;
-						}
-
-						if (repositoryModel.name.equals(user.getPersonalPath())) {
-							// reset path prefix and show error
-							repositoryModel.name = user.getPersonalPath() + "/";
-							error(getString("gb.pleaseSetRepositoryName"));
-							return;
-						}
 					}
 
 					// confirm access restriction selection
@@ -426,33 +383,15 @@
 					}
 				} catch (GitBlitException e) {
 					error(e.getMessage());
+					namePanel.resetModel(repositoryModel);
 					return;
 				}
 				setRedirect(false);
-				if (isCreate) {
-					setResponsePage(RepositoriesPage.class);
-				} else {
-					setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name));
-				}
+				setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name));
 			}
 		};
 
-		// do not let the browser pre-populate these fields
-		form.add(new SimpleAttributeModifier("autocomplete", "off"));
-
-		// field names reflective match RepositoryModel fields
-		form.add(new TextField<String>("name").setEnabled(allowEditName));
-		form.add(new TextField<String>("description"));
-		form.add(ownersPalette);
-		form.add(new CheckBox("allowForks").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true)));
-		DropDownChoice<AccessRestrictionType> accessRestriction = new DropDownChoice<AccessRestrictionType>("accessRestriction",
-				AccessRestrictionType.choices(app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)), new AccessRestrictionRenderer());
-		form.add(accessRestriction);
-		form.add(new CheckBox("isFrozen"));
-		// TODO enable origin definition
-		form.add(new TextField<String>("origin").setEnabled(false/* isCreate */));
-
-		// allow relinking HEAD to a branch or tag other than master on edit repository
+		// Determine available refs & branches
 		List<String> availableRefs = new ArrayList<String>();
 		List<String> availableBranches = new ArrayList<String>();
 		if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) {
@@ -465,58 +404,79 @@
 				}
 			}
 		}
-		form.add(new DropDownChoice<String>("HEAD", availableRefs).setEnabled(availableRefs.size() > 0));
 
-		boolean gcEnabled = app().settings().getBoolean(Keys.git.enableGarbageCollection, false);
-		int defaultGcPeriod = app().settings().getInteger(Keys.git.defaultGarbageCollectionPeriod, 7);
-		if (repositoryModel.gcPeriod == 0) {
-			repositoryModel.gcPeriod = defaultGcPeriod;
-		}
-		List<Integer> gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 );
-		form.add(new DropDownChoice<Integer>("gcPeriod", gcPeriods, new GCPeriodRenderer()).setEnabled(gcEnabled));
-		form.add(new TextField<String>("gcThreshold").setEnabled(gcEnabled));
+		// do not let the browser pre-populate these fields
+		form.add(new SimpleAttributeModifier("autocomplete", "off"));
 
-		// federation strategies - remove ORIGIN choice if this repository has
-		// no origin.
-		List<FederationStrategy> federationStrategies = new ArrayList<FederationStrategy>(
-				Arrays.asList(FederationStrategy.values()));
-		if (StringUtils.isEmpty(repositoryModel.origin)) {
-			federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN);
-		}
-		form.add(new DropDownChoice<FederationStrategy>("federationStrategy", federationStrategies,
-				new FederationTypeRenderer()));
-		form.add(new CheckBox("acceptNewPatchsets"));
-		form.add(new CheckBox("acceptNewTickets"));
-		form.add(new CheckBox("requireApproval"));
-		form.add(new DropDownChoice<String>("mergeTo", availableBranches).setEnabled(availableBranches.size() > 0));
-		form.add(new CheckBox("useIncrementalPushTags"));
-		form.add(new CheckBox("showRemoteBranches"));
-		form.add(new CheckBox("skipSizeCalculation"));
-		form.add(new CheckBox("skipSummaryMetrics"));
-		List<Integer> maxActivityCommits  = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500);
-		form.add(new DropDownChoice<Integer>("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer()));
 
-		metricAuthorExclusions = new Model<String>(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? ""
-				: StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " "));
-		form.add(new TextField<String>("metricAuthorExclusions", metricAuthorExclusions));
+		//
+		//
+		// GENERAL
+		//
+		namePanel = new RepositoryNamePanel("namePanel", repositoryModel);
+		namePanel.setEditable(allowEditName);
+		form.add(namePanel);
 
-		mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
-				: StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
-		form.add(new TextField<String>("mailingLists", mailingLists));
-		form.add(indexedBranchesPalette);
+		// XXX AccessPolicyPanel is defined later.
 
-		List<AuthorizationControl> acList = Arrays.asList(AuthorizationControl.values());
-		final RadioChoice<AuthorizationControl> authorizationControl = new RadioChoice<Constants.AuthorizationControl>(
-				"authorizationControl", acList, new AuthorizationControlRenderer());
-		form.add(authorizationControl);
+		form.add(new ChoiceOption<String>("head",
+				getString("gb.headRef"),
+				getString("gb.headRefDescription"),
+				new PropertyModel<String>(repositoryModel, "HEAD"),
+				availableRefs));
 
-		final CheckBox verifyCommitter = new CheckBox("verifyCommitter");
-		verifyCommitter.setOutputMarkupId(true);
-		form.add(verifyCommitter);
 
+		//
+		// PERMISSIONS
+		//
+		form.add(ownersPalette);
 		form.add(usersPalette);
 		form.add(teamsPalette);
-		form.add(federationSetsPalette);
+
+		//
+		// TICKETS
+		//
+		form.add(new CheckboxOption("acceptNewPatchsets",
+				getString("gb.acceptNewPatchsets"),
+				getString("gb.acceptNewPatchsetsDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "acceptNewPatchsets")));
+
+		form.add(new CheckboxOption("acceptNewTickets",
+				getString("gb.acceptNewTickets"),
+				getString("gb.acceptNewTicketsDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "acceptNewPatchsets")));
+
+		form.add(new CheckboxOption("requireApproval",
+				getString("gb.requireApproval"),
+				getString("gb.requireApprovalDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "requireApproval")));
+
+		form.add(new ChoiceOption<String>("mergeTo",
+				getString("gb.mergeTo"),
+				getString("gb.mergeToDescription"),
+				new PropertyModel<String>(repositoryModel, "mergeTo"),
+				availableBranches));
+
+		//
+		// RECEIVE
+		//
+		form.add(new CheckboxOption("isFrozen",
+				getString("gb.isFrozen"),
+				getString("gb.isFrozenDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "isFrozen")));
+
+		form.add(new CheckboxOption("incrementalPushTags",
+				getString("gb.enableIncrementalPushTags"),
+				getString("gb.useIncrementalPushTagsDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "useIncrementalPushTags")));
+
+		final CheckBox verifyCommitter = new CheckBox("checkbox", new PropertyModel<Boolean>(repositoryModel, "verifyCommitter"));
+		verifyCommitter.setOutputMarkupId(true);
+		form.add(new CheckboxOption("verifyCommitter",
+				getString("gb.verifyCommitter"),
+				getString("gb.verifyCommitterDescription") + "<br/>" + getString("gb.verifyCommitterNote"),
+				verifyCommitter).setIsHtmlDescription(true));
+
 		form.add(preReceivePalette);
 		form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), app().repositories()
 				.getPreReceiveScriptsInherited(repositoryModel)));
@@ -528,17 +488,125 @@
 		customFieldsSection.add(customFieldsListView);
 		form.add(customFieldsSection.setVisible(!app().settings().getString(Keys.groovy.customFields, "").isEmpty()));
 
+		//
+		// FEDERATION
+		//
+		List<FederationStrategy> federationStrategies = new ArrayList<FederationStrategy>(
+				Arrays.asList(FederationStrategy.values()));
+		// federation strategies - remove ORIGIN choice if this repository has no origin.
+		if (StringUtils.isEmpty(repositoryModel.origin)) {
+			federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN);
+		}
+
+		form.add(new ChoiceOption<FederationStrategy>("federationStrategy",
+				getString("gb.federationStrategy"),
+				getString("gb.federationStrategyDescription"),
+				new DropDownChoice<FederationStrategy>(
+						"choice",
+						new PropertyModel<FederationStrategy>(repositoryModel, "federationStrategy"),
+						federationStrategies,
+						new FederationTypeRenderer())));
+
+		form.add(federationSetsPalette);
+
+		//
+		// SEARCH
+		//
+		form.add(indexedBranchesPalette);
+
+		//
+		// GARBAGE COLLECTION
+		//
+		boolean gcEnabled = app().settings().getBoolean(Keys.git.enableGarbageCollection, false);
+		int defaultGcPeriod = app().settings().getInteger(Keys.git.defaultGarbageCollectionPeriod, 7);
+		if (repositoryModel.gcPeriod == 0) {
+			repositoryModel.gcPeriod = defaultGcPeriod;
+		}
+		List<Integer> gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 );
+		form.add(new ChoiceOption<Integer>("gcPeriod",
+				getString("gb.gcPeriod"),
+				getString("gb.gcPeriodDescription"),
+				new DropDownChoice<Integer>("choice",
+						new PropertyModel<Integer>(repositoryModel, "gcPeriod"),
+						gcPeriods,
+						new GCPeriodRenderer())).setEnabled(gcEnabled));
+
+		form.add(new TextOption("gcThreshold",
+				getString("gb.gcThreshold"),
+				getString("gb.gcThresholdDescription"),
+				"span1",
+				new PropertyModel<String>(repositoryModel, "gcThreshold")).setEnabled(gcEnabled));
+
+		//
+		// MISCELLANEOUS
+		//
+
+		form.add(new TextOption("origin",
+				getString("gb.origin"),
+				getString("gb.originDescription"),
+				"span6",
+				new PropertyModel<String>(repositoryModel, "origin")).setEnabled(false));
+
+		form.add(new CheckboxOption("showRemoteBranches",
+				getString("gb.showRemoteBranches"),
+				getString("gb.showRemoteBranchesDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "showRemoteBranches")));
+
+		form.add(new CheckboxOption("skipSizeCalculation",
+				getString("gb.skipSizeCalculation"),
+				getString("gb.skipSizeCalculationDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "skipSizeCalculation")));
+
+		form.add(new CheckboxOption("skipSummaryMetrics",
+				getString("gb.skipSummaryMetrics"),
+				getString("gb.skipSummaryMetricsDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "skipSummaryMetrics")));
+
+		List<Integer> maxActivityCommits  = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500);
+		form.add(new ChoiceOption<Integer>("maxActivityCommits",
+				getString("gb.maxActivityCommits"),
+				getString("gb.maxActivityCommitsDescription"),
+				new DropDownChoice<Integer>("choice",
+						new PropertyModel<Integer>(repositoryModel, "maxActivityCommits"),
+						maxActivityCommits,
+						new MaxActivityCommitsRenderer())));
+
+		List<CommitMessageRenderer> renderers = Arrays.asList(CommitMessageRenderer.values());
+		form.add(new ChoiceOption<CommitMessageRenderer>("commitMessageRenderer",
+				getString("gb.commitMessageRenderer"),
+				getString("gb.commitMessageRendererDescription"),
+				new DropDownChoice<CommitMessageRenderer>("choice",
+						new PropertyModel<CommitMessageRenderer>(repositoryModel, "commitMessageRenderer"),
+						renderers)));
+
+		metricAuthorExclusions = new Model<String>(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? ""
+				: StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " "));
+
+		form.add(new TextOption("metricAuthorExclusions",
+				getString("gb.metricAuthorExclusions"),
+				getString("gb.metricAuthorExclusions"),
+				"span6",
+				metricAuthorExclusions));
+
+		mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
+				: StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
+
+		form.add(new TextOption("mailingLists",
+				getString("gb.mailingLists"),
+				getString("gb.mailingLists"),
+				"span6",
+				mailingLists));
+
+
 		// initial enable/disable of permission controls
 		if (repositoryModel.accessRestriction.equals(AccessRestrictionType.NONE)) {
 			// anonymous everything, disable all controls
 			usersPalette.setEnabled(false);
 			teamsPalette.setEnabled(false);
-			authorizationControl.setEnabled(false);
 			verifyCommitter.setEnabled(false);
 		} else {
 			// authenticated something
 			// enable authorization controls
-			authorizationControl.setEnabled(true);
 			verifyCommitter.setEnabled(true);
 
 			boolean allowFineGrainedControls = repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED);
@@ -546,15 +614,18 @@
 			teamsPalette.setEnabled(allowFineGrainedControls);
 		}
 
-		accessRestriction.add(new AjaxFormComponentUpdatingBehavior("onchange") {
+		//
+		// ACCESS POLICY PANEL (GENERAL)
+		//
+		AjaxFormChoiceComponentUpdatingBehavior callback = new AjaxFormChoiceComponentUpdatingBehavior() {
 
 			private static final long serialVersionUID = 1L;
 
 			@Override
 			protected void onUpdate(AjaxRequestTarget target) {
-				// enable/disable permissions panel based on access restriction
+				accessPolicyPanel.updateModel(repositoryModel);
+
 				boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE);
-				authorizationControl.setEnabled(allowAuthorizationControl);
 				verifyCommitter.setEnabled(allowAuthorizationControl);
 
 				boolean allowFineGrainedControls = allowAuthorizationControl && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED);
@@ -565,41 +636,19 @@
 					repositoryModel.authorizationControl = AuthorizationControl.NAMED;
 				}
 
-				target.addComponent(authorizationControl);
 				target.addComponent(verifyCommitter);
 				target.addComponent(usersPalette);
 				target.addComponent(teamsPalette);
 			}
-		});
+		};
 
-		authorizationControl.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+		accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel, callback);
+		form.add(accessPolicyPanel);
 
-			private static final long serialVersionUID = 1L;
 
-			@Override
-			protected void onUpdate(AjaxRequestTarget target) {
-				// enable/disable permissions panel based on access restriction
-				boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE);
-				authorizationControl.setEnabled(allowAuthorizationControl);
-
-				boolean allowFineGrainedControls = allowAuthorizationControl && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED);
-				usersPalette.setEnabled(allowFineGrainedControls);
-				teamsPalette.setEnabled(allowFineGrainedControls);
-
-				if (allowFineGrainedControls) {
-					repositoryModel.authorizationControl = AuthorizationControl.NAMED;
-				}
-
-				target.addComponent(authorizationControl);
-				target.addComponent(usersPalette);
-				target.addComponent(teamsPalette);
-			}
-		});
-
-		List<CommitMessageRenderer> renderers = Arrays.asList(CommitMessageRenderer.values());
-		DropDownChoice<CommitMessageRenderer> messageRendererChoice = new DropDownChoice<CommitMessageRenderer>("commitMessageRenderer", renderers);
-		form.add(messageRendererChoice);
-
+		//
+		// FORM CONTROLS
+		//
 		form.add(new Button("save"));
 		Button cancel = new Button("cancel") {
 			private static final long serialVersionUID = 1L;
@@ -632,7 +681,15 @@
 				if (canDelete) {
 					if (app().repositories().deleteRepositoryModel(latestModel)) {
 						info(MessageFormat.format(getString("gb.repositoryDeleted"), latestModel));
-						setResponsePage(RepositoriesPage.class);
+						if (latestModel.isPersonalRepository()) {
+							// redirect to user's profile page
+							String prefix = app().settings().getString(Keys.git.userRepositoryPrefix, "~");
+							String username = latestModel.projectPath.substring(prefix.length());
+							setResponsePage(UserPage.class, WicketUtils.newUsernameParameter(username));
+						} else {
+							// redirect to server repositories page
+							setResponsePage(RepositoriesPage.class);
+						}
 					} else {
 						error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), latestModel));
 					}
@@ -697,26 +754,6 @@
 		}
 	}
 
-	private class AccessRestrictionRenderer implements IChoiceRenderer<AccessRestrictionType> {
-
-		private static final long serialVersionUID = 1L;
-
-		private final Map<AccessRestrictionType, String> map;
-
-		public AccessRestrictionRenderer() {
-			map = getAccessRestrictions();
-		}
-
-		@Override
-		public String getDisplayValue(AccessRestrictionType type) {
-			return map.get(type);
-		}
-
-		@Override
-		public String getIdValue(AccessRestrictionType type, int index) {
-			return Integer.toString(index);
-		}
-	}
 
 	private class FederationTypeRenderer implements IChoiceRenderer<FederationStrategy> {
 
@@ -735,27 +772,6 @@
 
 		@Override
 		public String getIdValue(FederationStrategy type, int index) {
-			return Integer.toString(index);
-		}
-	}
-
-	private class AuthorizationControlRenderer implements IChoiceRenderer<AuthorizationControl> {
-
-		private static final long serialVersionUID = 1L;
-
-		private final Map<AuthorizationControl, String> map;
-
-		public AuthorizationControlRenderer() {
-			map = getAuthorizationControls();
-		}
-
-		@Override
-		public String getDisplayValue(AuthorizationControl type) {
-			return map.get(type);
-		}
-
-		@Override
-		public String getIdValue(AuthorizationControl type, int index) {
 			return Integer.toString(index);
 		}
 	}
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html
index ebd513a..31226ff 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html
@@ -10,7 +10,7 @@
 <div class="markdown">
 <div class="row">
 <div class="span10 offset1">	
-	<h2><center>Empty Repository</center></h2>
+	<h3><center>Empty Repository</center></h3>
 	<div class="alert alert-info">
 		<span wicket:id="repository" style="font-weight: bold;">[repository]</span> is an empty repository and can not be viewed by Gitblit.
 		<p></p>		
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html
index 0f168bf..af75b4e 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html
@@ -12,7 +12,7 @@
 <div class="markdown">
 <div class="row">
 <div class="span10 offset1">	
-	<h2><center>Repositorio Vac&iacute;o</center></h2>
+	<h3><center>Repositorio Vac&iacute;o</center></h3>
 	<div class="alert alert-info">
 		<span wicket:id="repository" style="font-weight: bold;">[repository]</span> es un repositorio vac&iacute;o y no puede ser visto en Gitblit.
 		<p></p>		
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html
index bd1f4f5..7fbcee1 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html
@@ -10,7 +10,7 @@
 <div class="markdown">
 <div class="row">
 <div class="span10 offset1">	
-	<h2><center>비어있는 저장소</center></h2>
+	<h3><center>비어있는 저장소</center></h3>
 	<div class="alert alert-info">
 		<span wicket:id="repository" style="font-weight: bold;">[repository]</span> 저장소는 비어 있어서 Gitblit 에서 볼 수 없습니다.
 		<p></p>		
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html
index dd58ed4..84373d2 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html
@@ -10,7 +10,7 @@
 <div class="markdown">
 <div class="row">
 <div class="span10 offset1">	
-	<h2><center>Lege Repository</center></h2>
+	<h3><center>Lege Repository</center></h3>
 	<div class="alert alert-info">
 		<span wicket:id="repository" style="font-weight: bold;">[repository]</span> is een lege repository en kan niet bekeken worden door Gitblit.
 		<p></p>		
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html
index dd0f4a5..b50bdac 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html
@@ -12,7 +12,7 @@
 <div class="markdown">
 <div class="row">
 <div class="span10 offset1">	
-	<h2><center>Puste repozytorium</center></h2>
+	<h3><center>Puste repozytorium</center></h3>
 	<div class="alert alert-info">
 		<span wicket:id="repository" style="font-weight: bold;">[repository]</span> jest pustym repozytorium i nie mo&#380;e by&#263; zaprezentowane przez Gitblit.
 		<p></p>		
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pt_BR.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pt_BR.html
index 0182d87..fc20121 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pt_BR.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pt_BR.html
@@ -10,7 +10,7 @@
 <div class="markdown">
 <div class="row">
 <div class="span10 offset1">	
-	<h2><center>Repositório Vazio</center></h2>
+	<h3><center>Repositório Vazio</center></h3>
 	<div class="alert alert-info">
 		<span wicket:id="repository" style="font-weight: bold;">[repository]</span> é um repositório vazio e não pode ser visualizado pelo Gitblit.
 		<p></p>		
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html
index 151abc4..1acf4f8 100644
--- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html
+++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html
@@ -10,7 +10,7 @@
 <div class="markdown">
 <div class="row">
 <div class="span10 offset1">	
-	<h2><center>空版本库</center></h2>
+	<h3><center>空版本库</center></h3>
 	<div class="alert alert-info">
 		<span wicket:id="repository" style="font-weight: bold;">[repository]</span> 版本库目前为空。
 		Gitblit 无法查看。
diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html
new file mode 100644
index 0000000..115b8c1
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html
@@ -0,0 +1,41 @@
+<!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:extend>
+<body onload="document.getElementById('name').focus();">
+	<form style="padding-top:5px;" wicket:id="editForm">
+<div class="row">
+	<div class="span12">
+
+		<div wicket:id="namePanel"></div>
+		
+		<hr/>
+		
+		<div wicket:id="accessPolicyPanel"></div>
+		
+		<hr/>
+		
+		<h4><wicket:message key="gb.initialCommit"></wicket:message></h4>
+		<p><wicket:message key="gb.initialCommitDescription"></wicket:message></p>
+		
+		<div wicket:id="addReadme"></div>
+		
+		<div wicket:id="addGitIgnore"></div>
+		
+		<div wicket:id="addGitFlow"></div>
+	</div>
+</div>
+
+<div class="row">
+<div class="span12">
+	<div class="form-actions"><input class="btn btn-appmenu" type="submit" value="Create" wicket:message="value:gb.create" wicket:id="create" /></div>
+</div>
+</div>
+
+</form>	
+</body>
+</wicket:extend>
+</html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java
new file mode 100644
index 0000000..bc2c68c
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.pages;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.FileUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.AccessPolicyPanel;
+import com.gitblit.wicket.panels.CheckboxOption;
+import com.gitblit.wicket.panels.ConditionalChoiceOption;
+import com.gitblit.wicket.panels.RepositoryNamePanel;
+
+public class NewRepositoryPage extends RootSubPage {
+
+	private final RepositoryModel repositoryModel;
+	private IModel<Boolean> addReadmeModel;
+	private Model<String> gitignoreModel;
+	private IModel<Boolean> addGitflowModel;
+	private IModel<Boolean> addGitignoreModel;
+	private AccessPolicyPanel accessPolicyPanel;
+	private RepositoryNamePanel namePanel;
+
+	public NewRepositoryPage() {
+		// create constructor
+		super();
+		repositoryModel = new RepositoryModel();
+
+		setupPage(getString("gb.newRepository"), "");
+
+		setStatelessHint(false);
+		setOutputMarkupId(true);
+	}
+
+	@Override
+	protected boolean requiresPageMap() {
+		return true;
+	}
+
+	@Override
+	protected Class<? extends BasePage> getRootNavPageClass() {
+		return RepositoriesPage.class;
+	}
+
+	@Override
+	protected void onInitialize() {
+		super.onInitialize();
+
+		CompoundPropertyModel<RepositoryModel> rModel = new CompoundPropertyModel<>(repositoryModel);
+		Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", rModel) {
+
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			protected void onSubmit() {
+				try {
+					if (!namePanel.updateModel(repositoryModel)) {
+						return;
+					}
+					accessPolicyPanel.updateModel(repositoryModel);
+
+					repositoryModel.owners = new ArrayList<String>();
+					repositoryModel.owners.add(GitBlitWebSession.get().getUsername());
+
+					// setup branch defaults
+					boolean useGitFlow = addGitflowModel.getObject();
+
+					repositoryModel.HEAD = Constants.R_MASTER;
+					repositoryModel.mergeTo = Constants.MASTER;
+					if (useGitFlow) {
+						// tickets normally merge to develop unless they are hotfixes
+						repositoryModel.mergeTo = Constants.DEVELOP;
+					}
+
+					repositoryModel.allowForks = app().settings().getBoolean(Keys.web.allowForking, true);
+
+					// optionally generate an initial commit
+					boolean addReadme = addReadmeModel.getObject();
+					String gitignore = null;
+					boolean addGitignore = addGitignoreModel.getObject();
+					if (addGitignore) {
+						gitignore = gitignoreModel.getObject();
+						if (StringUtils.isEmpty(gitignore)) {
+							throw new GitBlitException(getString("gb.pleaseSelectGitIgnore"));
+						}
+					}
+
+					// init the repository
+					app().gitblit().updateRepositoryModel(repositoryModel.name, repositoryModel, true);
+
+					// optionally create an initial commit
+					initialCommit(repositoryModel, addReadme, gitignore, useGitFlow);
+
+				} catch (GitBlitException e) {
+					error(e.getMessage());
+					namePanel.resetModel(repositoryModel);
+					return;
+				}
+				setRedirect(true);
+				setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name));
+			}
+		};
+
+		// do not let the browser pre-populate these fields
+		form.add(new SimpleAttributeModifier("autocomplete", "off"));
+
+		namePanel = new RepositoryNamePanel("namePanel", repositoryModel);
+		form.add(namePanel);
+
+		// prepare the default access controls
+		AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName(
+				app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name()));
+		if (AccessRestrictionType.NONE == defaultRestriction) {
+			defaultRestriction = AccessRestrictionType.PUSH;
+		}
+		AuthorizationControl defaultControl = AuthorizationControl.fromName(
+				app().settings().getString(Keys.git.defaultAuthorizationControl, AuthorizationControl.NAMED.name()));
+
+		if (AuthorizationControl.AUTHENTICATED == defaultControl) {
+			defaultRestriction = AccessRestrictionType.PUSH;
+		}
+
+		repositoryModel.authorizationControl = defaultControl;
+		repositoryModel.accessRestriction = defaultRestriction;
+
+		accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel);
+		form.add(accessPolicyPanel);
+
+		//
+		// initial commit options
+		//
+
+		// add README
+		addReadmeModel = Model.of(false);
+		form.add(new CheckboxOption("addReadme",
+				getString("gb.initWithReadme"),
+				getString("gb.initWithReadmeDescription"),
+				addReadmeModel));
+
+		// add .gitignore
+		File gitignoreDir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore");
+		File [] files = gitignoreDir.listFiles();
+		if (files == null) {
+			files = new File[0];
+		}
+		List<String> gitignores = new ArrayList<String>();
+		for (File file : files) {
+			if (file.isFile() && file.getName().endsWith(".gitignore")) {
+				gitignores.add(StringUtils.stripFileExtension(file.getName()));
+			}
+		}
+		Collections.sort(gitignores);
+
+		gitignoreModel = Model.of("");
+		addGitignoreModel = Model.of(false);
+		form.add(new ConditionalChoiceOption<String>("addGitIgnore",
+				getString("gb.initWithGitignore"),
+				getString("gb.initWithGitignoreDescription"),
+				addGitignoreModel,
+				gitignoreModel,
+				gitignores));
+
+		// TODO consider gitflow at creation (ticket-55)
+		addGitflowModel = Model.of(false);
+		form.add(new CheckboxOption("addGitFlow",
+				"Include a .gitflow file",
+				"This will generate a config file which guides Git clients in setting up Gitflow branches.",
+				addGitflowModel).setVisible(false));
+
+		form.add(new Button("create"));
+
+		add(form);
+	}
+
+	/**
+	 * Prepare the initial commit for the repository.
+	 *
+	 * @param repository
+	 * @param addReadme
+	 * @param gitignore
+	 * @param addGitFlow
+	 * @return true if an initial commit was created
+	 */
+	protected boolean initialCommit(RepositoryModel repository, boolean addReadme, String gitignore,
+			boolean addGitFlow) {
+		boolean initialCommit = addReadme || !StringUtils.isEmpty(gitignore) || addGitFlow;
+		if (!initialCommit) {
+			return false;
+		}
+
+		// build an initial commit
+		boolean success = false;
+		Repository db = app().repositories().getRepository(repositoryModel.name);
+		ObjectInserter odi = db.newObjectInserter();
+		try {
+
+			UserModel user = GitBlitWebSession.get().getUser();
+			PersonIdent author = new PersonIdent(user.getDisplayName(), user.emailAddress);
+
+			DirCache newIndex = DirCache.newInCore();
+			DirCacheBuilder indexBuilder = newIndex.builder();
+
+			if (addReadme) {
+				// insert a README
+				String title = StringUtils.stripDotGit(StringUtils.getLastPathElement(repositoryModel.name));
+				String description = repositoryModel.description == null ? "" : repositoryModel.description;
+				String readme = String.format("## %s\n\n%s\n\n", title, description);
+				byte [] bytes = readme.getBytes(Constants.ENCODING);
+
+				DirCacheEntry entry = new DirCacheEntry("README.md");
+				entry.setLength(bytes.length);
+				entry.setLastModified(System.currentTimeMillis());
+				entry.setFileMode(FileMode.REGULAR_FILE);
+				entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes));
+
+				indexBuilder.add(entry);
+			}
+
+			if (!StringUtils.isEmpty(gitignore)) {
+				// insert a .gitignore file
+				File dir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore");
+				File file = new File(dir, gitignore + ".gitignore");
+				if (file.exists() && file.length() > 0) {
+					byte [] bytes = FileUtils.readContent(file);
+					if (!ArrayUtils.isEmpty(bytes)) {
+						DirCacheEntry entry = new DirCacheEntry(".gitignore");
+						entry.setLength(bytes.length);
+						entry.setLastModified(System.currentTimeMillis());
+						entry.setFileMode(FileMode.REGULAR_FILE);
+						entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes));
+
+						indexBuilder.add(entry);
+					}
+				}
+			}
+
+			if (addGitFlow) {
+				// insert a .gitflow file
+				Config config = new Config();
+				config.setString("gitflow", null, "masterBranch", Constants.MASTER);
+				config.setString("gitflow", null, "developBranch", Constants.DEVELOP);
+				config.setString("gitflow", null, "featureBranchPrefix", "feature/");
+				config.setString("gitflow", null, "releaseBranchPrefix", "release/");
+				config.setString("gitflow", null, "hotfixBranchPrefix", "hotfix/");
+				config.setString("gitflow", null, "supportBranchPrefix", "support/");
+				config.setString("gitflow", null, "versionTagPrefix", "");
+
+				byte [] bytes = config.toText().getBytes(Constants.ENCODING);
+
+				DirCacheEntry entry = new DirCacheEntry(".gitflow");
+				entry.setLength(bytes.length);
+				entry.setLastModified(System.currentTimeMillis());
+				entry.setFileMode(FileMode.REGULAR_FILE);
+				entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes));
+
+				indexBuilder.add(entry);
+			}
+
+			indexBuilder.finish();
+
+			if (newIndex.getEntryCount() == 0) {
+				// nothing to commit
+				return false;
+			}
+
+			ObjectId treeId = newIndex.writeTree(odi);
+
+			// Create a commit object
+			CommitBuilder commit = new CommitBuilder();
+			commit.setAuthor(author);
+			commit.setCommitter(author);
+			commit.setEncoding(Constants.ENCODING);
+			commit.setMessage("Initial commit");
+			commit.setTreeId(treeId);
+
+			// Insert the commit into the repository
+			ObjectId commitId = odi.insert(commit);
+			odi.flush();
+
+			// set the branch refs
+			RevWalk revWalk = new RevWalk(db);
+			try {
+				// set the master branch
+				RevCommit revCommit = revWalk.parseCommit(commitId);
+				RefUpdate masterRef = db.updateRef(Constants.R_MASTER);
+				masterRef.setNewObjectId(commitId);
+				masterRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);
+				Result masterRC = masterRef.update();
+				switch (masterRC) {
+				case NEW:
+					success = true;
+					break;
+				default:
+					success = false;
+				}
+
+				if (addGitFlow) {
+					// set the develop branch for git-flow
+					RefUpdate developRef = db.updateRef(Constants.R_DEVELOP);
+					developRef.setNewObjectId(commitId);
+					developRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);
+					Result developRC = developRef.update();
+					switch (developRC) {
+					case NEW:
+						success = true;
+						break;
+					default:
+						success = false;
+					}
+				}
+			} finally {
+				revWalk.release();
+			}
+		} catch (UnsupportedEncodingException e) {
+			logger().error(null, e);
+		} catch (IOException e) {
+			logger().error(null, e);
+		} finally {
+			odi.release();
+			db.close();
+		}
+		return success;
+	}
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java
index a2f3a49..b1c3639 100644
--- a/src/main/java/com/gitblit/wicket/pages/RootPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java
@@ -607,7 +607,7 @@
 			List<MenuItem> standardItems = new ArrayList<MenuItem>();
 			standardItems.add(new MenuDivider());
 			if (user.canAdmin() || user.canCreate()) {
-				standardItems.add(new PageLinkMenuItem("gb.newRepository", EditRepositoryPage.class));
+				standardItems.add(new PageLinkMenuItem("gb.newRepository", app().getNewRepositoryPage()));
 			}
 			standardItems.add(new PageLinkMenuItem("gb.myProfile", UserPage.class,
 					WicketUtils.newUsernameParameter(user.username)));
diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java
index 6cb791e..29b49b3 100644
--- a/src/main/java/com/gitblit/wicket/pages/UserPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java
@@ -30,8 +30,8 @@
 
 import com.gitblit.Keys;
 import com.gitblit.models.Menu.ParameterMenuItem;
-import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
 import com.gitblit.models.NavLink;
+import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
 import com.gitblit.models.ProjectModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
@@ -95,7 +95,7 @@
 		UserModel sessionUser = GitBlitWebSession.get().getUser();
 		if (sessionUser != null && user.canCreate() && sessionUser.equals(user)) {
 			// user can create personal repositories
-			add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));
+			add(new BookmarkablePageLink<Void>("newRepository", app().getNewRepositoryPage()));
 		} else {
 			add(new Label("newRepository").setVisible(false));
 		}
diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html
new file mode 100644
index 0000000..a2d76b7
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html
@@ -0,0 +1,28 @@
+<!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>
+
+	<h4><wicket:message key="gb.accessPolicy"></wicket:message></h4>
+	<p><wicket:message key="gb.accessPolicyDescription"></wicket:message></p>
+		
+	<div wicket:id="policiesGroup">
+		<div wicket:id="policies" style="padding-top:4px;">
+			<div>
+				<label style="font-weight:bold;"><input type="radio" wicket:id="radio" /> <img wicket:id="image"></img> <span wicket:id="name"></span></label>
+			</div>
+			<label class="checkbox" style="color:#777;" wicket:id="description"></label>
+		</div>
+	</div>
+	
+	<hr />
+	
+	<div wicket:id="allowForks"></div>
+	
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java
new file mode 100644
index 0000000..4f23426
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.panels;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Radio;
+import org.apache.wicket.markup.html.form.RadioGroup;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.Keys;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.wicket.WicketUtils;
+
+/**
+ * A radio group panel of the 5 available authorization/access restriction combinations.
+ *
+ * @author James Moger
+ *
+ */
+public class AccessPolicyPanel extends BasePanel {
+
+	private static final long serialVersionUID = 1L;
+
+	private final RepositoryModel repository;
+
+	private final AjaxFormChoiceComponentUpdatingBehavior callback;
+
+	private RadioGroup<AccessPolicy> policiesGroup;
+
+	private IModel<Boolean> allowForks;
+
+	public AccessPolicyPanel(String wicketId, RepositoryModel repository) {
+		this(wicketId, repository, null);
+	}
+
+	public AccessPolicyPanel(String wicketId, RepositoryModel repository, AjaxFormChoiceComponentUpdatingBehavior callback) {
+		super(wicketId);
+		this.repository = repository;
+		this.callback = callback;
+	}
+
+	@Override
+	protected void onInitialize() {
+		super.onInitialize();
+
+		AccessPolicy anonymousPolicy = new AccessPolicy(getString("gb.anonymousPolicy"),
+				getString("gb.anonymousPolicyDescription"),
+				"blank.png",
+				AuthorizationControl.AUTHENTICATED,
+				AccessRestrictionType.NONE);
+
+		AccessPolicy authenticatedPushPolicy = new AccessPolicy(getString("gb.authenticatedPushPolicy"),
+				getString("gb.authenticatedPushPolicyDescription"),
+				"lock_go_16x16.png",
+				AuthorizationControl.AUTHENTICATED,
+				AccessRestrictionType.PUSH);
+
+		AccessPolicy namedPushPolicy = new AccessPolicy(getString("gb.namedPushPolicy"),
+				getString("gb.namedPushPolicyDescription"),
+				"lock_go_16x16.png",
+				AuthorizationControl.NAMED,
+				AccessRestrictionType.PUSH);
+
+		AccessPolicy clonePolicy = new AccessPolicy(getString("gb.clonePolicy"),
+				getString("gb.clonePolicyDescription"),
+				"lock_pull_16x16.png",
+				AuthorizationControl.NAMED,
+				AccessRestrictionType.CLONE);
+
+		AccessPolicy viewPolicy = new AccessPolicy(getString("gb.viewPolicy"),
+				getString("gb.viewPolicyDescription"),
+				"shield_16x16.png",
+				AuthorizationControl.NAMED,
+				AccessRestrictionType.VIEW);
+
+		List<AccessPolicy> policies = new ArrayList<AccessPolicy>();
+		if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) {
+			policies.add(anonymousPolicy);
+		}
+		policies.add(authenticatedPushPolicy);
+		policies.add(namedPushPolicy);
+		policies.add(clonePolicy);
+		policies.add(viewPolicy);
+
+		AccessRestrictionType defaultRestriction = repository.accessRestriction;
+		if (defaultRestriction == null) {
+			defaultRestriction = AccessRestrictionType.fromName(app().settings().getString(Keys.git.defaultAccessRestriction,
+					AccessRestrictionType.PUSH.name()));
+		}
+
+		AuthorizationControl defaultControl = repository.authorizationControl;
+		if (defaultControl == null) {
+			defaultControl = AuthorizationControl.fromName(app().settings().getString(Keys.git.defaultAuthorizationControl,
+					AuthorizationControl.NAMED.name()));
+		}
+
+		AccessPolicy defaultPolicy = namedPushPolicy;
+		for (AccessPolicy policy : policies) {
+			if (policy.type == defaultRestriction && policy.control == defaultControl) {
+				defaultPolicy = policy;
+			}
+		}
+
+		policiesGroup = new RadioGroup<>("policiesGroup", new Model<AccessPolicy>(defaultPolicy));
+		ListView<AccessPolicy> policiesList = new ListView<AccessPolicy>("policies", policies) {
+
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			protected void populateItem(ListItem<AccessPolicy> item) {
+				AccessPolicy p = item.getModelObject();
+				item.add(new Radio<AccessPolicy>("radio", item.getModel()));
+				item.add(WicketUtils.newImage("image",  p.image));
+				item.add(new Label("name", p.name));
+				item.add(new Label("description", p.description));
+			}
+		};
+		policiesGroup.add(policiesList);
+		if (callback != null) {
+			policiesGroup.add(callback);
+			policiesGroup.setOutputMarkupId(true);
+		}
+		add(policiesGroup);
+
+		allowForks = Model.of(true);
+		add(new CheckboxOption("allowForks",
+				getString("gb.allowForks"),
+				getString("gb.allowForksDescription"),
+				allowForks).setEnabled(app().settings().getBoolean(Keys.web.allowForking, true)));
+
+		setOutputMarkupId(true);
+	}
+
+	public void updateModel(RepositoryModel repository) {
+		AccessPolicy policy = policiesGroup.getModelObject();
+		repository.authorizationControl = policy.control;
+		repository.accessRestriction = policy.type;
+		repository.allowForks = allowForks.getObject();
+	}
+
+	@Override
+	protected boolean getStatelessHint() {
+		return false;
+	}
+
+	public static class AccessPolicy implements Serializable {
+
+		private static final long serialVersionUID = 1L;
+
+		final String name;
+		final String description;
+		final String image;
+		final AuthorizationControl control;
+		final AccessRestrictionType type;
+
+		AccessPolicy(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) {
+			this.name = name;
+			this.description = description;
+			this.image = img;
+			this.control = control;
+			this.type = type;
+		}
+
+		@Override
+		public String toString() {
+			return name;
+		}
+	}
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html
new file mode 100644
index 0000000..6684fe9
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  
+      xml:lang="en"  
+      lang="en"> 
+
+<body>
+<wicket:panel>
+	<div style="padding-top:4px;">
+		<div>
+			<label style="font-weight:bold;" class="checkbox"><input type="checkbox" wicket:id="checkbox" /> <span wicket:id="name"></span></label>
+		</div>
+		<label class="checkbox" style="color:#777;" wicket:id="description"></label>
+	</div>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java
new file mode 100644
index 0000000..08eeaa2
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.panels;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.model.IModel;
+import org.parboiled.common.StringUtils;
+
+/**
+ * A re-usable checkbox option panel.
+ *
+ * [x] title
+ *     description
+ *
+ * @author James Moger
+ *
+ */
+public class CheckboxOption extends BasePanel {
+
+	private static final long serialVersionUID = 1L;
+
+	public CheckboxOption(String wicketId, String title, String description, IModel<Boolean> model) {
+		super(wicketId);
+		add(new Label("name", title));
+		add(new Label("description", description).setVisible(!StringUtils.isEmpty(description)));
+		add(new CheckBox("checkbox", model));
+	}
+
+	public CheckboxOption(String wicketId, String title, String description, CheckBox checkbox) {
+		super(wicketId);
+		add(new Label("name", title));
+		add(new Label("description", description).setVisible(!StringUtils.isEmpty(description)));
+		add(checkbox.setMarkupId("checkbox"));
+	}
+
+	public CheckboxOption setIsHtmlDescription(boolean val) {
+		((Label) get("description")).setEscapeModelStrings(!val);
+		return this;
+	}
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html
new file mode 100644
index 0000000..8c34c81
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  
+      xml:lang="en"  
+      lang="en"> 
+
+<body>
+<wicket:panel>
+	<div style="padding-top:4px;">
+		<div>
+			<b><span wicket:id="name"></span></b>
+		</div>
+		<label class="checkbox" style="color:#777;"> <span wicket:id="description"></span>
+		<p style="padding-top:5px;"><select class="span3" wicket:id="choice" /></p>
+		</label>		
+	</div>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/ChoiceOption.java b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.java
new file mode 100644
index 0000000..9c25b70
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.panels;
+
+import java.util.List;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.model.IModel;
+import org.parboiled.common.StringUtils;
+
+/**
+ * A re-usable choice option panel.
+ *
+ * title
+ *     description
+ *     [choices]
+ *
+ * @author James Moger
+ *
+ */
+public class ChoiceOption<T> extends BasePanel {
+
+	private static final long serialVersionUID = 1L;
+
+	public ChoiceOption(String wicketId, String title, String description, IModel<T> model, List<T> choices) {
+		super(wicketId);
+		add(new Label("name", title));
+		add(new Label("description", description).setVisible(!StringUtils.isEmpty(description)));
+		add(new DropDownChoice<>("choice", model, choices).setEnabled(choices.size() > 0));
+	}
+
+	public ChoiceOption(String wicketId, String title, String description, DropDownChoice<?> choice) {
+		super(wicketId);
+		add(new Label("name", title));
+		add(new Label("description", description).setVisible(!StringUtils.isEmpty(description)));
+		add(choice.setMarkupId("choice").setEnabled(choice.getChoices().size() > 0));
+	}
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html b/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html
new file mode 100644
index 0000000..fb360d1
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  
+      xml:lang="en"  
+      lang="en"> 
+
+<body>
+<wicket:panel>
+	<div style="padding-top:4px;">
+		<div>
+			<label style="font-weight:bold;" class="checkbox"><input type="checkbox" wicket:id="checkbox" /> <span wicket:id="name"></span></label>
+		</div>
+		<label class="checkbox" style="color:#777;"> <span wicket:id="description"></span>
+		<p style="padding-top:5px;"><select class="span3" wicket:id="choice" /></p>
+		</label>		
+	</div>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.java b/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.java
new file mode 100644
index 0000000..07aaee8
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.panels;
+
+import java.util.List;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.model.IModel;
+import org.parboiled.common.StringUtils;
+
+/**
+ * A re-usable conditional choice option panel.
+ *
+ * [x] title
+ *     description
+ *     [choices]
+ *
+ * @author James Moger
+ *
+ */
+public class ConditionalChoiceOption<T> extends BasePanel {
+
+	private static final long serialVersionUID = 1L;
+
+	final CheckBox checkbox;
+	final DropDownChoice<T> choice;
+
+	public ConditionalChoiceOption(String wicketId, String title, String description, IModel<Boolean> checkboxModel, IModel<T> choiceModel, List<T> choices) {
+		super(wicketId);
+		add(new Label("name", title));
+		add(new Label("description", description).setVisible(!StringUtils.isEmpty(description)));
+
+		this.checkbox = new CheckBox("checkbox", checkboxModel);
+		checkbox.setOutputMarkupId(true);
+
+		this.choice = new DropDownChoice<T>("choice", choiceModel, choices);
+		choice.setOutputMarkupId(true);
+
+		setup();
+	}
+
+	private void setup() {
+		add(checkbox);
+		add(choice.setMarkupId("choice").setEnabled(choice.getChoices().size() > 0));
+		choice.setEnabled(checkbox.getModelObject());
+
+		checkbox.add(new AjaxFormComponentUpdatingBehavior("onchange") {
+
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			protected void onUpdate(AjaxRequestTarget target) {
+				choice.setEnabled(checkbox.getModelObject());
+				target.addComponent(choice);
+				if (!choice.isEnabled()) {
+					choice.setModelObject(null);
+				}
+			}
+		});
+	}
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java
index 45b0bab..4433b04 100644
--- a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java
+++ b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java
@@ -33,7 +33,6 @@
 import com.gitblit.wicket.WicketUtils;
 import com.gitblit.wicket.freemarker.FreemarkerPanel;
 import com.gitblit.wicket.ng.NgController;
-import com.gitblit.wicket.pages.EditRepositoryPage;
 
 /**
  * A client-side filterable rich repository list which uses Freemarker, Wicket,
@@ -98,7 +97,7 @@
 		}
 
 		if (allowCreate) {
-			panel.add(new LinkPanel(ngList + "Button", "btn btn-mini", getString("gb.newRepository"), EditRepositoryPage.class));
+			panel.add(new LinkPanel(ngList + "Button", "btn btn-mini", getString("gb.newRepository"), app().getNewRepositoryPage()));
 		} else {
 			panel.add(new Label(ngList + "Button").setVisible(false));
 		}
diff --git a/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html b/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html
index eb82245..a48797e 100644
--- a/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html
@@ -16,7 +16,7 @@
 	</form>
 	
 	<div style="clear:both;" wicket:id="permissionRow">
-		<div style="padding-top:10px;border-left:1px solid #ccc;border-right:1px solid #ccc;" class="row-fluid">
+		<div style="padding-top:10px;" class="row-fluid">
 			<div style="padding-top:5px;padding-left:5px" class="span6"><span wicket:id="registrant"></span></div><div style="padding-top:5px;padding-right:5px;text-align:right;" class="span3"><span class="label" wicket:id="pType">[permission type]</span></div> <select class="input-medium" wicket:id="permission"></select>
 		</div>
 	</div>
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java
index dd208e2..8573e1a 100644
--- a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java
@@ -51,7 +51,6 @@
 import com.gitblit.wicket.GitBlitWebSession;
 import com.gitblit.wicket.WicketUtils;
 import com.gitblit.wicket.pages.BasePage;
-import com.gitblit.wicket.pages.EditRepositoryPage;
 import com.gitblit.wicket.pages.ProjectPage;
 import com.gitblit.wicket.pages.RepositoriesPage;
 import com.gitblit.wicket.pages.SummaryPage;
@@ -87,12 +86,12 @@
 					setResponsePage(RepositoriesPage.class);
 				}
 			}.setVisible(app().settings().getBoolean(Keys.git.cacheRepositoryList, true)));
-			managementLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));
+			managementLinks.add(new BookmarkablePageLink<Void>("newRepository", app().getNewRepositoryPage()));
 			add(managementLinks);
 		} else if (showManagement && user != null && user.canCreate()) {
 			// user can create personal repositories
 			managementLinks = new Fragment("managementPanel", "personalLinks", this);
-			managementLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));
+			managementLinks.add(new BookmarkablePageLink<Void>("newRepository", app().getNewRepositoryPage()));
 			add(managementLinks);
 		} else {
 			// user has no management permissions
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html
new file mode 100644
index 0000000..6fb6e45
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  
+      xml:lang="en"  
+      lang="en"> 
+
+<body>
+<wicket:panel>
+
+	<table class="plain">
+		<tbody class="settings">
+			<tr>
+				<th><wicket:message key="gb.project"></wicket:message></th>
+				<th><wicket:message key="gb.name"></wicket:message></th>
+			</tr>
+			<tr>
+				<td><select class="span2" wicket:id="projectPath" /></td>
+				<td class="edit"><input class="span4" type="text" wicket:id="name" id="name" /> &nbsp;<span class="help-inline"><wicket:message key="gb.nameDescription"></wicket:message></span></td>
+			</tr>
+		</tbody>
+	</table>
+	
+	<div>
+		<b><wicket:message key="gb.description"></wicket:message></b><br/>
+		<input class="span5" type="text" wicket:id="description" />
+	</div>
+			
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java
new file mode 100644
index 0000000..358ff59
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.panels;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.markup.html.form.TextField;
+
+import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+
+/**
+ * A panel for naming a repository, specifying it's project, and entering a description.
+ *
+ * @author James Moger
+ *
+ */
+public class RepositoryNamePanel extends BasePanel {
+
+	private static final long serialVersionUID = 1L;
+
+	private String fullName;
+
+	private DropDownChoice<String> projectChoice;
+
+	private TextField<String> nameField;
+
+	public RepositoryNamePanel(String wicketId, RepositoryModel repository) {
+		super(wicketId);
+
+		GitBlitWebSession session = GitBlitWebSession.get();
+		UserModel user = session.getUser();
+
+		// build project set for repository destination
+		String defaultProject = null;
+		Set<String> projectNames = new TreeSet<String>();
+
+		// add the registered/known projects
+		for (ProjectModel project : app().projects().getProjectModels(user, false)) {
+			// TODO issue-351: user.canAdmin(project)
+			if (user.canAdmin()) {
+				if (project.isRoot) {
+					projectNames.add("/");
+				} else {
+					projectNames.add(project.name + "/");
+				}
+			}
+		}
+
+		// add the user's personal project namespace
+		if (user.canAdmin() || user.canCreate()) {
+			projectNames.add(user.getPersonalPath() + "/");
+		}
+
+		if (!StringUtils.isEmpty(repository.name)) {
+			// editing a repository name
+			// set the defaultProject to the current repository project
+			defaultProject = repository.projectPath;
+			if (StringUtils.isEmpty(defaultProject)) {
+				defaultProject = "/";
+			} else {
+				defaultProject += "/";
+			}
+
+			projectNames.add(defaultProject);
+		}
+
+		// if default project is not already set, set preference based on the user permissions
+		if (defaultProject == null) {
+			if (user.canAdmin()) {
+				defaultProject = "/";
+			} else if (user.canCreate()) {
+				defaultProject = user.getPersonalPath() + "/";
+			}
+		}
+
+		// update the model which is reflectively mapped to the Wicket fields by name
+		repository.projectPath = defaultProject;
+		if (repository.projectPath.length() > 1 && !StringUtils.isEmpty(repository.name)) {
+			repository.name = repository.name.substring(repository.projectPath.length());
+		}
+		projectChoice = new DropDownChoice<String>("projectPath", new ArrayList<String>(projectNames));
+		nameField = new TextField<String>("name");
+
+		// only enable project selection if we actually have multiple choices
+		add(projectChoice.setEnabled(projectNames.size() > 1));
+		add(nameField);
+		add(new TextField<String>("description"));
+	}
+
+	public void setEditable(boolean editable) {
+		// only enable project selection if we actually have multiple choices
+		projectChoice.setEnabled(projectChoice.getChoices().size() > 1 && editable);
+		nameField.setEnabled(editable);
+	}
+
+	public boolean updateModel(RepositoryModel repositoryModel) {
+		// confirm a project was selected
+		if (StringUtils.isEmpty(repositoryModel.projectPath)) {
+			error(getString("gb.pleaseSelectProject"));
+			return false;
+		}
+
+		// confirm a repository name was entered
+		if (StringUtils.isEmpty(repositoryModel.name)) {
+			error(getString("gb.pleaseSetRepositoryName"));
+			return false;
+		}
+
+		String project = repositoryModel.projectPath;
+
+		fullName = (project + repositoryModel.name).trim();
+		fullName = fullName.replace('\\', '/');
+		fullName = fullName.replace("//", "/");
+		if (fullName.charAt(0) == '/') {
+			fullName = fullName.substring(1);
+		}
+		if (fullName.endsWith("/")) {
+			fullName = fullName.substring(0, fullName.length() - 1);
+		}
+
+		if (fullName.contains("../")) {
+			error(getString("gb.illegalRelativeSlash"));
+			return false;
+		}
+		if (fullName.contains("/../")) {
+			error(getString("gb.illegalRelativeSlash"));
+			return false;
+		}
+
+		// confirm valid characters in repository name
+		Character c = StringUtils.findInvalidCharacter(fullName);
+		if (c != null) {
+			error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"), c));
+			return false;
+		}
+
+		repositoryModel.name = fullName;
+		repositoryModel.projectPath = null;
+
+		return true;
+	}
+
+	public void resetModel(RepositoryModel repositoryModel) {
+		// restore project and name fields on error condition
+		repositoryModel.projectPath = StringUtils.getFirstPathElement(fullName) + "/";
+		if (repositoryModel.projectPath.length() > 1) {
+			repositoryModel.name = fullName.substring(repositoryModel.projectPath.length());
+		}
+	}
+
+	@Override
+	protected boolean getStatelessHint() {
+		return false;
+	}
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/TextOption.html b/src/main/java/com/gitblit/wicket/panels/TextOption.html
new file mode 100644
index 0000000..ff2da78
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/TextOption.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  
+      xml:lang="en"  
+      lang="en"> 
+
+<body>
+<wicket:panel>
+	<div style="padding-top:4px;">
+		<div>
+			<b><span wicket:id="name"></span></b>
+		</div>
+		<label class="checkbox" style="color:#777;"> <span wicket:id="description"></span>
+		<p style="padding-top:5px;"><input class="span2" type="text" wicket:id="text" /></p>
+		</label>
+		
+	</div>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/panels/TextOption.java b/src/main/java/com/gitblit/wicket/panels/TextOption.java
new file mode 100644
index 0000000..22370f3
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/panels/TextOption.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.panels;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.IModel;
+
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+
+/**
+ * A re-usable textfield option panel.
+ *
+ * title
+ *     description
+ *     [textfield]
+ *
+ * @author James Moger
+ *
+ */
+public class TextOption extends BasePanel {
+
+	private static final long serialVersionUID = 1L;
+
+	public TextOption(String wicketId, String title, String description, IModel<String> model) {
+		this(wicketId, title, description, null, model);
+	}
+
+	public TextOption(String wicketId, String title, String description, String css, IModel<String> model) {
+		super(wicketId);
+		add(new Label("name", title));
+		add(new Label("description", description).setVisible(!StringUtils.isEmpty(description)));
+		TextField<String> tf = new TextField<String>("text", model);
+		if (!StringUtils.isEmpty(css)) {
+			WicketUtils.setCssClass(tf, css);
+		}
+		add(tf);
+	}
+}

--
Gitblit v1.9.1