From 85b5d72949ead641ba697543324ff5d236e23fd1 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Tue, 03 Jun 2014 10:34:51 -0400
Subject: [PATCH] Overhaul EditRepositoryPage for layout and usability

---
 src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java   |   20 +
 src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html |    2 
 src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html   |  248 ++++++++++++++++------
 src/main/java/com/gitblit/wicket/GitBlitWebApp.properties        |   24 +
 src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html   |   35 ++-
 src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java   |  288 ++++++++++++++++++++-----
 6 files changed, 473 insertions(+), 144 deletions(-)

diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties
index 13abcc0..bd5d89e 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!
@@ -704,3 +704,21 @@
 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.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 ab44803..b5f9528 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,97 +27,200 @@
 
 		<!-- general tab -->
 		<div class="tab-pane active" id="general">
-		<div wicket:id="namePanel"></div>
+
+			<div wicket:id="namePanel"></div>
 		
-		<table class="plain">
-			<tbody class="settings">
-				<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>
+			<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></th><td style="padding:2px;"><span wicket:id="accessPolicyPanel"></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:fragment wicket:id="checkboxOption">
+	<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:fragment>
+
+<wicket:fragment wicket:id="choiceOption">
+	<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="span2" wicket:id="choice" /></p>
+		</label>
+		
+	</div>
+</wicket:fragment>
+
+<wicket:fragment wicket:id="textfieldOption">
+	<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:fragment>
+
 </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 e86bd1e..16dac89 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -43,9 +43,11 @@
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Fragment;
 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;
@@ -200,7 +202,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>();
@@ -387,21 +389,7 @@
 			}
 		};
 
