From 85b5d72949ead641ba697543324ff5d236e23fd1 Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 3 Jun 2014 00:16:38 -0400 Subject: [PATCH] Overhaul EditRepositoryPage for layout and usability --- .../gitblit/wicket/GitBlitWebApp.properties | 24 +- .../wicket/pages/EditRepositoryPage.html | 242 ++++++++++----- .../wicket/pages/EditRepositoryPage.java | 288 ++++++++++++++---- .../wicket/panels/AccessPolicyPanel.html | 35 ++- .../wicket/panels/AccessPolicyPanel.java | 20 ++ .../wicket/panels/RepositoryNamePanel.html | 2 +- 6 files changed, 470 insertions(+), 141 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 13abcc06..bd5d89e0 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -133,7 +133,7 @@ gb.sendProposal = propose 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.queryResults = results {0} - {1} ({2} hits) 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.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.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 BEFORE the refs are updated.

This is the appropriate hook for rejecting a push.

+gb.postReceiveDescription = Post-receive hooks are executed after commits are received but AFTER the refs are updated.

This is the appropriate hook for notifications, build triggers, etc.

+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 ab448038..b5f9528f 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 @@
-
+
@@ -24,97 +27,200 @@
-
+ +
+ +
+ +
- - - - - - - - - - - - - - - - - - - - - - - -

 



+ +

+

+
+ +
+ +

+

+
+ +
+ +

+

+
+ +
+ + +
+

+

+ +
+ +
+
+
+ +
+ +

+

+ - - - - - - - - - - - + + + +




-
- -
+
+ +

+

+ - - + + + +
+ +
+
+ +

+

+ + + + +
+
+ +
+ + +
+ +

+

+ +
+ +
+
+
+
+ +
+ + +
+

+

+ +
+ +
+ +
+ +

+

+ +
- -
- - - - -
-
- - - -

 

+ +
+ +

+

+ +
+
-
-
-
-
+ + +
-
-
-
   
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
   