-		// do not let the browser pre-populate these fields
-		form.add(new SimpleAttributeModifier("autocomplete", "off"));
-
-		// field names reflective match RepositoryModel fields
-		namePanel = new RepositoryNamePanel("namePanel", repositoryModel);
-		namePanel.setEditable(allowEditName);
-		form.add(namePanel);
-
-		form.add(ownersPalette);
-		form.add(new CheckBox("allowForks").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true)));
-		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)) {
@@ -414,53 +402,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.
 
-		final CheckBox verifyCommitter = new CheckBox("verifyCommitter");
-		verifyCommitter.setOutputMarkupId(true);
-		form.add(verifyCommitter);
+		form.add(newChoice("head",
+				getString("gb.headRef"),
+				getString("gb.headRefDescription"),
+				new PropertyModel<String>(repositoryModel, "HEAD"),
+				availableRefs));
 
+
+		//
+		// PERMISSIONS
+		//
+		form.add(ownersPalette);
 		form.add(usersPalette);
 		form.add(teamsPalette);
-		form.add(federationSetsPalette);
+
+		//
+		// TICKETS
+		//
+		form.add(newCheckbox("acceptNewPatchsets",
+				getString("gb.acceptNewPatchsets"),
+				getString("gb.acceptNewPatchsetsDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "acceptNewPatchsets")));
+
+		form.add(newCheckbox("acceptNewTickets",
+				getString("gb.acceptNewTickets"),
+				getString("gb.acceptNewTicketsDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "acceptNewPatchsets")));
+
+		form.add(newCheckbox("requireApproval",
+				getString("gb.requireApproval"),
+				getString("gb.requireApprovalDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "requireApproval")));
+
+		form.add(newChoice("mergeTo",
+				getString("gb.mergeTo"),
+				getString("gb.mergeToDescription"),
+				new PropertyModel<String>(repositoryModel, "mergeTo"),
+				availableBranches));
+
+		//
+		// RECEIVE
+		//
+		form.add(newCheckbox("isFrozen",
+				getString("gb.isFrozen"),
+				getString("gb.isFrozenDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "isFrozen")));
+
+		form.add(newCheckbox("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(newCheckbox("verifyCommitter",
+				getString("gb.verifyCommitter"),
+				getString("gb.verifyCommitterDescription"),
+				verifyCommitter));
+
 		form.add(preReceivePalette);
 		form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), app().repositories()
 				.getPreReceiveScriptsInherited(repositoryModel)));
@@ -471,6 +485,116 @@
 		WebMarkupContainer customFieldsSection = new WebMarkupContainer("customFieldsSection");
 		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(newChoice("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(newChoice("gcPeriod",
+				getString("gb.gcPeriod"),
+				getString("gb.gcPeriodDescription"),
+				new DropDownChoice<Integer>("choice",
+						new PropertyModel<Integer>(repositoryModel, "gcPeriod"),
+						gcPeriods,
+						new GCPeriodRenderer())).setEnabled(gcEnabled));
+
+		form.add(newTextfield("gcThreshold",
+				getString("gb.gcThreshold"),
+				getString("gb.gcThresholdDescription"),
+				"span1",
+				new PropertyModel<String>(repositoryModel, "gcThreshold")).setEnabled(gcEnabled));
+
+		//
+		// MISCELLANEOUS
+		//
+
+		form.add(newTextfield("origin",
+				getString("gb.origin"),
+				getString("gb.originDescription"),
+				"span6",
+				new PropertyModel<String>(repositoryModel, "origin")).setEnabled(false));
+
+		form.add(newCheckbox("showRemoteBranches",
+				getString("gb.showRemoteBranches"),
+				getString("gb.showRemoteBranchesDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "showRemoteBranches")));
+
+		form.add(newCheckbox("skipSizeCalculation",
+				getString("gb.skipSizeCalculation"),
+				getString("gb.skipSizeCalculationDescription"),
+				new PropertyModel<Boolean>(repositoryModel, "skipSizeCalculation")));
+
+		form.add(newCheckbox("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(newChoice("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(newChoice("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(newTextfield("metricAuthorExclusions",
+				getString("gb.metricAuthorExclusions"),
+				getString("gb.metricAuthorExclusions"),
+				"span6",
+				metricAuthorExclusions));
+
+		mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
+				: StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
+
+		form.add(newTextfield("mailingLists",
+				getString("gb.mailingLists"),
+				getString("gb.mailingLists"),
+				"span6",
+				mailingLists));
+
 
 		// initial enable/disable of permission controls
 		if (repositoryModel.accessRestriction.equals(AccessRestrictionType.NONE)) {
@@ -488,6 +612,9 @@
 			teamsPalette.setEnabled(allowFineGrainedControls);
 		}
 
+		//
+		// ACCESS POLICY PANEL (GENERAL)
+		//
 		AjaxFormChoiceComponentUpdatingBehavior callback = new AjaxFormChoiceComponentUpdatingBehavior() {
 
 			private static final long serialVersionUID = 1L;
@@ -516,10 +643,10 @@
 		accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel, callback);
 		form.add(accessPolicyPanel);
 
-		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;
@@ -625,6 +752,51 @@
 		}
 	}
 
+	private Fragment newCheckbox(String wicketId, String title, String description, IModel<Boolean> model) {
+		Fragment fragment = new Fragment(wicketId, "checkboxOption", this);
+		fragment.add(new Label("name", title));
+		fragment.add(new Label("description", description));
+		fragment.add(new CheckBox("checkbox", model));
+		return fragment;
+	}
+
+	private Fragment newCheckbox(String wicketId, String title, String description, CheckBox checkbox) {
+		Fragment fragment = new Fragment(wicketId, "checkboxOption", this);
+		fragment.add(new Label("name", title));
+		fragment.add(new Label("description", description));
+		fragment.add(checkbox);
+		return fragment;
+	}
+
+	private <T> Fragment newChoice(String wicketId, String title, String description, IModel<T> model, List<T> choices) {
+		Fragment fragment = new Fragment(wicketId, "choiceOption", this);
+		fragment.add(new Label("name", title));
+		fragment.add(new Label("description", description));
+		fragment.add(new DropDownChoice<>("choice", model, choices).setEnabled(choices.size() > 0));
+		return fragment;
+	}
+
+	private <T> Fragment newChoice(String wicketId, String title, String description, DropDownChoice<?> choice) {
+		Fragment fragment = new Fragment(wicketId, "choiceOption", this);
+		fragment.add(new Label("name", title));
+		fragment.add(new Label("description", description));
+		fragment.add(choice.setEnabled(choice.getChoices().size() > 0));
+		return fragment;
+	}
+
+	private Fragment newTextfield(String wicketId, String title, String description, String css, IModel<String> model) {
+		Fragment fragment = new Fragment(wicketId, "textfieldOption", this);
+		fragment.add(new Label("name", title));
+		fragment.add(new Label("description", description));
+		TextField<String> tf = new TextField<String>("text", model);
+		if (!StringUtils.isEmpty(css)) {
+			WicketUtils.setCssClass(tf, css);
+		}
+		fragment.add(tf);
+		return fragment;
+	}
+
+
 	private class FederationTypeRenderer implements IChoiceRenderer<FederationStrategy> {
 
 		private static final long serialVersionUID = 1L;
diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html
index 38fa7f6..965c4d5 100644
--- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html
@@ -10,19 +10,32 @@
 	<h4><wicket:message key="gb.accessPolicy"></wicket:message></h4>
 	<p><wicket:message key="gb.accessPolicyDescription"></wicket:message></p>
 		
-	<span wicket:id="policiesGroup">
-			<div wicket:id="policies">
-				<div style="display: inline-block;vertical-align: top;">
-					<input type="radio" wicket:id="radio" />
-					<img wicket:id="image"></img> 
-				</div>
-				<div style="display: inline-block;vertical-align: top;">
-					<b><span wicket:id="name"></span></b><br/>
-					<span wicket:id="description"></span>
-				</div>
+	<div wicket:id="policiesGroup">
+		<div wicket:id="policies" style="padding-top:4px;">
+			<div style="display: inline-block;vertical-align: top;">
+				<input type="radio" wicket:id="radio" />
+				<img wicket:id="image"></img> 
 			</div>
-		</span>
+			<div style="display: inline-block;vertical-align: top;">
+				<b><span wicket:id="name"></span></b><br/>
+				<span class="help-inline" wicket:id="description"></span>
+			</div>
+		</div>
+	</div>
 	
+	<hr />
+	
+	<div wicket:id="allowForks"></div>
+	
+<wicket:fragment wicket:id="checkboxOption">
+	<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:fragment>
+
 </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
index 057b96f..7aa801f 100644
--- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java
@@ -21,10 +21,13 @@
 
 import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
 import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.CheckBox;
 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.markup.html.panel.Fragment;
+import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 
 import com.gitblit.Constants.AccessRestrictionType;
@@ -48,6 +51,8 @@
 	private final AjaxFormChoiceComponentUpdatingBehavior callback;
 
 	private RadioGroup<AccessPolicy> policiesGroup;
+
+	private IModel<Boolean> allowForks;
 
 	public AccessPolicyPanel(String wicketId, RepositoryModel repository) {
 		this(wicketId, repository, null);
@@ -142,13 +147,28 @@
 		}
 		add(policiesGroup);
 
+		allowForks = Model.of(true);
+		add(newCheckbox("allowForks",
+				getString("gb.allowForks"),
+				getString("gb.allowForksDescription"),
+				allowForks).setEnabled(app().settings().getBoolean(Keys.web.allowForking, true)));
+
 		setOutputMarkupId(true);
+	}
+
+	private Fragment newCheckbox(String wicketId, String title, String description, IModel<Boolean> model) {
+		Fragment fragment = new Fragment(wicketId, "checkboxOption", this);
+		fragment.add(new Label("name", title));
+		fragment.add(new Label("description", description));
+		fragment.add(new CheckBox("checkbox", model));
+		return fragment;
 	}
 
 	public void updateModel(RepositoryModel repository) {
 		AccessPolicy policy = policiesGroup.getModelObject();
 		repository.authorizationControl = policy.control;
 		repository.accessRestriction = policy.type;
+		repository.allowForks = allowForks.getObject();
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html
index 3c65162..6fb6e45 100644
--- a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html
@@ -15,7 +15,7 @@
 			</tr>
 			<tr>
 				<td><select class="span2" wicket:id="projectPath" /></td>
-				<td class="edit"><input class="span3" type="text" wicket:id="name" id="name" /> &nbsp;<span class="help-inline"><wicket:message key="gb.nameDescription"></wicket:message></span></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>

--
Gitblit v1.9.1