+ +
+
+ + +
+
+ +
+ +
+
+ + +
+
+ +
+ + +
+
+ \ 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 e86bd1ee..16dac895 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.form.TextField; 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 @@ public class EditRepositoryPage extends RootSubPage { } } final Palette ownersPalette = new Palette("owners", new ListModel(owners), new CollectionModel( - persons), new ChoiceRenderer(null, "userId"), 12, true); + persons), new ChoiceRenderer(null, "userId"), 12, false); // indexed local branches palette List allLocalBranches = new ArrayList(); @@ -387,21 +389,7 @@ public class EditRepositoryPage extends RootSubPage { } }; - // 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("origin").setEnabled(false/* isCreate */)); - - // allow relinking HEAD to a branch or tag other than master on edit repository + // Determine available refs & branches List availableRefs = new ArrayList(); List availableBranches = new ArrayList(); if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) { @@ -414,53 +402,79 @@ public class EditRepositoryPage extends RootSubPage { } } } - form.add(new DropDownChoice("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 gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 ); - form.add(new DropDownChoice("gcPeriod", gcPeriods, new GCPeriodRenderer()).setEnabled(gcEnabled)); - form.add(new TextField("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 federationStrategies = new ArrayList( - Arrays.asList(FederationStrategy.values())); - if (StringUtils.isEmpty(repositoryModel.origin)) { - federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN); - } - form.add(new DropDownChoice("federationStrategy", federationStrategies, - new FederationTypeRenderer())); - form.add(new CheckBox("acceptNewPatchsets")); - form.add(new CheckBox("acceptNewTickets")); - form.add(new CheckBox("requireApproval")); - form.add(new DropDownChoice("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 maxActivityCommits = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500); - form.add(new DropDownChoice("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer())); - metricAuthorExclusions = new Model(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? "" - : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " ")); - form.add(new TextField("metricAuthorExclusions", metricAuthorExclusions)); + // + // + // GENERAL + // + namePanel = new RepositoryNamePanel("namePanel", repositoryModel); + namePanel.setEditable(allowEditName); + form.add(namePanel); - mailingLists = new Model(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? "" - : StringUtils.flattenStrings(repositoryModel.mailingLists, " ")); - form.add(new TextField("mailingLists", mailingLists)); - form.add(indexedBranchesPalette); + // XXX AccessPolicyPanel is defined later. + + form.add(newChoice("head", + getString("gb.headRef"), + getString("gb.headRefDescription"), + new PropertyModel(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(newCheckbox("acceptNewPatchsets", + getString("gb.acceptNewPatchsets"), + getString("gb.acceptNewPatchsetsDescription"), + new PropertyModel(repositoryModel, "acceptNewPatchsets"))); + + form.add(newCheckbox("acceptNewTickets", + getString("gb.acceptNewTickets"), + getString("gb.acceptNewTicketsDescription"), + new PropertyModel(repositoryModel, "acceptNewPatchsets"))); + + form.add(newCheckbox("requireApproval", + getString("gb.requireApproval"), + getString("gb.requireApprovalDescription"), + new PropertyModel(repositoryModel, "requireApproval"))); + + form.add(newChoice("mergeTo", + getString("gb.mergeTo"), + getString("gb.mergeToDescription"), + new PropertyModel(repositoryModel, "mergeTo"), + availableBranches)); + + // + // RECEIVE + // + form.add(newCheckbox("isFrozen", + getString("gb.isFrozen"), + getString("gb.isFrozenDescription"), + new PropertyModel(repositoryModel, "isFrozen"))); + + form.add(newCheckbox("incrementalPushTags", + getString("gb.enableIncrementalPushTags"), + getString("gb.useIncrementalPushTagsDescription"), + new PropertyModel(repositoryModel, "useIncrementalPushTags"))); + + final CheckBox verifyCommitter = new CheckBox("checkbox", new PropertyModel(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))); @@ -472,6 +486,116 @@ public class EditRepositoryPage extends RootSubPage { customFieldsSection.add(customFieldsListView); form.add(customFieldsSection.setVisible(!app().settings().getString(Keys.groovy.customFields, "").isEmpty())); + // + // FEDERATION + // + List federationStrategies = new ArrayList( + 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( + "choice", + new PropertyModel(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 gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 ); + form.add(newChoice("gcPeriod", + getString("gb.gcPeriod"), + getString("gb.gcPeriodDescription"), + new DropDownChoice("choice", + new PropertyModel(repositoryModel, "gcPeriod"), + gcPeriods, + new GCPeriodRenderer())).setEnabled(gcEnabled)); + + form.add(newTextfield("gcThreshold", + getString("gb.gcThreshold"), + getString("gb.gcThresholdDescription"), + "span1", + new PropertyModel(repositoryModel, "gcThreshold")).setEnabled(gcEnabled)); + + // + // MISCELLANEOUS + // + + form.add(newTextfield("origin", + getString("gb.origin"), + getString("gb.originDescription"), + "span6", + new PropertyModel(repositoryModel, "origin")).setEnabled(false)); + + form.add(newCheckbox("showRemoteBranches", + getString("gb.showRemoteBranches"), + getString("gb.showRemoteBranchesDescription"), + new PropertyModel(repositoryModel, "showRemoteBranches"))); + + form.add(newCheckbox("skipSizeCalculation", + getString("gb.skipSizeCalculation"), + getString("gb.skipSizeCalculationDescription"), + new PropertyModel(repositoryModel, "skipSizeCalculation"))); + + form.add(newCheckbox("skipSummaryMetrics", + getString("gb.skipSummaryMetrics"), + getString("gb.skipSummaryMetricsDescription"), + new PropertyModel(repositoryModel, "skipSummaryMetrics"))); + + List 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("choice", + new PropertyModel(repositoryModel, "maxActivityCommits"), + maxActivityCommits, + new MaxActivityCommitsRenderer()))); + + List renderers = Arrays.asList(CommitMessageRenderer.values()); + form.add(newChoice("commitMessageRenderer", + getString("gb.commitMessageRenderer"), + getString("gb.commitMessageRendererDescription"), + new DropDownChoice("choice", + new PropertyModel(repositoryModel, "commitMessageRenderer"), + renderers))); + + metricAuthorExclusions = new Model(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? "" + : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " ")); + + form.add(newTextfield("metricAuthorExclusions", + getString("gb.metricAuthorExclusions"), + getString("gb.metricAuthorExclusions"), + "span6", + metricAuthorExclusions)); + + mailingLists = new Model(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)) { // anonymous everything, disable all controls @@ -488,6 +612,9 @@ public class EditRepositoryPage extends RootSubPage { teamsPalette.setEnabled(allowFineGrainedControls); } + // + // ACCESS POLICY PANEL (GENERAL) + // AjaxFormChoiceComponentUpdatingBehavior callback = new AjaxFormChoiceComponentUpdatingBehavior() { private static final long serialVersionUID = 1L; @@ -516,10 +643,10 @@ public class EditRepositoryPage extends RootSubPage { accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel, callback); form.add(accessPolicyPanel); - List renderers = Arrays.asList(CommitMessageRenderer.values()); - DropDownChoice messageRendererChoice = new DropDownChoice("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 @@ public class EditRepositoryPage extends RootSubPage { } } + private Fragment newCheckbox(String wicketId, String title, String description, IModel 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 Fragment newChoice(String wicketId, String title, String description, IModel model, List 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 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 model) { + Fragment fragment = new Fragment(wicketId, "textfieldOption", this); + fragment.add(new Label("name", title)); + fragment.add(new Label("description", description)); + TextField tf = new TextField("text", model); + if (!StringUtils.isEmpty(css)) { + WicketUtils.setCssClass(tf, css); + } + fragment.add(tf); + return fragment; + } + + private class FederationTypeRenderer implements IChoiceRenderer { 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 38fa7f6a..965c4d51 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 @@

- -
-
- - -
-
-
- -
+
+
+
+ +
- +
+
+ +
+
+
+ +
+
+ + +
+
+ +
+ +
+
+ \ 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 057b96f4..7aa801f4 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 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.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; @@ -49,6 +52,8 @@ public class AccessPolicyPanel extends BasePanel { private RadioGroup policiesGroup; + private IModel allowForks; + public AccessPolicyPanel(String wicketId, RepositoryModel repository) { this(wicketId, repository, null); } @@ -142,13 +147,28 @@ public class AccessPolicyPanel extends BasePanel { } 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 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 3c651620..6fb6e45c 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 @@   +   -- 2.39.5